home | OO Richards Bench

Nice #74

Register values v1 v2 are held in Task classes, which implement scheduler function fn to match interface ISchedulerTask.

Nice language Nice version 0.9.8 Nice language using Sun JVM

package bench;
import java.io.*;


let boolean traceOn = false;

void main(String[] args) {
   let count = toSingleInt(args);

   // Timing
   let startTicks = System.currentTimeMillis();
   
   let s = new Scheduler();
   var wkq = NoPacket;

   s.addIdleTask(id: Idle, priority: 0, wkq: NoPacket, count);

   wkq = new Packet(link: NoPacket, id: Worker, kind: Work);
   wkq = new Packet(link: wkq, id: Worker, kind: Work);
   s.addWorkerTask(id: Worker, priority: 1000, wkq);

   wkq = new Packet(link: NoPacket, id: DeviceA, kind: Device);
   wkq = new Packet(link: wkq, id: DeviceA, kind: Device);
   wkq = new Packet(link: wkq, id: DeviceA, kind: Device);
   s.addHandlerTask(id: HandlerA, priority: 2000, wkq);

   wkq = new Packet(link: NoPacket, id: DeviceB, kind: Device);
   wkq = new Packet(link: wkq, id: DeviceB, kind: Device);
   wkq = new Packet(link: wkq, id: DeviceB, kind: Device);
   s.addHandlerTask(id: HandlerB, priority: 3000, wkq);

   s.addDeviceTask(id: DeviceA, priority: 4000, wkq: NoPacket);
   s.addDeviceTask(id: DeviceB, priority: 5000, wkq: NoPacket);

   s.schedule();

   // Timing
   let stopTicks = System.currentTimeMillis();
   let frequency = 1000;

   try {
      let f = new FileOutputStream("testrun-times.xml", true);
      let pw = new PrintWriter(f);
      pw.println("<ExternalStat>");
      pw.println("<size>" + count + "</size>");
      pw.println("<ticks>" + (stopTicks - startTicks) + "</ticks>");
      pw.println("<ticksPerSecond>" + frequency + "</ticksPerSecond>");
      pw.println("</ExternalStat>");
      pw.close();
      }
   catch (FileNotFoundException e) { println(e.getMessage()); }

   println("QueueCount = " + s.queueCount);
   println("HoldCount = " + s.holdCount);
}



var int layout = 0;

void trace(char aChar){
   --layout;
   if (layout <= 0){
      println("");
      layout = 50;
   }
   print(aChar);
}


int toSingleInt(String[] s){
   try { return Integer.parseInt(s[0]); }
   catch (Exception e){ return 10000; } }




interface ISchedulerTask {
   Tcb run(Packet packet);
}


class IdleTask implements ISchedulerTask {
   int v1;
   int v2;
   Scheduler scheduler;

   run(packet) {
      v2--;
      if (v2 == 0)
      return scheduler.holdCurrent;

      if ( ( v1 & 1) == 0 )
         {
            v1 = v1 >> 1;
            return scheduler.release(DeviceA);
         }
      else
         {
            v1 = (v1 >> 1 ) ^ 0xD008 ;
            return scheduler.release(DeviceB);
         }
   }

}


class WorkerTask implements ISchedulerTask {
   PacketId v1;
   int v2;
   Scheduler scheduler;

   run(packet) {
      if (packet == NoPacket)
      {
         return scheduler.suspendCurrent;
      }
      else
      {
         if (v1 == HandlerA)
            v1 = HandlerB;
         else
            v1 = HandlerA;

         packet.setId( v1 );
         packet.setA1( (byte)(0) );

         for (int i=0; i < DataSize; i++)
         {
            v2++;
            if (v2 > 26) v2 = 1;
            packet.getA2[i] = byte(int('A') + v2 - 1);
         }
         return scheduler.queue(packet);
      }
   }
}


class HandlerTask implements ISchedulerTask {
   Packet v1;
   Packet v2;
   Scheduler scheduler;

   run(packet){
      if (packet != NoPacket)
      {
         if (packet.getKind == Work)
            v1 = packet.addTo(queue: v1);
         else
            v2 = packet.addTo(queue: v2);
      }
      if (v1 != NoPacket)
      {
         byte count = v1.getA1;
         Packet v;
         if (count < DataSize )
         {
            if (v2 != NoPacket )
            {
               v = v2;
               v2 = v2.getLink;
               v.setA1( v1.getA2[count] );
               v1.setA1( (byte)(count + 1) );
               return scheduler.queue(packet: v);
            }
         }
         else
         {
            v = v1;
            v1 = v1.getLink;
            return scheduler.queue(v);
         }
      }
      return scheduler.suspendCurrent;
   }
}


class DeviceTask implements ISchedulerTask {
   Packet v1;
   Scheduler scheduler;

   run(packet){
      if (packet == NoPacket)
      {
         if (v1 == NoPacket)
            return scheduler.suspendCurrent;
         Packet v = v1;
         v1 = NoPacket;
         return scheduler.queue(v);
      }
      else
      {
         v1 = packet;
         //if (traceOn) trace( (char)(packet.getA1) );
         return scheduler.holdCurrent;
      }
   }
}



let Tcb NoTcb = new Tcb(link: NoTcb, id: Idle, pri: 0, wkq: NoPacket);

// Named bit masks to access 3 bit state value.
let int RUNNING = 0;
let int RUNNABLE = 1;
let int SUSPENDED = 2;
let int HELD = 4;
let int SUSPENDED_RUNNABLE = SUSPENDED | RUNNABLE;
let int NOT_HELD = ~HELD;


class Tcb {

// initializer
   {   
      if (wkq != NoPacket) state = SUSPENDED_RUNNABLE;
   }

   // Variables from spec
   private Tcb link;     // pointer to another tcb
   private PacketId id;  // identifier (a small integer)
   private int pri;      // priority (a positive integer)
   private Packet wkq;   // list of Packets in the tasks work queue
   private int state = SUSPENDED;  // a 3 bit value giving the state
   private ?ISchedulerTask task = null;


   Tcb getLink() = link;

   PacketId getId() = id;

   int getPriority() = pri;


   Tcb checkPriorityAdd(Tcb task, Packet packet) {
      if (wkq == NoPacket ) {
         wkq = packet;
         state = state | RUNNABLE;
         if (pri > task.getPriority) { return this; }
      }
      else {
         wkq = packet.addTo(queue: wkq);
      }
      return task;
   }


   Tcb run(){
      Packet packet;
      if (state == SUSPENDED_RUNNABLE) {
         packet = wkq;
         wkq = packet.getLink;
         if (wkq == NoPacket )
            state = RUNNING; 
         else
            state = RUNNABLE; 
      }
      else {
         packet = NoPacket;
      }
      return (notNull(task)).run(packet);
   }


   void setRunning() = 
      state = 0;

   void suspended() =
      state = state | SUSPENDED;

   void held() =
      state = state | HELD;
      
   void notHeld() =
      state = state & NOT_HELD;

   boolean isHeldOrSuspended() = 
      (state & HELD) != 0 || (state == SUSPENDED);
}




let int MaxTasks = 6;

class Scheduler {
   private Tcb[] table = new Tcb[MaxTasks].fill(int index => NoTcb);
   private Tcb list = NoTcb;
   private Tcb currentTcb = NoTcb;
   private PacketId currentId = Idle;

   public int queueCount = 0;
   public int holdCount = 0;


   void addIdleTask(PacketId id, int priority, Packet wkq, int count) {
      this.addRunningTask(
         id,
         priority,
         wkq,
         new IdleTask(scheduler: this, v1: 1, v2: count)
      );
   }


   void addWorkerTask(PacketId id, int priority, Packet wkq) {
      this.addTask(
         id,
         priority,
         wkq,
         new WorkerTask(scheduler: this, v1: HandlerA, v2: 0)
      );
   }


   void addHandlerTask(PacketId id, int priority, Packet wkq) {
      this.addTask(
         id,
         priority,
         wkq,
         new HandlerTask(scheduler: this, v1: NoPacket, v2: NoPacket)
      );
   }


   void addDeviceTask(PacketId id, int priority, Packet wkq) {
      this.addTask(
         id,
         priority,
         wkq,
         new DeviceTask(scheduler: this, v1: NoPacket)
      );
   }


   private void addTask(PacketId id, int priority, 
         Packet wkq, ISchedulerTask task) {
      currentTcb = new Tcb(link: list, id: id, pri: priority,
         wkq: wkq, task: task);
      list = currentTcb;
      table[id.hashCode] = currentTcb;
   }


   private void addRunningTask(PacketId id, int priority, 
         Packet wkq, ISchedulerTask task) {
      this.addTask(id, priority, wkq, task);
      currentTcb.setRunning;
   }


   void schedule(){
      currentTcb = list;
      while (currentTcb != NoTcb) {
         if (currentTcb.isHeldOrSuspended())
            currentTcb = currentTcb.getLink;
         else {
            currentId = currentTcb.getId;
            //if (traceOn) trace( char(int('0') + currentId.hashCode + 1));
            currentTcb = currentTcb.run;
         }
      }
   }


   private Tcb queue(Packet packet) {
      let t = table[packet.getId.hashCode];
      if (t == NoTcb) return t;
      queueCount++;
      packet.setLink(NoPacket);
      packet.setId(currentId);
      return t.checkPriorityAdd(currentTcb, packet);
   }


   private Tcb release(PacketId id){
      let t = table[id.hashCode];
      if (t == NoTcb) return t;
      t.notHeld();
      if (t.getPriority > currentTcb.getPriority)
         return t;
      else
         return currentTcb;
   }


   private Tcb holdCurrent(){
      ++holdCount;
      currentTcb.held();
      return currentTcb.getLink;
   }


   private Tcb suspendCurrent() {
      currentTcb.suspended();
      return currentTcb;
   }
}




let Packet NoPacket = new Packet();
let int DataSize = 4;

enum PacketKind { Device, Work }
enum PacketId { Idle, Worker, HandlerA, HandlerB, DeviceA, DeviceB }

class Packet {
      // Variables from spec
   private Packet link = NoPacket;   // pointer to the next Packet
   private PacketId id = Idle;	    // task or device that sent the packet
   private PacketKind kind = Device; // part of the message
   private byte a1 = 0;	             // part of the message
   private byte[] a2 = new byte[DataSize];


   Packet addTo(Packet queue) {
      Packet next, peek;
      link = NoPacket;
      if (queue == NoPacket) return this;
      next = queue;
      while ((peek = next.link) != NoPacket)
         next = peek;
      next.link = this;
      return queue;
   }

   Packet getLink() = link;

   void setLink(Packet p) = 
      link = p;

   PacketId getId() = id;

   void setId(PacketId i) = 
      id = i;

   PacketKind getKind() = kind;

   byte getA1() = a1;

   void setA1(byte a) = 
      a1 = a;

   byte[] getA2() = a2;
}

Valid XHTML 1.0!