Mercurial > hg > blitz_condensed
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 |