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;
}
|