diff --git a/.gitignore b/.gitignore index 91e148c1..15a1890f 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,8 @@ annotations/Test1.txt annotations/Test2.txt io/*.out io/*.txt +io/*.dat +io/*.tmp io/test.zip +io/test.gz +io/X.file diff --git a/build.xml b/build.xml index ebb9e336..592b151b 100644 --- a/build.xml +++ b/build.xml @@ -11,6 +11,9 @@ Ant available from: http://ant.apache.org/ To see options, type: ant -p + + NOTE: Temporarily excluded + annotations/build.xml @@ -38,7 +41,6 @@ io/build.xml xml/build.xml enumerated/build.xml - annotations/build.xml concurrency/build.xml gui/build.xml swt/build.xml diff --git a/concurrency/SynchronizationComparisons-original-fixed.java b/concurrency/SynchronizationComparisons-original-fixed.java new file mode 100644 index 00000000..1969e0a2 --- /dev/null +++ b/concurrency/SynchronizationComparisons-original-fixed.java @@ -0,0 +1,258 @@ +//: concurrency/SynchronizationComparisons.java +// Comparing the performance of explicit Locks +// and Atomics versus the synchronized keyword. +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.*; +import java.util.*; +import static net.mindview.util.Print.*; + +abstract class Accumulator { + public static long cycles = 50000L; + // Number of Modifiers and Readers during each test: + private static final int N = 4; + public static ExecutorService exec = + Executors.newFixedThreadPool(N*2); + private static CyclicBarrier barrier = + new CyclicBarrier(N*2 + 1); + protected volatile int index = 0; + protected volatile long value = 0; + protected long duration = 0; + protected String id = "error"; + protected final static int SIZE = 100000; + protected static int[] preLoaded = new int[SIZE]; + static { + // Load the array of random numbers: + Random rand = new Random(47); + for(int i = 0; i < SIZE; i++) + preLoaded[i] = rand.nextInt(); + } + public abstract void accumulate(); + public abstract long read(); + private class Modifier implements Runnable { + public void run() { + for(long i = 0; i < cycles; i++) + accumulate(); + try { + barrier.await(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + } + private class Reader implements Runnable { + private volatile long value; + public void run() { + for(long i = 0; i < cycles; i++) + value = read(); + try { + barrier.await(); + } catch(Exception e) { + throw new RuntimeException(e); + } + } + } + public void timedTest() { + long start = System.nanoTime(); + for(int i = 0; i < N; i++) { + exec.execute(new Modifier()); + exec.execute(new Reader()); + } + try { + barrier.await(); + } catch(Exception e) { + throw new RuntimeException(e); + } + duration = System.nanoTime() - start; + printf("%-13s: %13d\n", id, duration); + } + public static void + report(Accumulator acc1, Accumulator acc2) { + printf("%-22s: %.2f\n", acc1.id + "/" + acc2.id, + (double)acc1.duration/(double)acc2.duration); + } +} + +class BaseLine extends Accumulator { + { id = "BaseLine"; } + public void accumulate() { + if(index >= SIZE - 1) index = 0; + value += preLoaded[index++]; + } + public long read() { return value; } +} + +class SynchronizedTest extends Accumulator { + { id = "synchronized"; } + public synchronized void accumulate() { + if(index >= SIZE - 1) index = 0; + value += preLoaded[index++]; + } + public synchronized long read() { + return value; + } +} + +class LockTest extends Accumulator { + { id = "Lock"; } + private Lock lock = new ReentrantLock(); + public void accumulate() { + lock.lock(); + try { + if(index >= SIZE - 1) index = 0; + value += preLoaded[index++]; + } finally { + lock.unlock(); + } + } + public long read() { + lock.lock(); + try { + return value; + } finally { + lock.unlock(); + } + } +} + +class AtomicTest extends Accumulator { + { id = "Atomic"; } + private AtomicInteger index = new AtomicInteger(0); + private AtomicLong value = new AtomicLong(0); + public void accumulate() { + // Oops! Relying on more than one Atomic at + // a time doesn't work. But it still gives us + // a performance indicator: + int i = index.getAndIncrement(); + if(++i >= SIZE - 1) { + i = 0; + index.set(i); + } + value.getAndAdd(preLoaded[i]); + } + public long read() { return value.get(); } +} + +public class SynchronizationComparisons { + static BaseLine baseLine = new BaseLine(); + static SynchronizedTest synch = new SynchronizedTest(); + static LockTest lock = new LockTest(); + static AtomicTest atomic = new AtomicTest(); + static void test() { + print("============================"); + printf("%-12s : %13d\n", "Cycles", Accumulator.cycles); + baseLine.timedTest(); + synch.timedTest(); + lock.timedTest(); + atomic.timedTest(); + Accumulator.report(synch, baseLine); + Accumulator.report(lock, baseLine); + Accumulator.report(atomic, baseLine); + Accumulator.report(synch, lock); + Accumulator.report(synch, atomic); + Accumulator.report(lock, atomic); + } + public static void main(String[] args) { + int iterations = 5; // Default + if(args.length > 0) // Optionally change iterations + iterations = new Integer(args[0]); + // The first time fills the thread pool: + print("Warmup"); + baseLine.timedTest(); + // Now the initial test doesn't include the cost + // of starting the threads for the first time. + // Produce multiple data points: + for(int i = 0; i < iterations; i++) { + test(); + Accumulator.cycles *= 2; + } + Accumulator.exec.shutdown(); + } +} /* Output: (Sample) +Warmup +BaseLine : 34237033 +============================ +Cycles : 50000 +BaseLine : 20966632 +synchronized : 24326555 +Lock : 53669950 +Atomic : 30552487 +synchronized/BaseLine : 1.16 +Lock/BaseLine : 2.56 +Atomic/BaseLine : 1.46 +synchronized/Lock : 0.45 +synchronized/Atomic : 0.79 +Lock/Atomic : 1.76 +============================ +Cycles : 100000 +BaseLine : 41512818 +synchronized : 43843003 +Lock : 87430386 +Atomic : 51892350 +synchronized/BaseLine : 1.06 +Lock/BaseLine : 2.11 +Atomic/BaseLine : 1.25 +synchronized/Lock : 0.50 +synchronized/Atomic : 0.84 +Lock/Atomic : 1.68 +============================ +Cycles : 200000 +BaseLine : 80176670 +synchronized : 5455046661 +Lock : 177686829 +Atomic : 101789194 +synchronized/BaseLine : 68.04 +Lock/BaseLine : 2.22 +Atomic/BaseLine : 1.27 +synchronized/Lock : 30.70 +synchronized/Atomic : 53.59 +Lock/Atomic : 1.75 +============================ +Cycles : 400000 +BaseLine : 160383513 +synchronized : 780052493 +Lock : 362187652 +Atomic : 202030984 +synchronized/BaseLine : 4.86 +Lock/BaseLine : 2.26 +Atomic/BaseLine : 1.26 +synchronized/Lock : 2.15 +synchronized/Atomic : 3.86 +Lock/Atomic : 1.79 +============================ +Cycles : 800000 +BaseLine : 322064955 +synchronized : 336155014 +Lock : 704615531 +Atomic : 393231542 +synchronized/BaseLine : 1.04 +Lock/BaseLine : 2.19 +Atomic/BaseLine : 1.22 +synchronized/Lock : 0.47 +synchronized/Atomic : 0.85 +Lock/Atomic : 1.79 +============================ +Cycles : 1600000 +BaseLine : 650004120 +synchronized : 52235762925 +Lock : 1419602771 +Atomic : 796950171 +synchronized/BaseLine : 80.36 +Lock/BaseLine : 2.18 +Atomic/BaseLine : 1.23 +synchronized/Lock : 36.80 +synchronized/Atomic : 65.54 +Lock/Atomic : 1.78 +============================ +Cycles : 3200000 +BaseLine : 1285664519 +synchronized : 96336767661 +Lock : 2846988654 +Atomic : 1590545726 +synchronized/BaseLine : 74.93 +Lock/BaseLine : 2.21 +Atomic/BaseLine : 1.24 +synchronized/Lock : 33.84 +synchronized/Atomic : 60.57 +Lock/Atomic : 1.79 +*///:~ diff --git a/io/build.xml b/io/build.xml index 70e8c9fe..e5319528 100644 --- a/io/build.xml +++ b/io/build.xml @@ -136,7 +136,6 @@ failonerror="true" fork="true"> - @@ -148,7 +147,6 @@ failonerror="true" fork="true"> - @@ -160,7 +158,6 @@ failonerror="true" fork="true"> -