[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Balking and JVM 1.2 vs. 1.1.5
- To: occam-com@xxxxxxxxx
- Subject: Re: Balking and JVM 1.2 vs. 1.1.5
- From: Oyvind Teig <Oyvind.Teig@xxxxxxxxxxxx>
- Date: Mon, 8 Mar 1999 09:09:21 +0100
- Alternate-recipient: Allowed
- X400-mts-identifier: [/PRMD=autronica/ADMD=TELEMAX/C=NO/;8308 99/03/08 09:09]
- X400-originator: Oyvind.Teig@xxxxxxxxxxxx
- X400-received: by mta mail.autronica.no in /PRMD=autronica/ADMD=TELEMAX/C=NO/; Relayed; Mon, 8 Mar 1999 09:09:21 +0100
- X400-recipients: non-disclosure:;
All
{
It seems like the default behaviour of java 1.2 launcher is to do
JIT-compilation. So a loop, including a test is done in about
40ns on a 233 MHz Pentium-II!
Setting JAVA_COMPILER=NONE switches it off, and then there's
no difference between 1.2 and 1.1.5.
} // Talking with myself
By the way, is this the only way to do balking in occam?
It certainly is more readable than the Java version, but
we would have no change to make this run in 40ns per
flashCounter increment! The run method is, in a way, rather
nice - but then it demands preemptive scheduling, in this
case!
PROTOCOL Balking
CASE
startPulsing
stopPulsing
stopIt
:
CHAN OF Balking chan:
CHAN OF INT result:
BOOL running:
BOOL flashingInProgress:
INT flashCounter:
SEQ
running := TRUE
flashingInProgress := TRUE
flashCounter := 0
WHILE running
PRI ALT
chan ? CASE
startPulsing
IF
flashingInProgress
SKIP -- Balk
TRUE
flashingInProgress := TRUE
stopPulsing
flashingInProgress := FALSE
stopIt
SEQ
running := FALSE
result ! flashCounter
flashingInProgress & SKIP
flashCounter := flashCounter + 1
I have attacthed a nicer version of Flasher.java, more readable,
and using typesafe constants.
--
|==================================================================|
| Oyvind Teig oyvind.teig@xxxxxxxxxxxx |
| Navia Maritime AS, division Autronica oyvind.teig@xxxxxxxxxxxx |
| 7005 Trondhem Tel.: +47 73 58 12 68 |
| Norway http://www.autronica.no Fax.: +47 73 91 93 20 |
|==================================================================|
import java.util.Random;
//{{{ Heading
/**
* <h2>An implementation of the Balking Concurrency Pattern</h2>
*
* <pre>
* Written by Øyvind Teig
* Inspired from "Patterns in Java, Volume 1", by Mark Grand
*
* Background
* <a href="Discussions.htm">Discussions.htm</a>
*
* Architecture
*
* o 1 instance of Pulser_thread (which is the Balking example
* proper) is started.
* o 3 instances of Action_thread as STARTER is started.
* o 3 instances of Action_thread as STOPPER is started.
* o All 3 STARTERs repeatedly start flashing in Pulser_thread,
* then they wait randomly with an average of 500ms. This starting will "balk"
* if Pulser_thread is already flashing.
* o All 3 STOPPERs repeatedly stop flashing in Pulser_thread,
* then they wait randomly with an average of 500ms.
* o There are therefore equally many starts and stops - but some of the starts
* will fail balk.
* o We saw that, under Linux, the Kaffe JVM with this program, was active for
* 45% of the time, with more than enough machine resources.
* o When Pulse_thread "flashes" it loops around incrementing a counter.
* </pre>
*
* @version 1.1 8Mar1999
* @version 1.0 5Mar1999 Sent to occam-com for comments
* @author Øyvind Teig, <a href="mailto:oyvind.teig@xxxxxxxxxxxx">oyvind.teig@xxxxxxxxxxxx</a>
*/
//}}}
//{{{ Flasher, contains main
public class Flasher
{
/**
* Flasher main runs the test program for a specified time.
*
* @param argv seconds: number of seconds, a value <=0 is "forever"
*/
public static void main (String argv[])
{
if (argv.length != 1)
{
//{{{ Print usage message
System.out.println ("\nFlasher - an example of the \"Balking\" Concurrency Pattern");
System.out.println ("8Mar1999, oyvind.teig@xxxxxxxxxxxx");
System.out.println ("Inspired by Mark Grand, \"Patterns in Java\", Vol.1\n");
System.err.println ("Usage:");
System.err.println (" java Flasher <seconds to run>");
System.err.println (" Negative or zero <seconds to run> is 'forever'\n");
//}}}
}
else
{
//{{{ Run main
Integer arg0 = new Integer(argv[0]);
long seconds;
try {arg0 = arg0.valueOf(argv[0]);} catch (NumberFormatException e) {};
seconds = arg0.longValue();
if (seconds <= 0)
{
//{{{ Inform that it will run forever
System.out.println ("\nWill run forever, hit Ctrl-C to stop\n");
try {Thread.sleep(4*1000);} catch (InterruptedException e) {};
//}}}
}
System.out.println ("");
Pulser_thread pulser = new Pulser_thread ();
Action_thread starter_1 = new Action_thread ("Starter 1 ", pulser, Mode.STARTER, Time.Interval_ms);
Action_thread starter_2 = new Action_thread ("Starter 2 ", pulser, Mode.STARTER, Time.Interval_ms);
Action_thread starter_3 = new Action_thread ("Starter 3 ", pulser, Mode.STARTER, Time.Interval_ms);
Action_thread stopper_A = new Action_thread ("Stopper A ", pulser, Mode.STOPPER, Time.Interval_ms);
Action_thread stopper_B = new Action_thread ("Stopper B ", pulser, Mode.STOPPER, Time.Interval_ms);
Action_thread stopper_C = new Action_thread ("Stopper C ", pulser, Mode.STOPPER, Time.Interval_ms);
if (seconds > 0)
{
//{{{ Stop threads and print results
long ms = seconds * 1000;
try { Thread.sleep(ms); } catch (InterruptedException e) { };
starter_1.stopIt();
starter_2.stopIt();
starter_3.stopIt();
stopper_A.stopIt();
stopper_B.stopIt();
stopper_C.stopIt();
{
float timeAccum_ms = (float) pulser.get_timeAccum_ms();
long pulserCounter = pulser.stopIt();
float dutyCycle = timeAccum_ms / (float)ms; // 0..1
float timePerInc_ns = (timeAccum_ms / (float)pulserCounter) * 1000000;
//
System.out.println ("\nGracefully terminated after " + seconds + " seconds");
System.out.println ("1 Pulser, 3 Starter and 3 Stopper threads were running");
System.out.println (timePerInc_ns + " ns per pulserCounter increment (normalized to dutyCycle 1.0)");
System.out.println ("Duty cycle: " + dutyCycle + "\n");
}
//}}}
}
//}}}
}
}
}
//}}}
//{{{ Time
/**
* Time constants
* Is must be final!
*/
final class Time
{
public final static long Interval_ms = 1000;
}
//}}}
//{{{ Mode
/**
* Mode may be STARTER of STOPPER.
* Is must be final!
*/
final class Mode
{
public final static Mode STARTER = new Mode();
public final static Mode STOPPER = new Mode();
public final static long Interval_ms = 1000;
}
//}}}
//{{{ Pulser_thread
/**
* This class gives an example of a method that may balk.
*/
class Pulser_thread extends Thread
{
// Internal state
private boolean running = true; // To stop correctly
private boolean flashingInProgress = false; // Balks as a consequence of this
private long flashCounter = 0; // Flashing _is_ incrementing this
// Just to measure and study, no functional function:
private long balkCounter = 0;
private long notifyCounter = 0;
private long stopCounter = 0;
private long timeAccum_ms = 0;
//{{{ Constructor
public Pulser_thread()
{
this.start();
}
//}}}
//{{{ start_pulsing and stop_pulsing
public synchronized void start_pulsing (String name)
{
if (flashingInProgress == true)
{
balkCounter++;
System.out.println (name + "balkCounter= " + balkCounter);
}
else
{
flashingInProgress = true;
this.notify();
notifyCounter++;
System.out.println (name + " notifyCounter= " + notifyCounter);
}
}
public synchronized void stop_pulsing (String name)
{
flashingInProgress = false;
stopCounter++;
System.out.println (name + " stopCounter= " + stopCounter);
}
//}}}
//{{{ stopIt
/**
* I have called the stop method "stopIt" so that I can compile this code
* under Java 1.2 as well where Thread.stop has been deprecated and therefore
* cannot be overridden. The only way to stop a thread now is to do it
* gracefully from inside. We first notify the run method so that it will awake
* should it wait. The we clear running, which will cause the run-method's
* while-loop to terminate.
*
* @return flashCounter, we want to have this value as "atomic" as possible,
* that's why we haven't made a separate getflashCounter method.
*/
public synchronized long stopIt()
{
this.notify();
running = false;
return (flashCounter);
}
//}}}
//{{{ get_timeAccum_ms
public synchronized long get_timeAccum_ms()
{
return (timeAccum_ms);
}
//}}}
//{{{ run
/**
* This is the thread body, so to say.
* It loops around in its while-loop as long as running is true. If it flashes,
* the flashCounter is incremented. If, however, flashingInProgress is false,
* it will wait until start_pulsing notify it. Observe that both
* wait and signal must be wrapped up in a synchronized statement, so
* that the parties get ownership of their own monitor before they use it.
* Observe that the loop that increments flashCounter IS DEPENDENT ON
* PREEMPTIVE SCHEDULING! We really ought to have some communication
* in that loop!
*/
public void run()
{
long timePre_ms; // To measure time
synchronized (this)
{
try { wait(); } catch (InterruptedException e) { };
timePre_ms = System.currentTimeMillis(); // Init at first flash
}
while (running)
{
if (flashingInProgress == true)
{
flashCounter++; // This is per definition the "flashing"
}
else
{
synchronized (this)
{
// Flashing going off
timeAccum_ms = timeAccum_ms + (System.currentTimeMillis() - timePre_ms);
try { wait(); } catch (InterruptedException e) { };
// Flashing going on
timePre_ms = System.currentTimeMillis();
}
}
}
}
//}}}
}
//}}}
//{{{ Action_thread
/**
* Action_thread either starts or stops its pulser server.
*
* If it a pulser, it may balk. Stopping a pulser never causes balking.
*/
class Action_thread extends Thread
{
private boolean running = true;
private String name;
private Pulser_thread pulser;
private Random ran = new Random();
private long time_ms;
private Mode action;
//{{{ Constructor
public Action_thread (String name, Pulser_thread pulser, Mode action, long time_ms)
{
this.name = name;
this.pulser = pulser;
this.action = action;
this.time_ms = time_ms;
start();
}
//}}}
//{{{ stopIt
public synchronized void stopIt()
{
running = false;
}
//}}}
//{{{ run
public void run()
{
while (running)
{
if (action == Mode.STARTER)
{
pulser.start_pulsing (name);
}
else
if (action == Mode.STOPPER)
{
pulser.stop_pulsing (name);
}
long randomTime_ms = (long) (ran.nextFloat() * time_ms);
try { Thread.sleep(randomTime_ms); } catch (InterruptedException e) { };
}
}
//}}}
}
//}}}