- public class SynchronizationTimer
- extends java.lang.Object
This program records times for various fine-grained synchronization
schemes, and provides some ways of measuring them over different
- javac -d base of some CLASSPATH *.java
You'll need Swing (JFC). (This
program currently imports the javax.swing versions.
You can edit imports to instead use other versions.)
- java EDU.oswego.cs.dl.util.concurrent.misc.SynchronizationTimer
- Click start.
Clicking stop cancels the run. Cancellation can take
a while when there are a lot of threads.
- For more explanation about tested classes, see
Documentation for util.concurrent
Synchronization schemes are tested around implementations and
RNG, 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
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 NOT included in these times.
In tests with many threads, construction and other bookkeeping
can take longer than the tests themselves.
Results are listed in a table, and optionally printed on standard output.
You can redirect standard output to save to a file.
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).
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.
This program cannot
tell you how busy your computer is while running tests.
You can run a utility program (for
top on unix)
alongside this program
to find out.
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.
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.)
- Number of threads
- Controls concurrency. The indicated number of threads are
started simultaneously and then waited out.
- 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.)
- You can choose to only test the indicated classes. You can
probably figure out how to add more classes to run yourself.
- Calls per thread per test
- 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
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
- Computations per call
- 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.
- Iterations per barrier.
- 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.
- Threads per barrier
- 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.
- Lock mode
- 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.
- Producer mode
- For classes that support it, this controls whether producers
perform blocking puts versus loops repeatedly calling offer.
- Consumer mode
- For classes that support it, this controls whether consumers
perform blocking takes versus loops repeatedly calling poll.
- Specifies the duration of timeouts used in timeout mode. A
value of zero results in pure spin-loops.
- Producer/consumer rates.
- 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.
- Buffer capacity
- For tests involving finite capacity
buffers, this controls maximum buffer size.
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:
- Using built-in synchronization
- 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.
Sync classes as locks
- 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.
- Using Channels
- 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.
- Using Executors
- 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.
The test code is ugly; it has just evolved over the years. Sorry.
Start up this application
|Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
public static void main(java.lang.String args)
- Start up this application