📄 synchronizationtimer.java
字号:
/* File: SynchronizationTimer.java Originally written by Doug Lea and released into the public domain. This may be used for any purposes whatsoever without acknowledgment. Thanks for the assistance and support of Sun Microsystems Labs, and everyone contributing, testing, and using this code. History: Date Who What 7Jul1998 dl Create public version 16Jul1998 dl fix intialization error for compute loops combined into one frame misc layout and defaults changes increase printed precision overlap get/set in Executor tests Swap defaults for swing import Active thread counts reflect executors 30Aug1998 dl Misc revisions to mesh with 1.1.0 27jan1999 dl Eliminate GC calls 24Nov2001 dl Increase some default values*/package EDU.oswego.cs.dl.util.concurrent.misc;// Swap the following sets of imports if necessary.import javax.swing.*;import javax.swing.border.*;//import com.sun.java.swing.*;//import com.sun.java.swing.border.*;import EDU.oswego.cs.dl.util.concurrent.*;import java.awt.*;import java.awt.event.*;import java.io.*;import java.net.*;import java.lang.reflect.*;/** * * This program records times for various fine-grained synchronization * schemes, and provides some ways of measuring them over different * context parameters. * * <p> * Quick start: * <ol> * <li>javac -d <em>base of some CLASSPATH</em> *.java <br> * You'll need Swing (JFC). (This * program currently imports the javax.swing versions. * You can edit imports to instead use other versions.) * <li>java EDU.oswego.cs.dl.util.concurrent.misc.SynchronizationTimer <br> * <li> Click<em> start</em>. * Clicking <em>stop</em> cancels the run. Cancellation can take * a while when there are a lot of threads. * <li>For more explanation about tested classes, see * <a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html">Documentation for util.concurrent</a> * </ol> * * <p> * Synchronization schemes are tested around implementations and * subclasses of <code>RNG</code>, which is just a hacked random * number generator class. Objects of this class have just enough * state and require just enough computation to be reasonable minimal * targets. (Additionally, random numbers are needed a lot in these * kinds of time tests, so basing them on objects that produce random * numbers is convenient.) Computation of each random number is * padded a bit with an adjustable compute loop running a random * number of times to avoid getting schedulers locked into * uninteresting patterns. * * <p> * Each iteration of each test ultimately somehow calls * the random number generation * method of an RNG. The time listed is the average time it took to do * one iteration, in microseconds. These are just based on wallclock * time (System.currentTimeMillis()). Thread * construction time is <em>NOT</em> included in these times. * In tests with many threads, construction and other bookkeeping * can take longer than the tests themselves. * <p> * Results are listed in a table, and optionally printed on standard output. * You can redirect standard output to save to a file. * <p> * The total amount of ``real'' computation reported in each cell is * the same. Thus, the unobtainably ideal pattern of results would be * for every cell of the table to be the same (and very small). * <p> * A thread pool (PooledExecutor) is used to manage the threads used in * test runs. The current number of active threads is indicated in * the panel. It should normally be at most three plus the number of threads used in the * indicated test column (there are at most three overhead threads per run), although * it may transiently climb, and is larger in those tests that * generate their own internal threads (for example ThreadedExceutor). If the * indicated size fails to return to zero within about 10 seconds of * either hitting stop * or the end of a run, you may have a * problem with interruption handling on your Java VM. * * <p> * This program cannot * tell you how busy your computer is while running tests. * You can run a utility program (for * example <code>perfmeter</code> or <code>top</code> on unix) * alongside this program * to find out. * <p> * A number of control parameters can be changed at any time. * Most combinations of parameter settings create contexts * that are completely unrepresentative of those seen in practical * applications. However, they can be set to provide rough analogs of * real applications, and the results used as rough guesses about * performance impact. Also, do not be too upset about slow * performance on tests representing situations * that would never occur in practice. * <p> * * You can control parameters by clicking any of the following, * at any time. (You can even change parameters * while tests are running, in which case they will take * effect as soon as possible. Most controls momentarily stall * while test objects and threads are being constructed, to avoid * inconsistencies during test runs.) * <dl> * * <dt> Number of threads * * <dd> Controls concurrency. The indicated number of threads are * started simultaneously and then waited out. * * <dt>Contention. * * <dd>Percent sharing among threads. Zero percent means that each * thread has its own RNG object, so there is no * interference among threads. The zero * percent case thus shows the cost of synchronization mechanics that * happen to never be needed. * 100 percent sharing means that all * threads call methods on the same object, so each thread will have to * wait until the RNG objects are not being used by others. * In between is in between: Only the given percentage of calls are * made to shared RNG objects; others are to unshared. * Contention in classes that use Channels works slightly differently: * The Channels are shared, not the base RNG objects. (Another way * of looking at it is that tests demonstrate effects of multiple * producers and consumers on the same channel.) * * <dt>Classes * <dd>You can choose to only test the indicated classes. You can * probably figure out how to add more classes to run yourself. * * <dt>Calls per thread per test * * <dd>Specifies number of iterations per thread per test. The listed * times are averages over these iterations. The default seems to * provide precise enough values for informal testing purposes. * You should expect to see a fair amount of variation across * repeated runs. * If you get zeroes printed in any cell, this means that the * test ran too fast to measure in milleconds, so you should increase the * iterations value. * * <dt> Computations per call * * <dd>Specifies length of each call by setting an internal looping * parameter inside each RNG object. Shorter calls lead to shorter * times between synchronization measures. Longer calls, along with * high contention can be used to force timeouts to occur. * * <dt> Iterations per barrier. * * <dd> Specifies the number of iterations performed by each thread until * a synchronization barrier is forced with other threads, forcing * it to wait for other threads to reach the same number of iterations. This * controls the amount of interaction (versus contention) among threads. * Setting to a value greater than the number of iterations per test * effectively disables barriers. * * <dt> Threads per barrier * * <dd> Specifies how many threads are forced to synchronize at each * barrier point. Greater numbers cause more threads to wait for each * other at barriers. Setting to 1 means that a thread only has to * wait for itself, which means not to wait at all. * * <dt>Lock mode * * <dd>For classes that support it, this controls whether mutual * exclusion waits are done via standard blocking synchronization, or * a loop repeatedly calling a timed wait. * * <dt>Producer mode * * <dd>For classes that support it, this controls whether producers * perform blocking puts versus loops repeatedly calling offer. * * <dt>Consumer mode * * <dd>For classes that support it, this controls whether consumers * perform blocking takes versus loops repeatedly calling poll. * * <dt> Timeouts * * <dd> Specifies the duration of timeouts used in timeout mode. A * value of zero results in pure spin-loops. * * <dt>Producer/consumer rates. * * <dd>For tests involving producer/consumer pairs, this controls * whether the producer is much faster, about the same speed, or much * slower than the consumer. This is implemented by having the * producer do all, half, or none of the actual calls to update, in * addition to adding elements to channel. * * <dt>Buffer capacity * * <dd>For tests involving finite capacity * buffers, this controls maximum buffer size. * * </dl> * * <p> * To scaffold all this, the RNG class is defined in * layers. Each RNG has internal non-public methods that do the actual * computation, and public methods that call the internal ones. The * particular classes run in tests might change over time, but * currently includes the following general kinds: * * <dl> * * * <dt> Using built-in synchronization * <dd> Versions of RNG classes that use (or don't use) * synchronized methods and/or blocks. Also some tests of * simple SynchronizedVariables. Tests that would not * be thread-safe are not run when there is more than one * thread and non-zero contention. * * * <dt> Using <code>Sync</code> classes as locks * <dd> Classes protecting public methods via Semaphores, mutexes, etc. * In each case, the outer public methods delegate actions to * another RNG object, surrounded by acquire/release/etc. The * class called SDelegated does this using builtin * synchronization rather than Sync locks * so might be a useful comparison. * * <dt> Using Channels * <dd> These classes work a little bit differently than the others. * Each test arranges that half of the threads behave as producers, * and half as consumers. Each test iteration puts/takes an RNG object * through a channel before or after executing its update * method. When the number of threads is one, each producer * simply consumers its own object. Some Channels (notably * SynchronousChannels) cannot be used with only one thread, * in which case the test is skipped. * * <dt> Using Executors * <dd> These classes arrange for each RNG update to occur * as an executable command. Each test iteration passes a * command to an Executor, which eventually executes it. * Execution is overlapped: Each iteration starts a new * command, and then waits for the previous command to complete. * * </dl> * * <p> * * The test code is ugly; it has just evolved over the years. Sorry.**/public class SynchronizationTimer { /** Start up this application **/ public static void main(String[] args) { JFrame frame = new JFrame("Times per call in microseconds"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); frame.getContentPane().add(new SynchronizationTimer().mainPanel()); frame.pack(); frame.setVisible(true); } /** * Information about classes to be tested **/ static class TestedClass { final String name; final Class cls; final boolean multipleOK; final boolean singleOK; final Class buffCls; Boolean enabled_ = new Boolean(true); synchronized void setEnabled(Boolean b) { enabled_ = b; } synchronized Boolean getEnabled() { return enabled_; } synchronized void toggleEnabled() { boolean enabled = enabled_.booleanValue(); enabled_ = new Boolean(!enabled); } synchronized boolean isEnabled(int nthreads, Fraction shared) { boolean enabled = enabled_.booleanValue(); if (!enabled) return false; if (!singleOK && nthreads <= 1) return false; if (!multipleOK && nthreads > 1 && shared.compareTo(0) > 0) return false; return true; } TestedClass(String n, Class c, boolean m, boolean sok) { name = n; cls = c; multipleOK = m; singleOK = sok; buffCls = null; } TestedClass(String n, Class c, boolean m, boolean sok, Class bc) { name = n; cls = c; multipleOK = m; singleOK = sok; buffCls = bc; } static final TestedClass dummy = new TestedClass("", null, false, false); static final TestedClass[] classes = { new TestedClass("NoSynchronization", NoSynchRNG.class, false, true), new TestedClass("PublicSynchronization", PublicSynchRNG.class, true, true), new TestedClass("NestedSynchronization", AllSynchRNG.class, true, true), new TestedClass("SDelegated", SDelegatedRNG.class, true, true), new TestedClass("SynchLongUsingSet", SynchLongRNG.class, true, true), new TestedClass("SynchLongUsingCommit", AClongRNG.class, true, true), new TestedClass("Semaphore", SemRNG.class, true, true), new TestedClass("WaiterPrefSemaphore", WpSemRNG.class, true, true), new TestedClass("FIFOSemaphore", FifoRNG.class, true, true), new TestedClass("PrioritySemaphore", PrioritySemRNG.class, true, true), new TestedClass("Mutex", MutexRNG.class, true, true), new TestedClass("ReentrantLock", RlockRNG.class, true, true), new TestedClass("WriterPrefRWLock", WpRWlockRNG.class, true, true), new TestedClass("ReaderPrefRWLock", ReaderPrefRWlockRNG.class, true, true), new TestedClass("FIFORWLock", FIFORWlockRNG.class, true, true), new TestedClass("ReentrantRWL", ReentrantRWlockRNG.class, true, true), new TestedClass("LinkedQueue", ChanRNG.class, true, true, LinkedQueue.class), new TestedClass("WaitFreeQueue", ChanRNG.class, true, true, WaitFreeQueue.class), new TestedClass("BoundedLinkedQueue", ChanRNG.class, true, true, BoundedLinkedQueue.class), new TestedClass("BoundedBuffer", ChanRNG.class, true, true, BoundedBuffer.class), new TestedClass("CondVarBoundedBuffer", ChanRNG.class, true, true, CVBuffer.class), new TestedClass("BoundedPriorityQueue", ChanRNG.class, true, true, BoundedPriorityQueue.class), new TestedClass("Slot", ChanRNG.class, true, true, Slot.class), // new TestedClass("FIFOSlot", ChanRNG.class, true, true, FIFOSlot.class), new TestedClass("SynchronousChannel", ChanRNG.class, true, false, SynchronousChannel.class), new TestedClass("DirectExecutor", DirectExecutorRNG.class, true, true), new TestedClass("SemaphoreLckExecutor", LockedSemRNG.class, true, true), new TestedClass("QueuedExecutor", QueuedExecutorRNG.class, true, true), new TestedClass("ThreadedExecutor", ThreadedExecutorRNG.class, true, true), new TestedClass("PooledExecutor", PooledExecutorRNG.class, true, true), // new TestedClass("Pipe", ChanRNG.class, true, true, PipedChannel.class), }; } // test parameters static final int[] nthreadsChoices = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; static final int BLOCK_MODE = 0; static final int TIMEOUT_MODE = 1; static final int[] syncModes = { BLOCK_MODE, TIMEOUT_MODE, }; // misc formatting utilities static String modeToString(int m) { String sms; if (m == BLOCK_MODE) sms = "block"; else if (m == TIMEOUT_MODE) sms = "timeout"; else sms = "No such mode"; return sms; } static String biasToString(int b) { String sms; if (b < 0) sms = "slower producer"; else if (b == 0) sms = "balanced prod/cons rate"; else if (b > 0) sms = "slower consumer"; else sms = "No such bias"; return sms; } static String p2ToString(int n) { // print power of two String suf = ""; if (n >= 1024) { n = n / 1024; suf = "K"; if (n >= 1024) { n = n / 1024; suf = "M"; } } return n + suf; } static final int PRECISION = 10; // microseconds static String formatTime(long ns, boolean showDecimal) { long intpart = ns / PRECISION; long decpart = ns % PRECISION; if (!showDecimal) { if (decpart >= PRECISION/2) ++intpart; return Long.toString(intpart); } else { String sint = Long.toString(intpart); String sdec = Long.toString(decpart); if (decpart == 0) { int z = PRECISION; while (z > 10) { sdec = "0" + sdec; z /= 10; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -