comparison src/EDU/oswego/cs/dl/util/concurrent/misc/SynchronizationTimer.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /*
2 File: SynchronizationTimer.java
3
4 Originally written by Doug Lea and released into the public domain.
5 This may be used for any purposes whatsoever without acknowledgment.
6 Thanks for the assistance and support of Sun Microsystems Labs,
7 and everyone contributing, testing, and using this code.
8
9 History:
10 Date Who What
11 7Jul1998 dl Create public version
12 16Jul1998 dl fix intialization error for compute loops
13 combined into one frame
14 misc layout and defaults changes
15 increase printed precision
16 overlap get/set in Executor tests
17 Swap defaults for swing import
18 Active thread counts reflect executors
19 30Aug1998 dl Misc revisions to mesh with 1.1.0
20 27jan1999 dl Eliminate GC calls
21 24Nov2001 dl Increase some default values
22 */
23
24 package EDU.oswego.cs.dl.util.concurrent.misc;
25
26 // Swap the following sets of imports if necessary.
27
28 import javax.swing.*;
29 import javax.swing.border.*;
30
31 //import com.sun.java.swing.*;
32 //import com.sun.java.swing.border.*;
33
34 import EDU.oswego.cs.dl.util.concurrent.*;
35 import java.awt.*;
36 import java.awt.event.*;
37 import java.io.*;
38 import java.net.*;
39 import java.lang.reflect.*;
40
41 /**
42 *
43 * This program records times for various fine-grained synchronization
44 * schemes, and provides some ways of measuring them over different
45 * context parameters.
46 *
47 * <p>
48 * Quick start:
49 * <ol>
50 * <li>javac -d <em>base of some CLASSPATH</em> *.java <br>
51 * You'll need Swing (JFC). (This
52 * program currently imports the javax.swing versions.
53 * You can edit imports to instead use other versions.)
54 * <li>java EDU.oswego.cs.dl.util.concurrent.misc.SynchronizationTimer <br>
55 * <li> Click<em> start</em>.
56 * Clicking <em>stop</em> cancels the run. Cancellation can take
57 * a while when there are a lot of threads.
58 * <li>For more explanation about tested classes, see
59 * <a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">Documentation for util.concurrent</a>
60 * </ol>
61 *
62 * <p>
63 * Synchronization schemes are tested around implementations and
64 * subclasses of <code>RNG</code>, which is just a hacked random
65 * number generator class. Objects of this class have just enough
66 * state and require just enough computation to be reasonable minimal
67 * targets. (Additionally, random numbers are needed a lot in these
68 * kinds of time tests, so basing them on objects that produce random
69 * numbers is convenient.) Computation of each random number is
70 * padded a bit with an adjustable compute loop running a random
71 * number of times to avoid getting schedulers locked into
72 * uninteresting patterns.
73 *
74 * <p>
75 * Each iteration of each test ultimately somehow calls
76 * the random number generation
77 * method of an RNG. The time listed is the average time it took to do
78 * one iteration, in microseconds. These are just based on wallclock
79 * time (System.currentTimeMillis()). Thread
80 * construction time is <em>NOT</em> included in these times.
81 * In tests with many threads, construction and other bookkeeping
82 * can take longer than the tests themselves.
83 * <p>
84 * Results are listed in a table, and optionally printed on standard output.
85 * You can redirect standard output to save to a file.
86 * <p>
87 * The total amount of ``real'' computation reported in each cell is
88 * the same. Thus, the unobtainably ideal pattern of results would be
89 * for every cell of the table to be the same (and very small).
90 * <p>
91 * A thread pool (PooledExecutor) is used to manage the threads used in
92 * test runs. The current number of active threads is indicated in
93 * the panel. It should normally be at most three plus the number of threads used in the
94 * indicated test column (there are at most three overhead threads per run), although
95 * it may transiently climb, and is larger in those tests that
96 * generate their own internal threads (for example ThreadedExceutor). If the
97 * indicated size fails to return to zero within about 10 seconds of
98 * either hitting stop
99 * or the end of a run, you may have a
100 * problem with interruption handling on your Java VM.
101 *
102 * <p>
103 * This program cannot
104 * tell you how busy your computer is while running tests.
105 * You can run a utility program (for
106 * example <code>perfmeter</code> or <code>top</code> on unix)
107 * alongside this program
108 * to find out.
109 * <p>
110 * A number of control parameters can be changed at any time.
111 * Most combinations of parameter settings create contexts
112 * that are completely unrepresentative of those seen in practical
113 * applications. However, they can be set to provide rough analogs of
114 * real applications, and the results used as rough guesses about
115 * performance impact. Also, do not be too upset about slow
116 * performance on tests representing situations
117 * that would never occur in practice.
118 * <p>
119 *
120 * You can control parameters by clicking any of the following,
121 * at any time. (You can even change parameters
122 * while tests are running, in which case they will take
123 * effect as soon as possible. Most controls momentarily stall
124 * while test objects and threads are being constructed, to avoid
125 * inconsistencies during test runs.)
126 * <dl>
127 *
128 * <dt> Number of threads
129 *
130 * <dd> Controls concurrency. The indicated number of threads are
131 * started simultaneously and then waited out.
132 *
133 * <dt>Contention.
134 *
135 * <dd>Percent sharing among threads. Zero percent means that each
136 * thread has its own RNG object, so there is no
137 * interference among threads. The zero
138 * percent case thus shows the cost of synchronization mechanics that
139 * happen to never be needed.
140 * 100 percent sharing means that all
141 * threads call methods on the same object, so each thread will have to
142 * wait until the RNG objects are not being used by others.
143 * In between is in between: Only the given percentage of calls are
144 * made to shared RNG objects; others are to unshared.
145 * Contention in classes that use Channels works slightly differently:
146 * The Channels are shared, not the base RNG objects. (Another way
147 * of looking at it is that tests demonstrate effects of multiple
148 * producers and consumers on the same channel.)
149 *
150 * <dt>Classes
151 * <dd>You can choose to only test the indicated classes. You can
152 * probably figure out how to add more classes to run yourself.
153 *
154 * <dt>Calls per thread per test
155 *
156 * <dd>Specifies number of iterations per thread per test. The listed
157 * times are averages over these iterations. The default seems to
158 * provide precise enough values for informal testing purposes.
159 * You should expect to see a fair amount of variation across
160 * repeated runs.
161 * If you get zeroes printed in any cell, this means that the
162 * test ran too fast to measure in milleconds, so you should increase the
163 * iterations value.
164 *
165 * <dt> Computations per call
166 *
167 * <dd>Specifies length of each call by setting an internal looping
168 * parameter inside each RNG object. Shorter calls lead to shorter
169 * times between synchronization measures. Longer calls, along with
170 * high contention can be used to force timeouts to occur.
171 *
172 * <dt> Iterations per barrier.
173 *
174 * <dd> Specifies the number of iterations performed by each thread until
175 * a synchronization barrier is forced with other threads, forcing
176 * it to wait for other threads to reach the same number of iterations. This
177 * controls the amount of interaction (versus contention) among threads.
178 * Setting to a value greater than the number of iterations per test
179 * effectively disables barriers.
180 *
181 * <dt> Threads per barrier
182 *
183 * <dd> Specifies how many threads are forced to synchronize at each
184 * barrier point. Greater numbers cause more threads to wait for each
185 * other at barriers. Setting to 1 means that a thread only has to
186 * wait for itself, which means not to wait at all.
187 *
188 * <dt>Lock mode
189 *
190 * <dd>For classes that support it, this controls whether mutual
191 * exclusion waits are done via standard blocking synchronization, or
192 * a loop repeatedly calling a timed wait.
193 *
194 * <dt>Producer mode
195 *
196 * <dd>For classes that support it, this controls whether producers
197 * perform blocking puts versus loops repeatedly calling offer.
198 *
199 * <dt>Consumer mode
200 *
201 * <dd>For classes that support it, this controls whether consumers
202 * perform blocking takes versus loops repeatedly calling poll.
203 *
204 * <dt> Timeouts
205 *
206 * <dd> Specifies the duration of timeouts used in timeout mode. A
207 * value of zero results in pure spin-loops.
208 *
209 * <dt>Producer/consumer rates.
210 *
211 * <dd>For tests involving producer/consumer pairs, this controls
212 * whether the producer is much faster, about the same speed, or much
213 * slower than the consumer. This is implemented by having the
214 * producer do all, half, or none of the actual calls to update, in
215 * addition to adding elements to channel.
216 *
217 * <dt>Buffer capacity
218 *
219 * <dd>For tests involving finite capacity
220 * buffers, this controls maximum buffer size.
221 *
222 * </dl>
223 *
224 * <p>
225 * To scaffold all this, the RNG class is defined in
226 * layers. Each RNG has internal non-public methods that do the actual
227 * computation, and public methods that call the internal ones. The
228 * particular classes run in tests might change over time, but
229 * currently includes the following general kinds:
230 *
231 * <dl>
232 *
233 *
234 * <dt> Using built-in synchronization
235 * <dd> Versions of RNG classes that use (or don't use)
236 * synchronized methods and/or blocks. Also some tests of
237 * simple SynchronizedVariables. Tests that would not
238 * be thread-safe are not run when there is more than one
239 * thread and non-zero contention.
240 *
241 *
242 * <dt> Using <code>Sync</code> classes as locks
243 * <dd> Classes protecting public methods via Semaphores, mutexes, etc.
244 * In each case, the outer public methods delegate actions to
245 * another RNG object, surrounded by acquire/release/etc. The
246 * class called SDelegated does this using builtin
247 * synchronization rather than Sync locks
248 * so might be a useful comparison.
249 *
250 * <dt> Using Channels
251 * <dd> These classes work a little bit differently than the others.
252 * Each test arranges that half of the threads behave as producers,
253 * and half as consumers. Each test iteration puts/takes an RNG object
254 * through a channel before or after executing its update
255 * method. When the number of threads is one, each producer
256 * simply consumers its own object. Some Channels (notably
257 * SynchronousChannels) cannot be used with only one thread,
258 * in which case the test is skipped.
259 *
260 * <dt> Using Executors
261 * <dd> These classes arrange for each RNG update to occur
262 * as an executable command. Each test iteration passes a
263 * command to an Executor, which eventually executes it.
264 * Execution is overlapped: Each iteration starts a new
265 * command, and then waits for the previous command to complete.
266 *
267 * </dl>
268 *
269 * <p>
270 *
271 * The test code is ugly; it has just evolved over the years. Sorry.
272 **/
273
274 public class SynchronizationTimer {
275
276 /** Start up this application **/
277 public static void main(String[] args) {
278
279 JFrame frame = new JFrame("Times per call in microseconds");
280
281 frame.addWindowListener(new WindowAdapter() {
282 public void windowClosing(WindowEvent e) {System.exit(0);}
283 });
284
285 frame.getContentPane().add(new SynchronizationTimer().mainPanel());
286 frame.pack();
287 frame.setVisible(true);
288 }
289
290 /**
291 * Information about classes to be tested
292 **/
293 static class TestedClass {
294 final String name;
295 final Class cls;
296 final boolean multipleOK;
297 final boolean singleOK;
298 final Class buffCls;
299 Boolean enabled_ = new Boolean(true);
300
301 synchronized void setEnabled(Boolean b) { enabled_ = b; }
302 synchronized Boolean getEnabled() { return enabled_; }
303
304 synchronized void toggleEnabled() {
305 boolean enabled = enabled_.booleanValue();
306 enabled_ = new Boolean(!enabled);
307 }
308
309 synchronized boolean isEnabled(int nthreads, Fraction shared) {
310 boolean enabled = enabled_.booleanValue();
311 if (!enabled) return false;
312 if (!singleOK && nthreads <= 1) return false;
313 if (!multipleOK && nthreads > 1 && shared.compareTo(0) > 0) return false;
314 return true;
315 }
316
317
318 TestedClass(String n, Class c, boolean m, boolean sok) {
319 name = n; cls = c; multipleOK = m; singleOK = sok;
320 buffCls = null;
321 }
322
323 TestedClass(String n, Class c, boolean m, boolean sok, Class bc) {
324 name = n; cls = c; multipleOK = m; singleOK = sok;
325 buffCls = bc;
326 }
327
328 static final TestedClass dummy =
329 new TestedClass("", null, false, false);
330
331 static final TestedClass[] classes = {
332
333 new TestedClass("NoSynchronization", NoSynchRNG.class, false, true),
334 new TestedClass("PublicSynchronization", PublicSynchRNG.class, true, true),
335 new TestedClass("NestedSynchronization", AllSynchRNG.class, true, true),
336
337 new TestedClass("SDelegated", SDelegatedRNG.class, true, true),
338
339 new TestedClass("SynchLongUsingSet", SynchLongRNG.class, true, true),
340 new TestedClass("SynchLongUsingCommit", AClongRNG.class, true, true),
341
342 new TestedClass("Semaphore", SemRNG.class, true, true),
343 new TestedClass("WaiterPrefSemaphore", WpSemRNG.class, true, true),
344 new TestedClass("FIFOSemaphore", FifoRNG.class, true, true),
345 new TestedClass("PrioritySemaphore", PrioritySemRNG.class, true, true),
346 new TestedClass("Mutex", MutexRNG.class, true, true),
347 new TestedClass("ReentrantLock", RlockRNG.class, true, true),
348
349 new TestedClass("WriterPrefRWLock", WpRWlockRNG.class, true, true),
350 new TestedClass("ReaderPrefRWLock", ReaderPrefRWlockRNG.class, true, true),
351 new TestedClass("FIFORWLock", FIFORWlockRNG.class, true, true),
352 new TestedClass("ReentrantRWL", ReentrantRWlockRNG.class, true, true),
353
354
355
356 new TestedClass("LinkedQueue", ChanRNG.class, true, true,
357 LinkedQueue.class),
358
359 new TestedClass("WaitFreeQueue", ChanRNG.class, true, true,
360 WaitFreeQueue.class),
361
362 new TestedClass("BoundedLinkedQueue", ChanRNG.class, true, true,
363 BoundedLinkedQueue.class),
364 new TestedClass("BoundedBuffer", ChanRNG.class, true, true,
365 BoundedBuffer.class),
366 new TestedClass("CondVarBoundedBuffer", ChanRNG.class, true, true,
367 CVBuffer.class),
368 new TestedClass("BoundedPriorityQueue", ChanRNG.class, true, true,
369 BoundedPriorityQueue.class),
370 new TestedClass("Slot", ChanRNG.class, true, true,
371 Slot.class),
372 // new TestedClass("FIFOSlot", ChanRNG.class, true, true, FIFOSlot.class),
373 new TestedClass("SynchronousChannel", ChanRNG.class, true, false,
374 SynchronousChannel.class),
375
376
377 new TestedClass("DirectExecutor", DirectExecutorRNG.class, true, true),
378 new TestedClass("SemaphoreLckExecutor", LockedSemRNG.class, true, true),
379 new TestedClass("QueuedExecutor", QueuedExecutorRNG.class, true, true),
380 new TestedClass("ThreadedExecutor", ThreadedExecutorRNG.class, true, true),
381 new TestedClass("PooledExecutor", PooledExecutorRNG.class, true, true),
382
383 // new TestedClass("Pipe", ChanRNG.class, true, true, PipedChannel.class),
384 };
385 }
386
387
388
389 // test parameters
390
391 static final int[] nthreadsChoices = {
392 1,
393 2,
394 4,
395 8,
396 16,
397 32,
398 64,
399 128,
400 256,
401 512,
402 1024
403 };
404
405 static final int BLOCK_MODE = 0;
406 static final int TIMEOUT_MODE = 1;
407
408 static final int[] syncModes = { BLOCK_MODE, TIMEOUT_MODE, };
409
410 // misc formatting utilities
411
412 static String modeToString(int m) {
413 String sms;
414 if (m == BLOCK_MODE) sms = "block";
415 else if (m == TIMEOUT_MODE) sms = "timeout";
416 else sms = "No such mode";
417 return sms;
418 }
419
420 static String biasToString(int b) {
421 String sms;
422 if (b < 0) sms = "slower producer";
423 else if (b == 0) sms = "balanced prod/cons rate";
424 else if (b > 0) sms = "slower consumer";
425 else sms = "No such bias";
426 return sms;
427 }
428
429
430 static String p2ToString(int n) { // print power of two
431 String suf = "";
432 if (n >= 1024) {
433 n = n / 1024;
434 suf = "K";
435 if (n >= 1024) {
436 n = n / 1024;
437 suf = "M";
438 }
439 }
440 return n + suf;
441 }
442
443 static final int PRECISION = 10; // microseconds
444
445 static String formatTime(long ns, boolean showDecimal) {
446 long intpart = ns / PRECISION;
447 long decpart = ns % PRECISION;
448 if (!showDecimal) {
449 if (decpart >= PRECISION/2)
450 ++intpart;
451 return Long.toString(intpart);
452 }
453 else {
454 String sint = Long.toString(intpart);
455 String sdec = Long.toString(decpart);
456 if (decpart == 0) {
457 int z = PRECISION;
458 while (z > 10) {
459 sdec = "0" + sdec;
460 z /= 10;
461 }
462 }
463 String ts = sint + "." + sdec;
464 return ts;
465 }
466 }
467
468 static class ThreadInfo {
469 final String name;
470 final int number;
471 Boolean enabled;
472 ThreadInfo(int nthr) {
473 number = nthr;
474 name = p2ToString(nthr);
475 enabled = new Boolean(true);
476 }
477
478 synchronized Boolean getEnabled() { return enabled; }
479 synchronized void setEnabled(Boolean v) { enabled = v; }
480 synchronized void toggleEnabled() {
481 enabled = new Boolean(!enabled.booleanValue());
482 }
483 }
484
485 final ThreadInfo[] threadInfo = new ThreadInfo[nthreadsChoices.length];
486
487 boolean threadEnabled(int nthreads) {
488 return threadInfo[nthreads].getEnabled().booleanValue();
489 }
490
491 // This used to be a JTable datamodel, but now just part of this class ...
492
493 final static int headerRows = 1;
494 final static int classColumn = 0;
495 final static int headerColumns = 1;
496 final int tableRows = TestedClass.classes.length + headerRows;
497 final int tableColumns = nthreadsChoices.length + headerColumns;
498
499 final JComponent[][] resultTable_ = new JComponent[tableRows][tableColumns];
500
501 JPanel resultPanel() {
502
503 JPanel[] colPanel = new JPanel[tableColumns];
504 for (int col = 0; col < tableColumns; ++col) {
505 colPanel[col] = new JPanel();
506 colPanel[col].setLayout(new GridLayout(tableRows, 1));
507 if (col != 0)
508 colPanel[col].setBackground(Color.white);
509 }
510
511 Color hdrbg = colPanel[0].getBackground();
512 Border border = new LineBorder(hdrbg);
513
514 Font font = new Font("Dialog", Font.PLAIN, 12);
515 Dimension labDim = new Dimension(40, 16);
516 Dimension cbDim = new Dimension(154, 16);
517
518 JLabel cornerLab = new JLabel(" Classes \\ Threads");
519 cornerLab.setMinimumSize(cbDim);
520 cornerLab.setPreferredSize(cbDim);
521 cornerLab.setFont(font);
522 resultTable_[0][0] = cornerLab;
523 colPanel[0].add(cornerLab);
524
525 for (int col = 1; col < tableColumns; ++col) {
526 final int nthreads = col - headerColumns;
527 JCheckBox tcb = new JCheckBox(threadInfo[nthreads].name, true);
528 tcb.addActionListener(new ActionListener() {
529 public void actionPerformed(ActionEvent evt) {
530 threadInfo[nthreads].toggleEnabled();
531 }});
532
533
534 tcb.setMinimumSize(labDim);
535 tcb.setPreferredSize(labDim);
536 tcb.setFont(font);
537 tcb.setBackground(hdrbg);
538 resultTable_[0][col] = tcb;
539 colPanel[col].add(tcb);
540 }
541
542
543 for (int row = 1; row < tableRows; ++row) {
544 final int cls = row - headerRows;
545
546 JCheckBox cb = new JCheckBox(TestedClass.classes[cls].name, true);
547 cb.addActionListener(new ActionListener() {
548 public void actionPerformed(ActionEvent evt) {
549 TestedClass.classes[cls].toggleEnabled();
550 }});
551
552 resultTable_[row][0] = cb;
553 cb.setMinimumSize(cbDim);
554 cb.setPreferredSize(cbDim);
555 cb.setFont(font);
556 colPanel[0].add(cb);
557
558 for (int col = 1; col < tableColumns; ++col) {
559 int nthreads = col - headerColumns;
560 JLabel lab = new JLabel("");
561 resultTable_[row][col] = lab;
562
563 lab.setMinimumSize(labDim);
564 lab.setPreferredSize(labDim);
565 lab.setBorder(border);
566 lab.setFont(font);
567 lab.setBackground(Color.white);
568 lab.setForeground(Color.black);
569 lab.setHorizontalAlignment(JLabel.RIGHT);
570
571 colPanel[col].add(lab);
572 }
573 }
574
575 JPanel tblPanel = new JPanel();
576 tblPanel.setLayout(new BoxLayout(tblPanel, BoxLayout.X_AXIS));
577 for (int col = 0; col < tableColumns; ++col) {
578 tblPanel.add(colPanel[col]);
579 }
580
581 return tblPanel;
582
583 }
584
585 void setTime(final long ns, int clsIdx, int nthrIdx) {
586 int row = clsIdx+headerRows;
587 int col = nthrIdx+headerColumns;
588 final JLabel cell = (JLabel)(resultTable_[row][col]);
589
590 SwingUtilities.invokeLater(new Runnable() {
591 public void run() {
592 cell.setText(formatTime(ns, true));
593 }
594 });
595 }
596
597
598
599 void clearTable() {
600 for (int i = 1; i < tableRows; ++i) {
601 for (int j = 1; j < tableColumns; ++j) {
602 ((JLabel)(resultTable_[i][j])).setText("");
603 }
604 }
605 }
606
607 void setChecks(final boolean setting) {
608 for (int i = 0; i < TestedClass.classes.length; ++i) {
609 TestedClass.classes[i].setEnabled(new Boolean(setting));
610 ((JCheckBox)resultTable_[i+1][0]).setSelected(setting);
611 }
612 }
613
614
615 public SynchronizationTimer() {
616 for (int i = 0; i < threadInfo.length; ++i)
617 threadInfo[i] = new ThreadInfo(nthreadsChoices[i]);
618
619 }
620
621 final SynchronizedInt nextClassIdx_ = new SynchronizedInt(0);
622 final SynchronizedInt nextThreadIdx_ = new SynchronizedInt(0);
623
624
625 JPanel mainPanel() {
626 new PrintStart(); // classloader bug workaround
627 JPanel paramPanel = new JPanel();
628 paramPanel.setLayout(new GridLayout(5, 3));
629
630 JPanel buttonPanel = new JPanel();
631 buttonPanel.setLayout(new GridLayout(1, 3));
632
633 startstop_.addActionListener(new ActionListener() {
634 public void actionPerformed(ActionEvent evt) {
635 if (running_.get())
636 cancel();
637 else {
638 try {
639 startTestSeries(new TestSeries());
640 }
641 catch (InterruptedException ex) {
642 endTestSeries();
643 }
644 }
645 }});
646
647 paramPanel.add(startstop_);
648
649 JPanel p1 = new JPanel();
650 p1.setLayout(new GridLayout(1, 2));
651
652 JButton continueButton = new JButton("Continue");
653
654 continueButton.addActionListener(new ActionListener() {
655 public void actionPerformed(ActionEvent evt) {
656 if (!running_.get()) {
657 try {
658 startTestSeries(new TestSeries(nextClassIdx_.get(),
659 nextThreadIdx_.get()));
660 }
661 catch (InterruptedException ex) {
662 endTestSeries();
663 }
664 }
665 }});
666
667 p1.add(continueButton);
668
669 JButton clearButton = new JButton("Clear cells");
670
671 clearButton.addActionListener(new ActionListener(){
672 public void actionPerformed(ActionEvent evt) {
673 clearTable();
674 }
675 });
676
677 p1.add(clearButton);
678
679 paramPanel.add(p1);
680
681 JPanel p3 = new JPanel();
682 p3.setLayout(new GridLayout(1, 2));
683
684 JButton setButton = new JButton("All classes");
685
686 setButton.addActionListener(new ActionListener(){
687 public void actionPerformed(ActionEvent evt) {
688 setChecks(true);
689 }
690 });
691
692 p3.add(setButton);
693
694
695 JButton unsetButton = new JButton("No classes");
696
697 unsetButton.addActionListener(new ActionListener(){
698 public void actionPerformed(ActionEvent evt) {
699 setChecks(false);
700 }
701 });
702
703 p3.add(unsetButton);
704 paramPanel.add(p3);
705
706 JPanel p2 = new JPanel();
707 // p2.setLayout(new GridLayout(1, 2));
708 p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
709
710
711 JCheckBox consoleBox = new JCheckBox("Console echo");
712 consoleBox.addItemListener(new ItemListener() {
713 public void itemStateChanged(ItemEvent evt) {
714 echoToSystemOut.complement();
715 }
716 });
717
718
719
720 JLabel poolinfo = new JLabel("Active threads: 0");
721
722 p2.add(poolinfo);
723 p2.add(consoleBox);
724
725 paramPanel.add(p2);
726
727 paramPanel.add(contentionBox());
728 paramPanel.add(itersBox());
729 paramPanel.add(cloopBox());
730 paramPanel.add(barrierBox());
731 paramPanel.add(exchangeBox());
732 paramPanel.add(biasBox());
733 paramPanel.add(capacityBox());
734 paramPanel.add(timeoutBox());
735 paramPanel.add(syncModePanel());
736 paramPanel.add(producerSyncModePanel());
737 paramPanel.add(consumerSyncModePanel());
738
739 startPoolStatus(poolinfo);
740
741 JPanel mainPanel = new JPanel();
742 mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
743
744 JPanel tblPanel = resultPanel();
745
746 mainPanel.add(tblPanel);
747 mainPanel.add(paramPanel);
748 return mainPanel;
749 }
750
751
752
753
754 JComboBox syncModePanel() {
755 JComboBox syncModeComboBox = new JComboBox();
756
757 for (int j = 0; j < syncModes.length; ++j) {
758 String lab = "Locks: " + modeToString(syncModes[j]);
759 syncModeComboBox.addItem(lab);
760 }
761 syncModeComboBox.addItemListener(new ItemListener() {
762 public void itemStateChanged(ItemEvent evt) {
763 JComboBox src = (JComboBox)(evt.getItemSelectable());
764 int idx = src.getSelectedIndex();
765 RNG.syncMode.set(syncModes[idx]);
766 }
767 });
768
769 RNG.syncMode.set(syncModes[0]);
770 syncModeComboBox.setSelectedIndex(0);
771 return syncModeComboBox;
772 }
773
774 JComboBox producerSyncModePanel() {
775 JComboBox producerSyncModeComboBox = new JComboBox();
776
777 for (int j = 0; j < syncModes.length; ++j) {
778 String lab = "Producers: " + modeToString(syncModes[j]);
779 producerSyncModeComboBox.addItem(lab);
780 }
781 producerSyncModeComboBox.addItemListener(new ItemListener() {
782 public void itemStateChanged(ItemEvent evt) {
783 JComboBox src = (JComboBox)(evt.getItemSelectable());
784 int idx = src.getSelectedIndex();
785 RNG.producerMode.set(syncModes[idx]);
786 }
787 });
788
789 RNG.producerMode.set(syncModes[0]);
790 producerSyncModeComboBox.setSelectedIndex(0);
791 return producerSyncModeComboBox;
792 }
793
794 JComboBox consumerSyncModePanel() {
795 JComboBox consumerSyncModeComboBox = new JComboBox();
796
797 for (int j = 0; j < syncModes.length; ++j) {
798 String lab = "Consumers: " + modeToString(syncModes[j]);
799 consumerSyncModeComboBox.addItem(lab);
800 }
801 consumerSyncModeComboBox.addItemListener(new ItemListener() {
802 public void itemStateChanged(ItemEvent evt) {
803 JComboBox src = (JComboBox)(evt.getItemSelectable());
804 int idx = src.getSelectedIndex();
805 RNG.consumerMode.set(syncModes[idx]);
806 }
807 });
808
809 RNG.consumerMode.set(syncModes[0]);
810 consumerSyncModeComboBox.setSelectedIndex(0);
811 return consumerSyncModeComboBox;
812 }
813
814
815
816 JComboBox contentionBox() {
817 final Fraction[] contentionChoices = {
818 new Fraction(0, 1),
819 new Fraction(1, 16),
820 new Fraction(1, 8),
821 new Fraction(1, 4),
822 new Fraction(1, 2),
823 new Fraction(1, 1)
824 };
825
826 JComboBox contentionComboBox = new JComboBox();
827
828 for (int j = 0; j < contentionChoices.length; ++j) {
829 String lab = contentionChoices[j].asDouble() * 100.0 +
830 "% contention/sharing";
831 contentionComboBox.addItem(lab);
832 }
833 contentionComboBox.addItemListener(new ItemListener() {
834 public void itemStateChanged(ItemEvent evt) {
835 JComboBox src = (JComboBox)(evt.getItemSelectable());
836 int idx = src.getSelectedIndex();
837 contention_.set(contentionChoices[idx]);
838 }
839 });
840
841 contention_.set(contentionChoices[3]);
842 contentionComboBox.setSelectedIndex(3);
843 return contentionComboBox;
844 }
845
846 JComboBox itersBox() {
847 final int[] loopsPerTestChoices = {
848 1,
849 16,
850 256,
851 1024,
852 2 * 1024,
853 4 * 1024,
854 8 * 1024,
855 16 * 1024,
856 32 * 1024,
857 64 * 1024,
858 128 * 1024,
859 256 * 1024,
860 512 * 1024,
861 1024 * 1024,
862 };
863
864 JComboBox precComboBox = new JComboBox();
865
866 for (int j = 0; j < loopsPerTestChoices.length; ++j) {
867 String lab = p2ToString(loopsPerTestChoices[j]) +
868 " calls per thread per test";
869 precComboBox.addItem(lab);
870 }
871 precComboBox.addItemListener(new ItemListener() {
872 public void itemStateChanged(ItemEvent evt) {
873 JComboBox src = (JComboBox)(evt.getItemSelectable());
874 int idx = src.getSelectedIndex();
875 loopsPerTest_.set(loopsPerTestChoices[idx]);
876 }
877 });
878
879 loopsPerTest_.set(loopsPerTestChoices[8]);
880 precComboBox.setSelectedIndex(8);
881
882 return precComboBox;
883 }
884
885 JComboBox cloopBox() {
886 final int[] computationsPerCallChoices = {
887 1,
888 2,
889 4,
890 8,
891 16,
892 32,
893 64,
894 128,
895 256,
896 512,
897 1024,
898 2 * 1024,
899 4 * 1024,
900 8 * 1024,
901 16 * 1024,
902 32 * 1024,
903 64 * 1024,
904 };
905
906 JComboBox cloopComboBox = new JComboBox();
907
908 for (int j = 0; j < computationsPerCallChoices.length; ++j) {
909 String lab = p2ToString(computationsPerCallChoices[j]) +
910 " computations per call";
911 cloopComboBox.addItem(lab);
912 }
913 cloopComboBox.addItemListener(new ItemListener() {
914 public void itemStateChanged(ItemEvent evt) {
915 JComboBox src = (JComboBox)(evt.getItemSelectable());
916 int idx = src.getSelectedIndex();
917 RNG.computeLoops.set(computationsPerCallChoices[idx]);
918 }
919 });
920
921 RNG.computeLoops.set(computationsPerCallChoices[3]);
922 cloopComboBox.setSelectedIndex(3);
923 return cloopComboBox;
924 }
925
926 JComboBox barrierBox() {
927 final int[] itersPerBarrierChoices = {
928 1,
929 2,
930 4,
931 8,
932 16,
933 32,
934 64,
935 128,
936 256,
937 512,
938 1024,
939 2 * 1024,
940 4 * 1024,
941 8 * 1024,
942 16 * 1024,
943 32 * 1024,
944 64 * 1024,
945 128 * 1024,
946 256 * 1024,
947 512 * 1024,
948 1024 * 1024,
949 };
950
951 JComboBox barrierComboBox = new JComboBox();
952
953 for (int j = 0; j < itersPerBarrierChoices.length; ++j) {
954 String lab = p2ToString(itersPerBarrierChoices[j]) +
955 " iterations per barrier";
956 barrierComboBox.addItem(lab);
957 }
958 barrierComboBox.addItemListener(new ItemListener() {
959 public void itemStateChanged(ItemEvent evt) {
960 JComboBox src = (JComboBox)(evt.getItemSelectable());
961 int idx = src.getSelectedIndex();
962 RNG.itersPerBarrier.set(itersPerBarrierChoices[idx]);
963 }
964 });
965
966 RNG.itersPerBarrier.set(itersPerBarrierChoices[13]);
967 barrierComboBox.setSelectedIndex(13);
968
969 // RNG.itersPerBarrier.set(itersPerBarrierChoices[15]);
970 // barrierComboBox.setSelectedIndex(15);
971
972 return barrierComboBox;
973 }
974
975 JComboBox exchangeBox() {
976 final int[] exchangerChoices = {
977 1,
978 2,
979 4,
980 8,
981 16,
982 32,
983 64,
984 128,
985 256,
986 512,
987 1024,
988 };
989
990 JComboBox exchComboBox = new JComboBox();
991
992 for (int j = 0; j < exchangerChoices.length; ++j) {
993 String lab = p2ToString(exchangerChoices[j]) +
994 " max threads per barrier";
995 exchComboBox.addItem(lab);
996 }
997 exchComboBox.addItemListener(new ItemListener() {
998 public void itemStateChanged(ItemEvent evt) {
999 JComboBox src = (JComboBox)(evt.getItemSelectable());
1000 int idx = src.getSelectedIndex();
1001 RNG.exchangeParties.set(exchangerChoices[idx]);
1002 }
1003 });
1004
1005 RNG.exchangeParties.set(exchangerChoices[1]);
1006 exchComboBox.setSelectedIndex(1);
1007 return exchComboBox;
1008 }
1009
1010 JComboBox biasBox() {
1011 final int[] biasChoices = {
1012 -1,
1013 0,
1014 1
1015 };
1016
1017
1018 JComboBox biasComboBox = new JComboBox();
1019
1020 for (int j = 0; j < biasChoices.length; ++j) {
1021 String lab = biasToString(biasChoices[j]);
1022 biasComboBox.addItem(lab);
1023 }
1024 biasComboBox.addItemListener(new ItemListener() {
1025 public void itemStateChanged(ItemEvent evt) {
1026 JComboBox src = (JComboBox)(evt.getItemSelectable());
1027 int idx = src.getSelectedIndex();
1028 RNG.bias.set(biasChoices[idx]);
1029 }
1030 });
1031
1032 RNG.bias.set(biasChoices[1]);
1033 biasComboBox.setSelectedIndex(1);
1034 return biasComboBox;
1035 }
1036
1037 JComboBox capacityBox() {
1038
1039 final int[] bufferCapacityChoices = {
1040 1,
1041 4,
1042 64,
1043 256,
1044 1024,
1045 4096,
1046 16 * 1024,
1047 64 * 1024,
1048 256 * 1024,
1049 1024 * 1024,
1050 };
1051
1052 JComboBox bcapComboBox = new JComboBox();
1053
1054 for (int j = 0; j < bufferCapacityChoices.length; ++j) {
1055 String lab = p2ToString(bufferCapacityChoices[j]) +
1056 " element bounded buffers";
1057 bcapComboBox.addItem(lab);
1058 }
1059 bcapComboBox.addItemListener(new ItemListener() {
1060 public void itemStateChanged(ItemEvent evt) {
1061 JComboBox src = (JComboBox)(evt.getItemSelectable());
1062 int idx = src.getSelectedIndex();
1063 DefaultChannelCapacity.set(bufferCapacityChoices[idx]);
1064 }
1065 });
1066
1067
1068 DefaultChannelCapacity.set(bufferCapacityChoices[3]);
1069 bcapComboBox.setSelectedIndex(3);
1070 return bcapComboBox;
1071 }
1072
1073 JComboBox timeoutBox() {
1074
1075
1076 final long[] timeoutChoices = {
1077 0,
1078 1,
1079 10,
1080 100,
1081 1000,
1082 10000,
1083 100000,
1084 };
1085
1086
1087 JComboBox timeoutComboBox = new JComboBox();
1088
1089 for (int j = 0; j < timeoutChoices.length; ++j) {
1090 String lab = timeoutChoices[j] + " msec timeouts";
1091 timeoutComboBox.addItem(lab);
1092 }
1093 timeoutComboBox.addItemListener(new ItemListener() {
1094 public void itemStateChanged(ItemEvent evt) {
1095 JComboBox src = (JComboBox)(evt.getItemSelectable());
1096 int idx = src.getSelectedIndex();
1097 RNG.timeout.set(timeoutChoices[idx]);
1098 }
1099 });
1100
1101 RNG.timeout.set(timeoutChoices[3]);
1102 timeoutComboBox.setSelectedIndex(3);
1103 return timeoutComboBox;
1104 }
1105
1106 ClockDaemon timeDaemon = new ClockDaemon();
1107
1108 void startPoolStatus(final JLabel status) {
1109 Runnable updater = new Runnable() {
1110 int lastps = 0;
1111 public void run() {
1112 final int ps = Threads.activeThreads.get();
1113 if (lastps != ps) {
1114 lastps = ps;
1115 SwingUtilities.invokeLater(new Runnable() {
1116 public void run() {
1117 status.setText("Active threads: " + ps);
1118 } } );
1119 }
1120 }
1121 };
1122 timeDaemon.executePeriodically(250, updater, false);
1123 }
1124
1125 private final SynchronizedRef contention_ = new SynchronizedRef(null);
1126 private final SynchronizedInt loopsPerTest_ = new SynchronizedInt(0);
1127
1128 private final SynchronizedBoolean echoToSystemOut =
1129 new SynchronizedBoolean(false);
1130
1131
1132 private final JButton startstop_ = new JButton("Start");
1133
1134 private WaitableInt testNumber_ = new WaitableInt(1);
1135
1136 private void runOneTest(Runnable tst) throws InterruptedException {
1137 int nt = testNumber_.get();
1138 Threads.pool.execute(tst);
1139 testNumber_.whenNotEqual(nt, null);
1140 }
1141
1142 private void endOneTest() {
1143 testNumber_.increment();
1144 }
1145
1146 private SynchronizedBoolean running_ = new SynchronizedBoolean(false);
1147
1148 void cancel() {
1149 // not stable enough to cancel during construction
1150 synchronized (RNG.constructionLock) {
1151 try {
1152 Threads.pool.interruptAll();
1153 }
1154 catch(Exception ex) {
1155 System.out.println("\nException during cancel:\n" + ex);
1156 return;
1157 }
1158 }
1159 }
1160
1161
1162 void startTestSeries(Runnable tst) throws InterruptedException {
1163 running_.set(true);
1164 startstop_.setText("Stop");
1165 Threads.pool.execute(tst);
1166 }
1167
1168 // prevent odd class-gc problems on some VMs?
1169 class PrintStart implements Runnable {
1170 public void run() {
1171 startstop_.setText("Start");
1172 }
1173 }
1174
1175
1176 void endTestSeries() {
1177 running_.set(false);
1178 SwingUtilities.invokeLater(new PrintStart());
1179 }
1180
1181 /*
1182 void old_endTestSeries() {
1183 running_.set(false);
1184 SwingUtilities.invokeLater(new Runnable() {
1185 public void run() {
1186 startstop_.setText("Start");
1187 } } );
1188 }
1189 */
1190
1191 class TestSeries implements Runnable {
1192 final int firstclass;
1193 final int firstnthreads;
1194
1195 TestSeries() {
1196 firstclass = 0;
1197 firstnthreads = 0;
1198 }
1199
1200 TestSeries(final int firstc, final int firstnt) {
1201 firstclass = firstc;
1202 firstnthreads = firstnt;
1203 }
1204
1205 public void run() {
1206 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
1207
1208 try {
1209 int t = firstnthreads;
1210 int c = firstclass;
1211
1212 if (t < nthreadsChoices.length &&
1213 c < TestedClass.classes.length) {
1214
1215 for (;;) {
1216
1217
1218 // these checks are duplicated in OneTest, but added here
1219 // to minimize unecessary thread construction,
1220 // which can skew results
1221
1222 if (threadEnabled(t)) {
1223
1224 TestedClass entry = TestedClass.classes[c];
1225
1226 int nthreads = nthreadsChoices[t];
1227 int iters = loopsPerTest_.get();
1228 Fraction pshr = (Fraction)(contention_.get());
1229
1230 if (entry.isEnabled(nthreads, pshr)) {
1231
1232 runOneTest(new OneTest(c, t));
1233 }
1234 }
1235
1236 if (++c >= TestedClass.classes.length) {
1237 c = 0;
1238 if (++t >= nthreadsChoices.length)
1239 break;
1240 }
1241
1242 nextClassIdx_.set(c);
1243 nextThreadIdx_.set(t);
1244
1245 }
1246 }
1247
1248 }
1249 catch (InterruptedException ex) {
1250 Thread.currentThread().interrupt();
1251 }
1252 finally {
1253 endTestSeries();
1254 }
1255 }
1256 }
1257
1258 static class BarrierTimer implements Runnable {
1259 private long startTime_ = 0;
1260 private long endTime_ = 0;
1261
1262 public synchronized long getTime() {
1263 return endTime_ - startTime_;
1264 }
1265
1266 public synchronized void run() {
1267 long now = System.currentTimeMillis();
1268 if (startTime_ == 0)
1269 startTime_ = now;
1270 else
1271 endTime_ = now;
1272 }
1273 }
1274
1275 class OneTest implements Runnable {
1276 final int clsIdx;
1277 final int nthreadsIdx;
1278
1279 OneTest(int idx, int t) {
1280 clsIdx = idx;
1281 nthreadsIdx = t;
1282 }
1283
1284 public void run() {
1285 Thread.currentThread().setPriority(Thread.NORM_PRIORITY-3);
1286
1287 boolean wasInterrupted = false;
1288
1289 final TestedClass entry = TestedClass.classes[clsIdx];
1290
1291 final JLabel cell = (JLabel)(resultTable_[clsIdx+1][nthreadsIdx+1]);
1292 final Color oldfg = cell.getForeground();
1293
1294 try {
1295
1296
1297 if (Thread.interrupted()) return;
1298 if (!threadEnabled(nthreadsIdx)) return;
1299
1300 int nthreads = nthreadsChoices[nthreadsIdx];
1301 int iters = loopsPerTest_.get();
1302 Fraction pshr = (Fraction)(contention_.get());
1303
1304 if (!entry.isEnabled(nthreads, pshr)) return;
1305
1306 BarrierTimer timer = new BarrierTimer();
1307 CyclicBarrier barrier = new CyclicBarrier(nthreads+1, timer);
1308
1309 Class cls = entry.cls;
1310 Class chanCls = entry.buffCls;
1311
1312 try {
1313 SwingUtilities.invokeAndWait(new Runnable() {
1314 public void run() {
1315 cell.setForeground(Color.blue);
1316 cell.setText("RUN");
1317 cell.repaint();
1318 }
1319 });
1320 }
1321 catch (InvocationTargetException ex) {
1322 ex.printStackTrace();
1323 System.exit(-1);
1324 }
1325 synchronized (RNG.constructionLock) {
1326 RNG.reset(nthreads);
1327
1328 if (chanCls == null) {
1329 RNG shared = (RNG)(cls.newInstance());
1330 for (int k = 0; k < nthreads; ++k) {
1331 RNG pri = (RNG)(cls.newInstance());
1332 TestLoop l = new TestLoop(shared, pri, pshr, iters, barrier);
1333 Threads.pool.execute(l.testLoop());
1334 }
1335 }
1336 else {
1337 Channel shared = (Channel)(chanCls.newInstance());
1338 if (nthreads == 1) {
1339 ChanRNG single = (ChanRNG)(cls.newInstance());
1340 single.setSingle(true);
1341 PCTestLoop l = new PCTestLoop(single.getDelegate(), single, pshr,
1342 iters, barrier,
1343 shared, shared);
1344 Threads.pool.execute(l.testLoop(true));
1345 }
1346 else if (nthreads % 2 != 0)
1347 throw new Error("Must have even number of threads!");
1348 else {
1349 int npairs = nthreads / 2;
1350
1351 for (int k = 0; k < npairs; ++k) {
1352 ChanRNG t = (ChanRNG)(cls.newInstance());
1353 t.setSingle(false);
1354 Channel chan = (Channel)(chanCls.newInstance());
1355
1356 PCTestLoop l = new PCTestLoop(t.getDelegate(), t, pshr,
1357 iters, barrier,
1358 shared, chan);
1359
1360 Threads.pool.execute(l.testLoop(false));
1361 Threads.pool.execute(l.testLoop(true));
1362
1363 }
1364 }
1365 }
1366
1367 if (echoToSystemOut.get()) {
1368 System.out.print(
1369 entry.name + " " +
1370 nthreads + "T " +
1371 pshr + "S " +
1372 RNG.computeLoops.get() + "I " +
1373 RNG.syncMode.get() + "Lm " +
1374 RNG.timeout.get() + "TO " +
1375 RNG.producerMode.get() + "Pm " +
1376 RNG.consumerMode.get() + "Cm " +
1377 RNG.bias.get() + "B " +
1378 DefaultChannelCapacity.get() + "C " +
1379 RNG.exchangeParties.get() + "Xp " +
1380 RNG.itersPerBarrier.get() + "Ib : "
1381 );
1382 }
1383
1384 }
1385
1386 // Uncomment if AWT doesn't update right
1387 // Thread.sleep(100);
1388
1389 barrier.barrier(); // start
1390
1391 barrier.barrier(); // stop
1392
1393 long tm = timer.getTime();
1394 long totalIters = nthreads * iters;
1395 double dns = tm * 1000.0 * PRECISION / totalIters;
1396 long ns = Math.round(dns);
1397
1398 setTime(ns, clsIdx, nthreadsIdx);
1399
1400 if (echoToSystemOut.get()) {
1401 System.out.println(formatTime(ns, true));
1402 }
1403
1404 }
1405 catch (BrokenBarrierException ex) {
1406 wasInterrupted = true;
1407 }
1408 catch (InterruptedException ex) {
1409 wasInterrupted = true;
1410 Thread.currentThread().interrupt();
1411 }
1412 catch (Exception ex) {
1413 ex.printStackTrace();
1414 System.out.println("Construction Exception?");
1415 System.exit(-1);
1416 }
1417 finally {
1418 final boolean clear = wasInterrupted;
1419 SwingUtilities.invokeLater(new Runnable() {
1420 public void run() {
1421 if (clear) cell.setText("");
1422 cell.setForeground(oldfg);
1423 cell.repaint();
1424 }
1425 });
1426
1427 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
1428 endOneTest();
1429 }
1430 }
1431 }
1432
1433 }
1434
1435 class Threads implements ThreadFactory {
1436
1437 static final SynchronizedInt activeThreads = new SynchronizedInt(0);
1438
1439 static final Threads factory = new Threads();
1440
1441 static final PooledExecutor pool = new PooledExecutor();
1442
1443 static {
1444 pool.setKeepAliveTime(10000);
1445 pool.setThreadFactory(factory);
1446 }
1447
1448 static class MyThread extends Thread {
1449 public MyThread(Runnable cmd) {
1450 super(cmd);
1451 }
1452
1453 public void run() {
1454 activeThreads.increment();
1455
1456 try {
1457 super.run();
1458 }
1459 finally {
1460 activeThreads.decrement();
1461 }
1462 }
1463 }
1464
1465 public Thread newThread(Runnable cmd) {
1466 return new MyThread(cmd);
1467 }
1468 }
1469
1470
1471
1472 class TestLoop {
1473
1474 final RNG shared;
1475 final RNG primary;
1476 final int iters;
1477 final Fraction pshared;
1478 final CyclicBarrier barrier;
1479 final boolean[] useShared;
1480 final int firstidx;
1481
1482 public TestLoop(RNG sh, RNG pri, Fraction pshr, int it, CyclicBarrier br) {
1483 shared = sh;
1484 primary = pri;
1485 pshared = pshr;
1486 iters = it;
1487 barrier = br;
1488
1489 firstidx = (int)(primary.get());
1490
1491 int num = (int)(pshared.numerator());
1492 int denom = (int)(pshared.denominator());
1493
1494 if (num == 0 || primary == shared) {
1495 useShared = new boolean[1];
1496 useShared[0] = false;
1497 }
1498 else if (num >= denom) {
1499 useShared = new boolean[1];
1500 useShared[0] = true;
1501 }
1502 else {
1503 // create bool array and randomize it.
1504 // This ensures that always same number of shared calls.
1505
1506 // denom slots is too few. iters is too many. an arbitrary compromise is:
1507 int xfactor = 1024 / denom;
1508 if (xfactor < 1) xfactor = 1;
1509 useShared = new boolean[denom * xfactor];
1510 for (int i = 0; i < num * xfactor; ++i)
1511 useShared[i] = true;
1512 for (int i = num * xfactor; i < denom * xfactor; ++i)
1513 useShared[i] = false;
1514
1515 for (int i = 1; i < useShared.length; ++i) {
1516 int j = ((int) (shared.next() & 0x7FFFFFFF)) % (i + 1);
1517 boolean tmp = useShared[i];
1518 useShared[i] = useShared[j];
1519 useShared[j] = tmp;
1520 }
1521 }
1522 }
1523
1524 public Runnable testLoop() {
1525 return new Runnable() {
1526 public void run() {
1527 int itersPerBarrier = RNG.itersPerBarrier.get();
1528 try {
1529 int delta = -1;
1530 if (primary.getClass().equals(PrioritySemRNG.class)) {
1531 delta = 2 - (int)((primary.get() % 5));
1532 }
1533 Thread.currentThread().setPriority(Thread.NORM_PRIORITY+delta);
1534
1535 int nshared = (int)(iters * pshared.asDouble());
1536 int nprimary = iters - nshared;
1537 int idx = firstidx;
1538
1539 barrier.barrier();
1540
1541 for (int i = iters; i > 0; --i) {
1542 ++idx;
1543 if (i % itersPerBarrier == 0)
1544 primary.exchange();
1545 else {
1546
1547 RNG r;
1548
1549 if (nshared > 0 && useShared[idx % useShared.length]) {
1550 --nshared;
1551 r = shared;
1552 }
1553 else {
1554 --nprimary;
1555 r = primary;
1556 }
1557 long rnd = r.next();
1558 if (rnd % 2 == 0 && Thread.currentThread().isInterrupted())
1559 break;
1560 }
1561 }
1562 }
1563 catch (BrokenBarrierException ex) {
1564 }
1565 catch (InterruptedException ex) {
1566 Thread.currentThread().interrupt();
1567 }
1568 finally {
1569 try {
1570 barrier.barrier();
1571 }
1572 catch (BrokenBarrierException ex) {
1573 }
1574 catch (InterruptedException ex) {
1575 Thread.currentThread().interrupt();
1576 }
1577 finally {
1578 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
1579 }
1580
1581 }
1582 }
1583 };
1584 }
1585 }
1586
1587 class PCTestLoop extends TestLoop {
1588 final Channel primaryChannel;
1589 final Channel sharedChannel;
1590
1591 public PCTestLoop(RNG sh, RNG pri, Fraction pshr, int it,
1592 CyclicBarrier br, Channel shChan, Channel priChan) {
1593 super(sh, pri, pshr, it, br);
1594 sharedChannel = shChan;
1595 primaryChannel = priChan;
1596 }
1597
1598 public Runnable testLoop(final boolean isProducer) {
1599 return new Runnable() {
1600 public void run() {
1601 int delta = -1;
1602 Thread.currentThread().setPriority(Thread.NORM_PRIORITY+delta);
1603 int itersPerBarrier = RNG.itersPerBarrier.get();
1604 try {
1605
1606 int nshared = (int)(iters * pshared.asDouble());
1607 int nprimary = iters - nshared;
1608 int idx = firstidx;
1609
1610 barrier.barrier();
1611
1612 ChanRNG target = (ChanRNG)(primary);
1613
1614 for (int i = iters; i > 0; --i) {
1615 ++idx;
1616 if (i % itersPerBarrier == 0)
1617 primary.exchange();
1618 else {
1619 Channel c;
1620
1621 if (nshared > 0 && useShared[idx % useShared.length]) {
1622 --nshared;
1623 c = sharedChannel;
1624 }
1625 else {
1626 --nprimary;
1627 c = primaryChannel;
1628 }
1629
1630 long rnd;
1631 if (isProducer)
1632 rnd = target.producerNext(c);
1633 else
1634 rnd = target.consumerNext(c);
1635
1636 if (rnd % 2 == 0 && Thread.currentThread().isInterrupted())
1637 break;
1638 }
1639 }
1640 }
1641 catch (BrokenBarrierException ex) {
1642 }
1643 catch (InterruptedException ex) {
1644 Thread.currentThread().interrupt();
1645 }
1646 finally {
1647 try {
1648 barrier.barrier();
1649 }
1650 catch (InterruptedException ex) {
1651 Thread.currentThread().interrupt();
1652 }
1653 catch (BrokenBarrierException ex) {
1654 }
1655 finally {
1656 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
1657 }
1658 }
1659 }
1660 };
1661 }
1662 }
1663
1664 // -------------------------------------------------------------
1665
1666
1667 abstract class RNG implements Serializable, Comparable {
1668 static final int firstSeed = 4321;
1669 static final int rmod = 2147483647;
1670 static final int rmul = 16807;
1671
1672 static int lastSeed = firstSeed;
1673 static final int smod = 32749;
1674 static final int smul = 3125;
1675
1676 static final Object constructionLock = RNG.class;
1677
1678 // Use construction lock for all params to disable
1679 // changes in midst of construction of test objects.
1680
1681 static final SynchronizedInt computeLoops =
1682 new SynchronizedInt(16, constructionLock);
1683 static final SynchronizedInt syncMode =
1684 new SynchronizedInt(0, constructionLock);
1685 static final SynchronizedInt producerMode =
1686 new SynchronizedInt(0, constructionLock);
1687 static final SynchronizedInt consumerMode =
1688 new SynchronizedInt(0, constructionLock);
1689 static final SynchronizedInt bias =
1690 new SynchronizedInt(0, constructionLock);
1691 static final SynchronizedLong timeout =
1692 new SynchronizedLong(100, constructionLock);
1693 static final SynchronizedInt exchangeParties =
1694 new SynchronizedInt(1, constructionLock);
1695 static final SynchronizedInt sequenceNumber =
1696 new SynchronizedInt(0, constructionLock);
1697 static final SynchronizedInt itersPerBarrier =
1698 new SynchronizedInt(0, constructionLock);
1699
1700 static Rendezvous[] exchangers_;
1701
1702 static void reset(int nthreads) {
1703 synchronized(constructionLock) {
1704 sequenceNumber.set(-1);
1705 int parties = exchangeParties.get();
1706 if (nthreads < parties) parties = nthreads;
1707 if (nthreads % parties != 0)
1708 throw new Error("need even multiple of parties");
1709 exchangers_ = new Rendezvous[nthreads / parties];
1710 for (int i = 0; i < exchangers_.length; ++i) {
1711 exchangers_[i] = new Rendezvous(parties);
1712 }
1713 }
1714 }
1715
1716 static long nextSeed() {
1717 synchronized(constructionLock) {
1718 long s = lastSeed;
1719 lastSeed = (lastSeed * smul) % smod;
1720 if (lastSeed == 0)
1721 lastSeed = (int)(System.currentTimeMillis());
1722 return s;
1723 }
1724 }
1725
1726 final int cloops = computeLoops.get();
1727 final int pcBias = bias.get();
1728 final int smode = syncMode.get();
1729 final int pmode = producerMode.get();
1730 final int cmode = consumerMode.get();
1731 final long waitTime = timeout.get();
1732 Rendezvous exchanger_ = null;
1733
1734 synchronized Rendezvous getExchanger() {
1735 if (exchanger_ == null) {
1736 synchronized (constructionLock) {
1737 int idx = sequenceNumber.increment();
1738 exchanger_ = exchangers_[idx % exchangers_.length];
1739 }
1740 }
1741 return exchanger_;
1742 }
1743
1744 public void exchange() throws InterruptedException {
1745 Rendezvous ex = getExchanger();
1746 Runnable r = (Runnable)(ex.rendezvous(new UpdateCommand(this)));
1747 if (r != null) r.run();
1748 }
1749
1750 public int compareTo(Object other) {
1751 int h1 = hashCode();
1752 int h2 = other.hashCode();
1753 if (h1 < h2) return -1;
1754 else if (h1 > h2) return 1;
1755 else return 0;
1756 }
1757
1758 protected final long compute(long l) {
1759 int loops = (int)((l & 0x7FFFFFFF) % (cloops * 2)) + 1;
1760 for (int i = 0; i < loops; ++i) l = (l * rmul) % rmod;
1761 return (l == 0)? firstSeed : l;
1762 }
1763
1764 abstract protected void set(long l);
1765 abstract protected long internalGet();
1766 abstract protected void internalUpdate();
1767
1768 public long get() { return internalGet(); }
1769 public void update() { internalUpdate(); }
1770 public long next() { internalUpdate(); return internalGet(); }
1771 }
1772
1773
1774 class UpdateCommand implements Runnable, Serializable, Comparable {
1775 private final RNG obj_;
1776 final long cmpVal;
1777 public UpdateCommand(RNG o) {
1778 obj_ = o;
1779 cmpVal = o.get();
1780 }
1781
1782 public void run() { obj_.update(); }
1783
1784 public int compareTo(Object x) {
1785 UpdateCommand u = (UpdateCommand)x;
1786 if (cmpVal < u.cmpVal) return -1;
1787 else if (cmpVal > u.cmpVal) return 1;
1788 else return 0;
1789 }
1790 }
1791
1792
1793 class GetFunction implements Callable {
1794 private final RNG obj_;
1795 public GetFunction(RNG o) { obj_ = o; }
1796 public Object call() { return new Long(obj_.get()); }
1797 }
1798
1799 class NextFunction implements Callable {
1800 private final RNG obj_;
1801 public NextFunction(RNG o) { obj_ = o; }
1802 public Object call() { return new Long(obj_.next()); }
1803 }
1804
1805
1806 class NoSynchRNG extends RNG {
1807 protected long current_ = nextSeed();
1808
1809 protected void set(long l) { current_ = l; }
1810 protected long internalGet() { return current_; }
1811 protected void internalUpdate() { set(compute(internalGet())); }
1812 }
1813
1814 class PublicSynchRNG extends NoSynchRNG {
1815 public synchronized long get() { return internalGet(); }
1816 public synchronized void update() { internalUpdate(); }
1817 public synchronized long next() { internalUpdate(); return internalGet(); }
1818 }
1819
1820 class AllSynchRNG extends PublicSynchRNG {
1821 protected synchronized void set(long l) { current_ = l; }
1822 protected synchronized long internalGet() { return current_; }
1823 protected synchronized void internalUpdate() { set(compute(internalGet())); }
1824 }
1825
1826
1827 class AClongRNG extends RNG {
1828 protected final SynchronizedLong acurrent_ =
1829 new SynchronizedLong(nextSeed());
1830
1831 protected void set(long l) { throw new Error("No set allowed"); }
1832 protected long internalGet() { return acurrent_.get(); }
1833
1834 protected void internalUpdate() {
1835 int retriesBeforeSleep = 100;
1836 int maxSleepTime = 100;
1837 int retries = 0;
1838 for (;;) {
1839 long v = internalGet();
1840 long n = compute(v);
1841 if (acurrent_.commit(v, n))
1842 return;
1843 else if (++retries >= retriesBeforeSleep) {
1844 try {
1845 Thread.sleep(n % maxSleepTime);
1846 }
1847 catch (InterruptedException ex) {
1848 Thread.currentThread().interrupt();
1849 }
1850 retries = 0;
1851 }
1852 }
1853 }
1854
1855 }
1856
1857 class SynchLongRNG extends RNG {
1858 protected final SynchronizedLong acurrent_ =
1859 new SynchronizedLong(nextSeed());
1860
1861 protected void set(long l) { acurrent_.set(l); }
1862 protected long internalGet() { return acurrent_.get(); }
1863 protected void internalUpdate() { set(compute(internalGet())); }
1864
1865 }
1866
1867 abstract class DelegatedRNG extends RNG {
1868 protected RNG delegate_ = null;
1869 public synchronized void setDelegate(RNG d) { delegate_ = d; }
1870 protected synchronized RNG getDelegate() { return delegate_; }
1871
1872 public long get() { return getDelegate().get(); }
1873 public void update() { getDelegate().update(); }
1874 public long next() { return getDelegate().next(); }
1875
1876 protected void set(long l) { throw new Error(); }
1877 protected long internalGet() { throw new Error(); }
1878 protected void internalUpdate() { throw new Error(); }
1879
1880 }
1881
1882 class SDelegatedRNG extends DelegatedRNG {
1883 public SDelegatedRNG() { setDelegate(new NoSynchRNG()); }
1884 public synchronized long get() { return getDelegate().get(); }
1885 public synchronized void update() { getDelegate().update(); }
1886 public synchronized long next() { return getDelegate().next(); }
1887 }
1888
1889
1890 class SyncDelegatedRNG extends DelegatedRNG {
1891 protected final Sync cond_;
1892 public SyncDelegatedRNG(Sync c) {
1893 cond_ = c;
1894 setDelegate(new NoSynchRNG());
1895 }
1896
1897
1898 protected final void acquire() throws InterruptedException {
1899 if (smode == 0) {
1900 cond_.acquire();
1901 }
1902 else {
1903 while (!cond_.attempt(waitTime)) {}
1904 }
1905 }
1906
1907 public long next() {
1908 try {
1909 acquire();
1910
1911 getDelegate().update();
1912 long l = getDelegate().get();
1913 cond_.release();
1914 return l;
1915 }
1916 catch(InterruptedException x) {
1917 Thread.currentThread().interrupt();
1918 return 0;
1919 }
1920 }
1921
1922 public long get() {
1923 try {
1924 acquire();
1925 long l = getDelegate().get();
1926 cond_.release();
1927 return l;
1928 }
1929 catch(InterruptedException x) {
1930 Thread.currentThread().interrupt();
1931 return 0;
1932 }
1933 }
1934
1935 public void update() {
1936 try {
1937 acquire();
1938 getDelegate().update();
1939 cond_.release();
1940 }
1941 catch(InterruptedException x) {
1942 Thread.currentThread().interrupt();
1943 }
1944 }
1945
1946
1947 }
1948
1949 class MutexRNG extends SyncDelegatedRNG {
1950 public MutexRNG() { super(new Mutex()); }
1951 }
1952
1953
1954 class SemRNG extends SyncDelegatedRNG {
1955 public SemRNG() { super(new Semaphore(1)); }
1956 }
1957
1958 class WpSemRNG extends SyncDelegatedRNG {
1959 public WpSemRNG() { super(new WaiterPreferenceSemaphore(1)); }
1960 }
1961
1962 class FifoRNG extends SyncDelegatedRNG {
1963 public FifoRNG() { super(new FIFOSemaphore(1)); }
1964 }
1965
1966 class PrioritySemRNG extends SyncDelegatedRNG {
1967 public PrioritySemRNG() { super(new PrioritySemaphore(1)); }
1968 }
1969
1970 class RlockRNG extends SyncDelegatedRNG {
1971 public RlockRNG() { super(new ReentrantLock()); }
1972 }
1973
1974
1975 class RWLockRNG extends NoSynchRNG {
1976 protected final ReadWriteLock lock_;
1977 public RWLockRNG(ReadWriteLock l) {
1978 lock_ = l;
1979 }
1980
1981 protected final void acquireR() throws InterruptedException {
1982 if (smode == 0) {
1983 lock_.readLock().acquire();
1984 }
1985 else {
1986 while (!lock_.readLock().attempt(waitTime)) {}
1987 }
1988 }
1989
1990 protected final void acquireW() throws InterruptedException {
1991 if (smode == 0) {
1992 lock_.writeLock().acquire();
1993 }
1994 else {
1995 while (!lock_.writeLock().attempt(waitTime)) {}
1996 }
1997 }
1998
1999
2000 public long next() {
2001 long l = 0;
2002 try {
2003 acquireR();
2004 l = current_;
2005 lock_.readLock().release();
2006 }
2007 catch(InterruptedException x) {
2008 Thread.currentThread().interrupt();
2009 return 0;
2010 }
2011
2012 l = compute(l);
2013
2014 try {
2015 acquireW();
2016 set(l);
2017 lock_.writeLock().release();
2018 return l;
2019 }
2020 catch(InterruptedException x) {
2021 Thread.currentThread().interrupt();
2022 return 0;
2023 }
2024 }
2025
2026
2027 public long get() {
2028 try {
2029 acquireR();
2030 long l = current_;
2031 lock_.readLock().release();
2032 return l;
2033 }
2034 catch(InterruptedException x) {
2035 Thread.currentThread().interrupt();
2036 return 0;
2037 }
2038 }
2039
2040 public void update() {
2041 long l = 0;
2042
2043 try {
2044 acquireR();
2045 l = current_;
2046 lock_.readLock().release();
2047 }
2048 catch(InterruptedException x) {
2049 Thread.currentThread().interrupt();
2050 return;
2051 }
2052
2053 l = compute(l);
2054
2055 try {
2056 acquireW();
2057 set(l);
2058 lock_.writeLock().release();
2059 }
2060 catch(InterruptedException x) {
2061 Thread.currentThread().interrupt();
2062 }
2063 }
2064
2065 }
2066
2067 class WpRWlockRNG extends RWLockRNG {
2068 public WpRWlockRNG() { super(new WriterPreferenceReadWriteLock()); }
2069 }
2070
2071 class ReaderPrefRWlockRNG extends RWLockRNG {
2072 public ReaderPrefRWlockRNG() {
2073 super(new ReaderPreferenceReadWriteLock());
2074 }
2075
2076
2077 }
2078
2079 class FIFORWlockRNG extends RWLockRNG {
2080 public FIFORWlockRNG() { super(new FIFOReadWriteLock()); }
2081 }
2082
2083
2084 class ReentrantRWlockRNG extends RWLockRNG {
2085 public ReentrantRWlockRNG() {
2086 super(new ReentrantWriterPreferenceReadWriteLock());
2087 }
2088
2089 public void update() { // use embedded acquires
2090 long l = 0;
2091
2092 try {
2093 acquireW();
2094
2095 try {
2096 acquireR();
2097 l = current_;
2098 lock_.readLock().release();
2099 }
2100 catch(InterruptedException x) {
2101 Thread.currentThread().interrupt();
2102 return;
2103 }
2104
2105 l = compute(l);
2106
2107 set(l);
2108 lock_.writeLock().release();
2109 }
2110 catch(InterruptedException x) {
2111 Thread.currentThread().interrupt();
2112 }
2113 }
2114
2115 }
2116
2117
2118 abstract class ExecutorRNG extends DelegatedRNG {
2119 Executor executor_;
2120
2121
2122 synchronized void setExecutor(Executor e) { executor_ = e; }
2123 synchronized Executor getExecutor() { return executor_; }
2124
2125 Runnable delegatedUpdate_ = null;
2126 Callable delegatedNext_ = null;
2127
2128 synchronized Runnable delegatedUpdateCommand() {
2129 if (delegatedUpdate_ == null)
2130 delegatedUpdate_ = new UpdateCommand(getDelegate());
2131 return delegatedUpdate_;
2132 }
2133
2134 synchronized Callable delegatedNextFunction() {
2135 if (delegatedNext_ == null)
2136 delegatedNext_ = new NextFunction(getDelegate());
2137 return delegatedNext_;
2138 }
2139
2140 public void update() {
2141 try {
2142 getExecutor().execute(delegatedUpdateCommand());
2143 }
2144 catch (InterruptedException ex) {
2145 Thread.currentThread().interrupt();
2146 }
2147 }
2148
2149 // Each call to next gets result of previous future
2150 FutureResult nextResult_ = null;
2151
2152 public synchronized long next() {
2153 long res = 0;
2154 try {
2155 if (nextResult_ == null) { // direct call first time through
2156 nextResult_ = new FutureResult();
2157 nextResult_.set(new Long(getDelegate().next()));
2158 }
2159 FutureResult currentResult = nextResult_;
2160
2161 nextResult_ = new FutureResult();
2162 Runnable r = nextResult_.setter(delegatedNextFunction());
2163 getExecutor().execute(r);
2164
2165 res = ((Long)(currentResult.get())).longValue();
2166
2167 }
2168 catch (InterruptedException ex) {
2169 Thread.currentThread().interrupt();
2170 }
2171 catch (InvocationTargetException ex) {
2172 ex.printStackTrace();
2173 throw new Error("Bad Callable?");
2174 }
2175 return res;
2176 }
2177 }
2178
2179 class DirectExecutorRNG extends ExecutorRNG {
2180 public DirectExecutorRNG() {
2181 setDelegate(new PublicSynchRNG());
2182 setExecutor(new DirectExecutor());
2183 }
2184 }
2185
2186 class LockedSemRNG extends ExecutorRNG {
2187 public LockedSemRNG() {
2188 setDelegate(new NoSynchRNG());
2189 setExecutor(new LockedExecutor(new Semaphore(1)));
2190 }
2191 }
2192
2193 class QueuedExecutorRNG extends ExecutorRNG {
2194 static final QueuedExecutor exec = new QueuedExecutor();
2195 static { exec.setThreadFactory(Threads.factory); }
2196 public QueuedExecutorRNG() {
2197 setDelegate(new PublicSynchRNG());
2198 setExecutor(exec);
2199 }
2200 }
2201
2202 class ForcedStartRunnable implements Runnable {
2203 protected final Latch latch_ = new Latch();
2204 protected final Runnable command_;
2205
2206 ForcedStartRunnable(Runnable command) { command_ = command; }
2207
2208 public Latch started() { return latch_; }
2209
2210 public void run() {
2211 latch_.release();
2212 command_.run();
2213 }
2214 }
2215
2216
2217 class ForcedStartThreadedExecutor extends ThreadedExecutor {
2218 public void execute(Runnable command) throws InterruptedException {
2219 ForcedStartRunnable wrapped = new ForcedStartRunnable(command);
2220 super.execute(wrapped);
2221 wrapped.started().acquire();
2222 }
2223 }
2224
2225 class ThreadedExecutorRNG extends ExecutorRNG {
2226 static final ThreadedExecutor exec = new ThreadedExecutor();
2227 static { exec.setThreadFactory(Threads.factory); }
2228
2229 public ThreadedExecutorRNG() {
2230 setDelegate(new PublicSynchRNG());
2231 setExecutor(exec);
2232 }
2233 }
2234
2235
2236 class PooledExecutorRNG extends ExecutorRNG {
2237 static final PooledExecutor exec = Threads.pool;
2238
2239 public PooledExecutorRNG() {
2240 setDelegate(new PublicSynchRNG());
2241 setExecutor(exec);
2242 }
2243 }
2244
2245
2246 class ChanRNG extends DelegatedRNG {
2247
2248 boolean single_;
2249
2250 ChanRNG() {
2251 setDelegate(new PublicSynchRNG());
2252 }
2253
2254 public synchronized void setSingle(boolean s) { single_ = s; }
2255 public synchronized boolean isSingle() { return single_; }
2256
2257 public long producerNext(Channel c) throws InterruptedException {
2258 RNG r = getDelegate();
2259 if (isSingle()) {
2260 c.put(r);
2261 r = (RNG)(c.take());
2262 r.update();
2263 }
2264 else {
2265 if (pcBias < 0) {
2266 r.update();
2267 r.update(); // update consumer side too
2268 }
2269 else if (pcBias == 0) {
2270 r.update();
2271 }
2272
2273 if (pmode == 0) {
2274 c.put(r);
2275 }
2276 else {
2277 while (!(c.offer(r, waitTime))) {}
2278 }
2279 }
2280 return r.get();
2281 }
2282
2283 public long consumerNext(Channel c) throws InterruptedException {
2284 RNG r = null;
2285 if (cmode == 0) {
2286 r = (RNG)(c.take());
2287 }
2288 else {
2289 while (r == null) r = (RNG)(c.poll(waitTime));
2290 }
2291
2292 if (pcBias == 0) {
2293 r.update();
2294 }
2295 else if (pcBias > 0) {
2296 r.update();
2297 r.update();
2298 }
2299 return r.get();
2300 }
2301 }
2302