/* * Written by Bill Scherer and Doug Lea with assistance from members * of JCP JSR-166 Expert Group and released to the public domain, as * explained at http://creativecommons.org/publicdomain/zero/1.0/ */ import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.util.concurrent.locks.*; public class TimeoutExchangerLoops { static final int NCPUS = Runtime.getRuntime().availableProcessors(); static final int DEFAULT_THREADS = NCPUS + 2; static final long DEFAULT_PATIENCE_NANOS = 100000; static final long DEFAULT_TRIAL_MILLIS = 10000; public static void main(String[] args) throws Exception { int maxThreads = DEFAULT_THREADS; long trialMillis = DEFAULT_TRIAL_MILLIS; long patienceNanos = DEFAULT_PATIENCE_NANOS; int nReps = 3; // Parse and check args int argc = 0; while (argc < args.length) { String option = args[argc++]; if (option.equals("-t")) trialMillis = Integer.parseInt(args[argc]); else if (option.equals("-p")) patienceNanos = Long.parseLong(args[argc]); else if (option.equals("-r")) nReps = Integer.parseInt(args[argc]); else maxThreads = Integer.parseInt(option); argc++; } // Display runtime parameters System.out.print("TimeoutExchangerTest"); System.out.print(" -t " + trialMillis); System.out.print(" -p " + patienceNanos); System.out.print(" -r " + nReps); System.out.print(" max threads " + maxThreads); System.out.println(); System.out.println("Warmups.."); long warmupTime = 1000; long sleepTime = 500; if (false) { for (int k = 0; k < 10; ++k) { for (int j = 0; j < 10; ++j) { oneRun(2, (j + 1) * 1000, patienceNanos); Thread.sleep(sleepTime); } } } oneRun(3, warmupTime, patienceNanos); Thread.sleep(sleepTime); for (int i = maxThreads; i >= 2; i -= 1) { oneRun(i, warmupTime, patienceNanos); Thread.sleep(sleepTime); } for (int j = 0; j < nReps; ++j) { System.out.println("Replication " + j); for (int i = 2; i <= maxThreads; i += 2) { oneRun(i, trialMillis, patienceNanos); Thread.sleep(sleepTime); } } } static void oneRun(int nThreads, long trialMillis, long patienceNanos) throws Exception { System.out.printf("%4d threads", nThreads); System.out.printf("%9dms", trialMillis); final CountDownLatch start = new CountDownLatch(1); Exchanger x = new Exchanger(); Runner[] runners = new Runner[nThreads]; Thread[] threads = new Thread[nThreads]; for (int i = 0; i < nThreads; ++i) { runners[i] = new Runner(x, patienceNanos, start); threads[i] = new Thread(runners[i]); threads[i].start(); } long startTime = System.nanoTime(); start.countDown(); Thread.sleep(trialMillis); for (int i = 0; i < nThreads; ++i) threads[i].interrupt(); long elapsed = System.nanoTime() - startTime; for (int i = 0; i < nThreads; ++i) threads[i].join(); int iters = 0; long fails = 0; for (int i = 0; i < nThreads; ++i) { iters += runners[i].iters; fails += runners[i].failures; } if (iters <= 0) iters = 1; long rate = iters * 1000L * 1000L * 1000L / elapsed; long npt = elapsed / iters; double failRate = (fails * 100.0) / (double) iters; System.out.printf("%9d it/s ", rate); System.out.printf("%9d ns/it", npt); System.out.printf("%9.5f%% fails ", failRate); System.out.print(fails); System.out.println(); // x.printStats(); } static final class Runner implements Runnable { final Exchanger exchanger; final CountDownLatch start; final long patience; volatile int iters; volatile int failures; Runner(Exchanger x, long patience, CountDownLatch start) { this.exchanger = x; this.patience = patience; this.start = start; } public void run() { int i = 0; try { Exchanger x = exchanger; Object m = new Integer(17); long p = patience; start.await(); for (;;) { try { Object e = x.exchange(m, p, TimeUnit.NANOSECONDS); if (e == null || e == m) throw new Error(); m = e; ++i; } catch (TimeoutException to) { if (Thread.interrupted()) { iters = i; return; } ++i; ++failures; } } } catch (InterruptedException ie) { iters = i; } } } }