/* * Written by 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/ */ /* * Simple benchmark comparing various locking techniques. */ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; public final class LockLoops { static final ExecutorService pool = Executors.newCachedThreadPool(); static final LoopHelpers.SimpleRandom rng = new LoopHelpers.SimpleRandom(); static boolean print = false; static boolean doBuiltin = true; static boolean doReadWrite = true; static boolean doSemaphore = true; static boolean doStampedLock = true; static boolean doFair = true; public static void main(String[] args) throws Exception { int maxThreads = 100; int iters = 1000000; int replications = 1; if (args.length > 0) maxThreads = Integer.parseInt(args[0]); if (args.length > 1) iters = Integer.parseInt(args[1]); if (args.length > 2) replications = Integer.parseInt(args[2]); rng.setSeed(3122688L); print = false; System.out.println("Warmup..."); oneTest(3, 10000); Thread.sleep(1000); oneTest(2, 10000); Thread.sleep(100); oneTest(1, 100000); Thread.sleep(100); oneTest(1, 100000); Thread.sleep(1000); print = true; for (int i = 1; i <= maxThreads; ++i) { for (int j = 0; j < replications; ++j) { System.out.println("Threads:" + i); oneTest(i, iters / i); Thread.sleep(100); } } pool.shutdown(); } static void oneTest(int nthreads, int iters) throws Exception { int v = rng.next(); if (print) System.out.print("No shared vars "); new NoLockLoop().test(v, nthreads, iters * 10); Thread.sleep(10); if (print) System.out.print("No Lock + volatile "); new NoLockVolatileLoop().test(v, nthreads, iters); Thread.sleep(10); if (doBuiltin) { if (print) System.out.print("builtin lock "); new BuiltinLockLoop().test(v, nthreads, iters); Thread.sleep(10); } if (print) System.out.print("ReentrantLock "); new ReentrantLockLoop().test(v, nthreads, iters); Thread.sleep(10); if (doReadWrite) { if (print) System.out.print("ReentrantWriteLock "); new ReentrantWriteLockLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("ReentrantReadLock "); new ReentrantReadLockLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("ReentrantReadWriteLock"); new ReentrantReadWriteLockLoop().test(v, nthreads, iters); Thread.sleep(10); } if (doSemaphore) { if (print) System.out.print("Semaphore "); new SemaphoreLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("FairSemaphore "); new FairSemaphoreLoop().test(v, nthreads, iters); Thread.sleep(10); } if (doFair) { if (print) System.out.print("FairReentrantLock "); new FairReentrantLockLoop().test(v, nthreads, iters); Thread.sleep(10); if (doReadWrite) { if (print) System.out.print("FairRWriteLock "); new FairReentrantWriteLockLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("FairRReadWriteLock "); new FairReentrantReadWriteLockLoop().test(v, nthreads, iters); Thread.sleep(10); } } if (doStampedLock) { if (print) System.out.print("StampedLockWrite "); new StampedLockWriteLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("StampedLockRead "); new StampedLockReadLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("StampedLockOptRead"); new StampedLockOptimisticReadLoop().test(v, nthreads, iters); Thread.sleep(10); if (print) System.out.print("StampedLockReadWrite"); new StampedLockReadWriteLoop().test(v, nthreads, iters); Thread.sleep(10); } } abstract static class LockLoop implements Runnable { int v; int iters; volatile int result; final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer(); CyclicBarrier barrier; final void test(int initialValue, int nthreads, int iters) throws Exception { v = initialValue; this.iters = iters; barrier = new CyclicBarrier(nthreads+1, timer); for (int i = 0; i < nthreads; ++i) pool.execute(this); barrier.await(); barrier.await(); long time = timer.getTime(); if (print) { long tpi = time / (iters * nthreads); System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update"); // double secs = (double) time / 1000000000.0; // System.out.print("\t " + secs + "s run time"); System.out.println(); } if (result == 0) // avoid overoptimization System.out.println("useless result: " + result); } abstract int loop(int n); public final void run() { try { barrier.await(); result += loop(iters); barrier.await(); } catch (Exception ie) { return; } } } private static class BuiltinLockLoop extends LockLoop { final int loop(int n) { int sum = 0; while (n-- > 0) { synchronized (this) { v = LoopHelpers.compute1(v); } sum += LoopHelpers.compute2(v); } return sum; } } private static class NoLockLoop extends LockLoop { final int loop(int n) { int sum = 0; int y = v; while (n-- > 0) { y = LoopHelpers.compute1(y); sum += LoopHelpers.compute2(y); } return sum; } } private static class NoLockVolatileLoop extends LockLoop { private volatile int vv; final int loop(int n) { int sum = 0; while (n-- > 0) { int y = LoopHelpers.compute1(vv); vv = y; sum += LoopHelpers.compute2(y); } return sum; } } private static class ReentrantLockLoop extends LockLoop { private final ReentrantLock lock = new ReentrantLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { lock.lock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class FairReentrantLockLoop extends LockLoop { private final ReentrantLock lock = new ReentrantLock(true); final int loop(int n) { int sum = 0; while (n-- > 0) { lock.lock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class ReentrantWriteLockLoop extends LockLoop { private final Lock lock = new ReentrantReadWriteLock().writeLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { lock.lock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class ReentrantReadLockLoop extends LockLoop { private final Lock lock = new ReentrantReadWriteLock().readLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { lock.lock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class ReentrantReadWriteLockLoop extends LockLoop { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { int x; lock.readLock().lock(); try { x = LoopHelpers.compute1(v); } finally { lock.readLock().unlock(); } lock.writeLock().lock(); try { v = x; } finally { lock.writeLock().unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class FairReentrantWriteLockLoop extends LockLoop { final Lock lock = new ReentrantReadWriteLock(true).writeLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { lock.lock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class SemaphoreLoop extends LockLoop { private final Semaphore sem = new Semaphore(1, false); final int loop(int n) { int sum = 0; try { while (n-- > 0) { sem.acquire(); try { v = LoopHelpers.compute1(v); } finally { sem.release(); } sum += LoopHelpers.compute2(v); } } catch (InterruptedException ie) { return sum; } return sum; } } private static class FairSemaphoreLoop extends LockLoop { private final Semaphore sem = new Semaphore(1, true); final int loop(int n) { int sum = 0; try { while (n-- > 0) { sem.acquire(); try { v = LoopHelpers.compute1(v); } finally { sem.release(); } sum += LoopHelpers.compute2(v); } } catch (InterruptedException ie) { return sum; } return sum; } } private static class FairReentrantReadWriteLockLoop extends LockLoop { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); final int loop(int n) { int sum = 0; while (n-- > 0) { int x; lock.readLock().lock(); try { x = LoopHelpers.compute1(v); } finally { lock.readLock().unlock(); } lock.writeLock().lock(); try { v = x; } finally { lock.writeLock().unlock(); } sum += LoopHelpers.compute2(v); } return sum; } } private static class StampedLockWriteLoop extends LockLoop { private final StampedLock lock = new StampedLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { long stamp = lock.writeLock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlockWrite(stamp); } sum += LoopHelpers.compute2(v); } return sum; } } private static class StampedLockReadLoop extends LockLoop { private final StampedLock lock = new StampedLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { long stamp = lock.readLock(); try { v = LoopHelpers.compute1(v); } finally { lock.unlockRead(stamp); } sum += LoopHelpers.compute2(v); } return sum; } } private static class StampedLockOptimisticReadLoop extends LockLoop { private final StampedLock lock = new StampedLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { long stamp; do { stamp = lock.tryOptimisticRead(); v = LoopHelpers.compute1(v); } while (!lock.validate(stamp)); sum += LoopHelpers.compute2(v); } return sum; } } private static class StampedLockReadWriteLoop extends LockLoop { private final StampedLock lock = new StampedLock(); final int loop(int n) { int sum = 0; while (n-- > 0) { int x; long stamp = lock.readLock(); try { x = LoopHelpers.compute1(v); } finally { lock.unlockRead(stamp); } stamp = lock.writeLock(); try { v = x; } finally { lock.unlockWrite(stamp); } sum += LoopHelpers.compute2(v); } return sum; } } }