[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Balking and JVM 1.2 vs. 1.1.5



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 &Oslash;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 &lt;=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) { };
      }
   }
   //}}}  
}
//}}}