ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/test/loops/CASLoops.java
Revision: 1.1
Committed: Fri Jun 10 15:45:19 2005 UTC (18 years, 11 months ago) by dl
Branch: MAIN
Log Message:
Add CAS timing test; use cheaper RNGs in others

File Contents

# User Rev Content
1 dl 1.1 /*
2     * Written by Doug Lea and released to the public domain, as explained at
3     * http://creativecommons.org/licenses/publicdomain
4     */
5    
6     /*
7     * Estimates the difference in time for compareAndSet and CAS-like
8     * operations versus unsynchronized, non-volatile pseudo-CAS when
9     * updating random numbers. These estimates thus give the cost
10     * of atomicity/barriers/exclusion over and above the time to
11     * just compare and conditionally store (int) values, so are
12     * not intended to measure the "raw" cost of a CAS.
13     *
14     * Outputs, for runs using 1 ... #cpus threads are, in nanoseconds:
15     * "Atomic CAS" AtomicInteger.compareAndSet
16     * "Volatile" pseudo-CAS using volatile store if comparison succeeds
17     * "Mutex" emulated compare and set done under AQS-based mutex lock
18     * "Synchronized" emulated compare and set done under a synchronized block.
19     *
20     * The last two are done only if this program is called with (any) argument
21     */
22    
23    
24     import java.util.concurrent.atomic.AtomicInteger;
25     import java.util.concurrent.atomic.AtomicLong;
26     import java.util.concurrent.*;
27     import java.util.concurrent.locks.*;
28    
29     public class CASLoops {
30    
31     static final int TRIALS = 2;
32     static final long BASE_SECS_PER_RUN = 4;
33     static final int NCPUS = Runtime.getRuntime().availableProcessors();
34    
35     static boolean includeLocks = false;
36    
37     public static void main(String[] args) throws Exception {
38     if (args.length > 0)
39     includeLocks = true;
40    
41     System.out.println("Warmup...");
42     for (int j = 0; j < 2; ++j) {
43     for (int i = 1; i <= NCPUS; ++i) {
44     runCalibration(i, 1000);
45     oneRun(i, loopIters[i] / 8, false);
46     }
47     }
48    
49     for (int i = 1; i <= NCPUS; ++i)
50     loopIters[i] = 0;
51    
52     for (int j = 0; j < TRIALS; ++j) {
53     System.out.println("Trial " + j);
54     for (int i = 1; i <= NCPUS; ++i) {
55     runCalibration(i, BASE_SECS_PER_RUN * 1000L);
56     oneRun(i, loopIters[i], true);
57     }
58     }
59     }
60    
61     static final AtomicLong totalIters = new AtomicLong(0);
62     static final AtomicLong successes = new AtomicLong(0);
63     static final AtomicInteger sum = new AtomicInteger(0);
64    
65     static final LoopHelpers.MarsagliaRandom rng = new LoopHelpers.MarsagliaRandom();
66    
67     static final long[] loopIters = new long[NCPUS+1];
68    
69     static final class NonAtomicInteger {
70     volatile int readBarrier;
71     int value;
72    
73     NonAtomicInteger() {}
74     int get() {
75     int junk = readBarrier;
76     return value;
77     }
78     boolean compareAndSet(int cmp, int val) {
79     if (value == cmp) {
80     value = val;
81     return true;
82     }
83     return false;
84     }
85     void set(int val) { value = val; }
86     }
87    
88     static final class VolatileInteger {
89     volatile int value;
90    
91     VolatileInteger() {}
92     int get() {
93     return value;
94     }
95     boolean compareAndSet(int cmp, int val) {
96     if (value == cmp) {
97     value = val;
98     return true;
99     }
100     return false;
101     }
102     void set(int val) { value = val; }
103     }
104    
105     static final class SynchedInteger {
106     int value;
107    
108     SynchedInteger() {}
109     int get() {
110     return value;
111     }
112     synchronized boolean compareAndSet(int cmp, int val) {
113     if (value == cmp) {
114     value = val;
115     return true;
116     }
117     return false;
118     }
119     synchronized void set(int val) { value = val; }
120     }
121    
122    
123     static final class LockedInteger extends AbstractQueuedSynchronizer {
124     int value;
125     LockedInteger() {}
126    
127     public boolean tryAcquire(int acquires) {
128     return compareAndSetState(0, 1);
129     }
130     public boolean tryRelease(int releases) {
131     setState(0);
132     return true;
133     }
134     void lock() { acquire(1); }
135     void unlock() { release(1); }
136    
137     int get() {
138     return value;
139     }
140     boolean compareAndSet(int cmp, int val) {
141     lock();
142     try {
143     if (value == cmp) {
144     value = val;
145     return true;
146     }
147     return false;
148     } finally {
149     unlock();
150     }
151     }
152     void set(int val) {
153     lock();
154     try {
155     value = val;
156     } finally {
157     unlock();
158     }
159     }
160     }
161    
162     // All these versions are copy-paste-hacked to avoid
163     // contamination with virtual call resolution etc.
164    
165     // Use fixed-length unrollable inner loops to reduce safepoint checks
166     static final int innerPerOuter = 16;
167    
168     static final class NonAtomicLoop implements Runnable {
169     final long iters;
170     final NonAtomicInteger obj;
171     final CyclicBarrier barrier;
172     NonAtomicLoop(long iters, NonAtomicInteger obj, CyclicBarrier b) {
173     this.iters = iters;
174     this.obj = obj;
175     this.barrier = b;
176     obj.set(rng.next());
177     }
178    
179     public void run() {
180     try {
181     barrier.await();
182     long i = iters;
183     int y = 0;
184     int succ = 0;
185     while (i > 0) {
186     for (int k = 0; k < innerPerOuter; ++k) {
187     int x = obj.get();
188     int z = y + LoopHelpers.compute6(x);
189     if (obj.compareAndSet(x, z))
190     ++succ;
191     y = LoopHelpers.compute7(z);
192     }
193     i -= innerPerOuter;
194     }
195     sum.getAndAdd(obj.get());
196     successes.getAndAdd(succ);
197     barrier.await();
198     }
199     catch (Exception ie) {
200     return;
201     }
202     }
203     }
204    
205     static final class AtomicLoop implements Runnable {
206     final long iters;
207     final AtomicInteger obj;
208     final CyclicBarrier barrier;
209     AtomicLoop(long iters, AtomicInteger obj, CyclicBarrier b) {
210     this.iters = iters;
211     this.obj = obj;
212     this.barrier = b;
213     obj.set(rng.next());
214     }
215    
216     public void run() {
217     try {
218     barrier.await();
219     long i = iters;
220     int y = 0;
221     int succ = 0;
222     while (i > 0) {
223     for (int k = 0; k < innerPerOuter; ++k) {
224     int x = obj.get();
225     int z = y + LoopHelpers.compute6(x);
226     if (obj.compareAndSet(x, z))
227     ++succ;
228     y = LoopHelpers.compute7(z);
229     }
230     i -= innerPerOuter;
231     }
232     sum.getAndAdd(obj.get());
233     successes.getAndAdd(succ);
234     barrier.await();
235     }
236     catch (Exception ie) {
237     return;
238     }
239     }
240     }
241    
242     static final class VolatileLoop implements Runnable {
243     final long iters;
244     final VolatileInteger obj;
245     final CyclicBarrier barrier;
246     VolatileLoop(long iters, VolatileInteger obj, CyclicBarrier b) {
247     this.iters = iters;
248     this.obj = obj;
249     this.barrier = b;
250     obj.set(rng.next());
251     }
252    
253     public void run() {
254     try {
255     barrier.await();
256     long i = iters;
257     int y = 0;
258     int succ = 0;
259     while (i > 0) {
260     for (int k = 0; k < innerPerOuter; ++k) {
261     int x = obj.get();
262     int z = y + LoopHelpers.compute6(x);
263     if (obj.compareAndSet(x, z))
264     ++succ;
265     y = LoopHelpers.compute7(z);
266     }
267     i -= innerPerOuter;
268     }
269     sum.getAndAdd(obj.get());
270     successes.getAndAdd(succ);
271     barrier.await();
272     }
273     catch (Exception ie) {
274     return;
275     }
276     }
277     }
278    
279     static final class SynchedLoop implements Runnable {
280     final long iters;
281     final SynchedInteger obj;
282     final CyclicBarrier barrier;
283     SynchedLoop(long iters, SynchedInteger obj, CyclicBarrier b) {
284     this.iters = iters;
285     this.obj = obj;
286     this.barrier = b;
287     obj.set(rng.next());
288     }
289    
290     public void run() {
291     try {
292     barrier.await();
293     long i = iters;
294     int y = 0;
295     int succ = 0;
296     while (i > 0) {
297     for (int k = 0; k < innerPerOuter; ++k) {
298     int x = obj.get();
299     int z = y + LoopHelpers.compute6(x);
300     if (obj.compareAndSet(x, z))
301     ++succ;
302     y = LoopHelpers.compute7(z);
303     }
304     i -= innerPerOuter;
305     }
306     sum.getAndAdd(obj.get());
307     successes.getAndAdd(succ);
308     barrier.await();
309     }
310     catch (Exception ie) {
311     return;
312     }
313     }
314     }
315    
316     static final class LockedLoop implements Runnable {
317     final long iters;
318     final LockedInteger obj;
319     final CyclicBarrier barrier;
320     LockedLoop(long iters, LockedInteger obj, CyclicBarrier b) {
321     this.iters = iters;
322     this.obj = obj;
323     this.barrier = b;
324     obj.set(rng.next());
325     }
326    
327     public void run() {
328     try {
329     barrier.await();
330     long i = iters;
331     int y = 0;
332     int succ = 0;
333     while (i > 0) {
334     for (int k = 0; k < innerPerOuter; ++k) {
335     int x = obj.get();
336     int z = y + LoopHelpers.compute6(x);
337     if (obj.compareAndSet(x, z))
338     ++succ;
339     y = LoopHelpers.compute7(z);
340     }
341     i -= innerPerOuter;
342     }
343     sum.getAndAdd(obj.get());
344     successes.getAndAdd(succ);
345     barrier.await();
346     }
347     catch (Exception ie) {
348     return;
349     }
350     }
351     }
352    
353     static final int loopsPerTimeCheck = 2048;
354    
355     static final class NACalibrationLoop implements Runnable {
356     final long endTime;
357     final NonAtomicInteger obj;
358     final CyclicBarrier barrier;
359     NACalibrationLoop(long endTime, NonAtomicInteger obj, CyclicBarrier b) {
360     this.endTime = endTime;
361     this.obj = obj;
362     this.barrier = b;
363     obj.set(rng.next());
364     }
365    
366     public void run() {
367     try {
368     barrier.await();
369     long iters = 0;
370     int y = 0;
371     int succ = 0;
372     do {
373     int i = loopsPerTimeCheck;
374     while (i > 0) {
375     for (int k = 0; k < innerPerOuter; ++k) {
376     int x = obj.get();
377     int z = y + LoopHelpers.compute6(x);
378     if (obj.compareAndSet(x, z))
379     ++succ;
380     y = LoopHelpers.compute7(z);
381     }
382     i -= innerPerOuter;
383     }
384     iters += loopsPerTimeCheck;
385     } while (System.currentTimeMillis() < endTime);
386     totalIters.getAndAdd(iters);
387     sum.getAndAdd(obj.get());
388     successes.getAndAdd(succ);
389     barrier.await();
390     }
391     catch (Exception ie) {
392     return;
393     }
394     }
395     }
396    
397     static void runCalibration(int n, long nms) throws Exception {
398     long now = System.currentTimeMillis();
399     long endTime = now + nms;
400     CyclicBarrier b = new CyclicBarrier(n+1);
401     totalIters.set(0);
402     NonAtomicInteger a = new NonAtomicInteger();
403     for (int j = 0; j < n; ++j)
404     new Thread(new NACalibrationLoop(endTime, a, b)).start();
405     b.await();
406     b.await();
407     long ipt = totalIters.get() / n;
408     if (ipt > loopIters[n])
409     loopIters[n] = ipt;
410     if (sum.get() == 0) System.out.print(" ");
411     }
412    
413     static long runNonAtomic(int n, long iters) throws Exception {
414     LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
415     CyclicBarrier b = new CyclicBarrier(n+1, timer);
416     NonAtomicInteger a = new NonAtomicInteger();
417     for (int j = 0; j < n; ++j)
418     new Thread(new NonAtomicLoop(iters, a, b)).start();
419     b.await();
420     b.await();
421     if (sum.get() == 0) System.out.print(" ");
422     return timer.getTime();
423     }
424    
425     static long runAtomic(int n, long iters) throws Exception {
426     LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
427     CyclicBarrier b = new CyclicBarrier(n+1, timer);
428     AtomicInteger a = new AtomicInteger();
429     for (int j = 0; j < n; ++j)
430     new Thread(new AtomicLoop(iters, a, b)).start();
431     b.await();
432     b.await();
433     if (sum.get() == 0) System.out.print(" ");
434     return timer.getTime();
435     }
436    
437     static long runVolatile(int n, long iters) throws Exception {
438     LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
439     CyclicBarrier b = new CyclicBarrier(n+1, timer);
440     VolatileInteger a = new VolatileInteger();
441     for (int j = 0; j < n; ++j)
442     new Thread(new VolatileLoop(iters, a, b)).start();
443     b.await();
444     b.await();
445     if (sum.get() == 0) System.out.print(" ");
446     return timer.getTime();
447     }
448    
449    
450     static long runSynched(int n, long iters) throws Exception {
451     LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
452     CyclicBarrier b = new CyclicBarrier(n+1, timer);
453     SynchedInteger a = new SynchedInteger();
454     for (int j = 0; j < n; ++j)
455     new Thread(new SynchedLoop(iters, a, b)).start();
456     b.await();
457     b.await();
458     if (sum.get() == 0) System.out.print(" ");
459     return timer.getTime();
460     }
461    
462     static long runLocked(int n, long iters) throws Exception {
463     LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer();
464     CyclicBarrier b = new CyclicBarrier(n+1, timer);
465     LockedInteger a = new LockedInteger();
466     for (int j = 0; j < n; ++j)
467     new Thread(new LockedLoop(iters, a, b)).start();
468     b.await();
469     b.await();
470     if (sum.get() == 0) System.out.print(" ");
471     return timer.getTime();
472     }
473    
474     static void report(String tag, long runtime, long basetime, long iters) {
475     System.out.print(tag);
476     System.out.print(LoopHelpers.rightJustify((runtime - basetime) / iters) + " ns");
477     double secs = (double)(runtime) / 1000000000.0;
478     System.out.println("\t " + secs + "s run time");
479     }
480    
481    
482     static void oneRun(int i, long iters, boolean print) throws Exception {
483     System.out.println("threads : " + i +
484     " base iters per thread per run : " +
485     LoopHelpers.rightJustify(loopIters[i]));
486     long ntime = runNonAtomic(i, iters);
487     if (print)
488     report("Base : ", ntime, ntime, iters);
489     Thread.sleep(100L);
490     long atime = runAtomic(i, iters);
491     if (print)
492     report("Atomic CAS : ", atime, ntime, iters);
493     Thread.sleep(100L);
494     long vtime = runVolatile(i, iters);
495     if (print)
496     report("Volatile : ", vtime, ntime, iters);
497    
498     Thread.sleep(100L);
499     if (!includeLocks) return;
500     long mtime = runLocked(i, iters);
501     if (print)
502     report("Mutex : ", mtime, ntime, iters);
503     Thread.sleep(100L);
504     long stime = runSynched(i, iters);
505     if (print)
506     report("Synchronized: ", stime, ntime, iters);
507     Thread.sleep(100L);
508     }
509    
510    
511     }