import java.io.*;
final class TestRun {
static final boolean traceOn = false;
static int layout = 0;
public static void main(String[] args) {
int count = 10000;
if (args.length > 0)
count = Integer.parseInt(args[0]);
// Timing
long startTicks, stopTicks, frequency;
startTicks = System.currentTimeMillis();
Scheduler s = new Scheduler(traceOn);
Packet wkq;
s.addIdleTask(Scheduler.IDLE, 0, null, count);
wkq = new Packet(null, Scheduler.WORKER, Packet.WORK_KIND);
wkq = new Packet(wkq, Scheduler.WORKER, Packet.WORK_KIND);
s.addWorkerTask(Scheduler.WORKER, 1000, wkq);
wkq = new Packet(null, Scheduler.DEVICEA, Packet.DEVICE_KIND);
wkq = new Packet(wkq, Scheduler.DEVICEA, Packet.DEVICE_KIND);
wkq = new Packet(wkq, Scheduler.DEVICEA, Packet.DEVICE_KIND);
s.addHandlerTask(Scheduler.HANDLERA, 2000, wkq);
wkq = new Packet(null, Scheduler.DEVICEB, Packet.DEVICE_KIND);
wkq = new Packet(wkq, Scheduler.DEVICEB, Packet.DEVICE_KIND);
wkq = new Packet(wkq, Scheduler.DEVICEB, Packet.DEVICE_KIND);
s.addHandlerTask(Scheduler.HANDLERB, 3000, wkq);
s.addDeviceTask(Scheduler.DEVICEA, 4000, null);
s.addDeviceTask(Scheduler.DEVICEB, 5000, null);
s.schedule();
// Timing
stopTicks = System.currentTimeMillis();
frequency = 1000;
// Timing
try {
FileOutputStream f = new FileOutputStream("testrun-times.xml", true);
PrintWriter 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) {System.out.println(e.getMessage()); }
System.out.println("QueueCount = " + s.queueCount);
System.out.println("HoldCount = " + s.holdCount);
}
static final void trace(char aChar){
--layout;
if (layout <= 0)
{
System.out.println("");
layout = 50;
}
System.out.print(aChar);
}
}
final class Scheduler {
private Tcb[] table = new Tcb[MAXTASKS];
private Tcb list = null;
private Tcb currentTcb;
private int currentId;
int queueCount = 0;
int holdCount = 0;
boolean traceOn = false;
final static int IDLE = 0;
final static int WORKER = 1;
final static int HANDLERA = 2;
final static int HANDLERB = 3;
final static int DEVICEA = 4;
final static int DEVICEB = 5;
final static int MAXTASKS = 6;
Scheduler(boolean trace)
{
traceOn = trace;
}
void addIdleTask(int anId, int aPriority,
Packet aWorkQueue, int aCount)
{
addRunningTask(
anId,
aPriority,
aWorkQueue,
(ISchedulerTask)(new IdleTask(this, 1, aCount))
);
}
void addWorkerTask(int anId, int aPriority, Packet aWorkQueue)
{
addTask(
anId,
aPriority,
aWorkQueue,
(ISchedulerTask)(new WorkerTask(this, HANDLERA, 0))
);
}
void addHandlerTask(int anId, int aPriority, Packet aWorkQueue)
{
addTask(
anId,
aPriority,
aWorkQueue,
(ISchedulerTask)(new HandlerTask(this))
);
}
void addDeviceTask(int anId, int aPriority, Packet aWorkQueue)
{
addTask(
anId,
aPriority,
aWorkQueue,
(ISchedulerTask)(new DeviceTask(this))
);
}
private void addTask(int anId, int aPriority,
Packet aWorkQueue, ISchedulerTask aTask)
// See addRunningTask before making changes
{
currentTcb = new Tcb(list, anId, aPriority, aWorkQueue, aTask);
list = currentTcb;
table[anId] = currentTcb;
}
private void addRunningTask(int anId, int aPriority,
Packet aWorkQueue, ISchedulerTask aTask)
{
addTask(anId, aPriority, aWorkQueue, aTask);
currentTcb.setRunning();
}
void schedule()
{
currentTcb = list;
while (currentTcb != null)
{
if (currentTcb.isHeldOrSuspended())
currentTcb = currentTcb.getLink();
else
{
currentId = currentTcb.getId();
//if (traceOn) TestRun.trace((char)('0' + currentId + 1));
currentTcb = currentTcb.run();
}
}
}
Tcb queue(Packet aPacket)
{
Tcb t = table[aPacket.getId()];
if (t == null) return t;
queueCount++;
aPacket.setLink(null);
aPacket.setId(currentId);
return t.checkPriorityAdd(currentTcb, aPacket);
}
Tcb release(int anId)
{
Tcb t = table[anId];
if (t == null) return t;
t.notHeld();
if (t.getPriority() > currentTcb.getPriority())
return t;
else
return currentTcb;
}
Tcb holdCurrent()
{
++holdCount;
currentTcb.held();
return currentTcb.getLink();
}
Tcb suspendCurrent()
{
currentTcb.suspended();
return currentTcb;
}
}
interface ISchedulerTask {
Tcb run(Packet aPacket);
}
final class IdleTask implements ISchedulerTask {
int v1, v2;
Scheduler s;
public IdleTask(Scheduler aScheduler, int value1, int value2){
v1 = value1;
v2 = value2;
s = aScheduler;
}
public Tcb run(Packet aPacket){
v2--;
if (v2 == 0)
return s.holdCurrent();
if ( ( v1 & 1) == 0 )
{
v1 = v1 >> 1;
return s.release(Scheduler.DEVICEA);
}
else
{
v1 = (v1 >> 1 ) ^ 0xD008 ;
return s.release(Scheduler.DEVICEB);
}
}
}
final class WorkerTask implements ISchedulerTask {
int v1, v2;
Scheduler s;
public WorkerTask(Scheduler aScheduler, int value1, int value2){
v1 = value1;
v2 = value2;
s = aScheduler;
}
public Tcb run(Packet aPacket){
if (aPacket == null)
{
return s.suspendCurrent();
}
else
{
if (v1 == Scheduler.HANDLERA)
v1 = Scheduler.HANDLERB;
else
v1 = Scheduler.HANDLERA;
aPacket.setId( v1 );
aPacket.setA1( (byte)0 );
for (int i=0; i < Packet.DATA_SIZE; i++)
{
v2++;
if (v2 > 26) v2 = 1;
aPacket.getA2()[i] = (byte)('A' + v2 - 1);
}
return s.queue(aPacket);
}
}
}
final class HandlerTask implements ISchedulerTask {
Packet v1, v2;
Scheduler s;
public HandlerTask(Scheduler aScheduler){
s = aScheduler;
}
public Tcb run(Packet aPacket){
if (aPacket != null)
{
if (aPacket.getKind() == Packet.WORK_KIND)
v1 = aPacket.addTo(v1);
else
v2 = aPacket.addTo(v2);
}
if (v1 != null)
{
byte count = v1.getA1();
Packet v;
if (count < Packet.DATA_SIZE )
{
if (v2 != null )
{
v = v2;
v2 = v2.getLink();
v.setA1( v1.getA2()[count] );
v1.setA1( (byte)(count + 1) );
return s.queue(v);
}
}
else
{
v = v1;
v1 = v1.getLink();
return s.queue(v);
}
}
return s.suspendCurrent();
}
}
final class DeviceTask implements ISchedulerTask {
Packet v1;
Scheduler s;
public DeviceTask(Scheduler aScheduler){
s = aScheduler;
}
public Tcb run(Packet aPacket){
if (aPacket == null)
{
if (v1 == null)
return s.suspendCurrent();
Packet v = v1;
v1 = null;
return s.queue(v);
}
else
{
v1 = aPacket;
//if (s.traceOn) TestRun.trace( (char)(aPacket.getA1()) );
return s.holdCurrent();
}
}
}
final class Tcb {
// Variables from spec
private Tcb link;
private int id;
private int pri;
private Packet wkq;
private int state;
private ISchedulerTask task;
Tcb(Tcb aTcb, int anId, int aPriority,
Packet aWorkQueue, ISchedulerTask aTask
)
{
link = aTcb;
id = anId;
pri = aPriority;
wkq = aWorkQueue;
task = aTask;
if (wkq == null)
state = SUSPENDED;
else
state = SUSPENDED_RUNNABLE;
}
Tcb getLink(){
return link;
}
int getId(){
return id;
}
int getPriority(){
return pri;
}
Tcb checkPriorityAdd(Tcb aTask, Packet aPacket)
{
if (wkq == null )
{
wkq = aPacket;
state = state | RUNNABLE;
if (pri > aTask.getPriority()) { return this; }
}
else
{
wkq = aPacket.addTo(wkq);
}
return aTask;
}
Tcb run()
{
Packet packet;
if (state == SUSPENDED_RUNNABLE)
{
packet = wkq;
wkq = packet.getLink();
if (wkq == null)
state = RUNNING;
else
state = RUNNABLE;
}
else
{
packet = null;
}
return task.run(packet);
}
// Named bit masks to access 3 bit state value.
static final int RUNNING = 0;
static final int RUNNABLE = 1;
static final int SUSPENDED = 2;
static final int HELD = 4;
static final int SUSPENDED_RUNNABLE = SUSPENDED | RUNNABLE;
static final int NOT_HELD = ~HELD;
void setRunning()
{
state = RUNNING;
}
void suspended(){
state = state | SUSPENDED;
}
void held(){
state = state | HELD;
}
void notHeld(){
state = state & NOT_HELD;
}
boolean isHeldOrSuspended(){
return (state & HELD) != 0 || (state == SUSPENDED);
}
}
final class Packet {
final static int DATA_SIZE = 4;
// Variables from spec
private Packet link;
private int id;
private int kind;
private byte a1 = 0;
private byte[] a2 = new byte[DATA_SIZE];
final static int DEVICE_KIND = 0;
final static int WORK_KIND = 1;
Packet(Packet aLink, int anId, int aKind)
{
link = aLink;
id = anId;
kind = aKind;
}
Packet addTo(Packet aQueue)
{
Packet next, peek;
link = null;
if (aQueue == null) return this;
next = aQueue;
while ((peek = next.link) != null)
next = peek;
next.link = this;
return aQueue;
}
Packet getLink(){
return link;
}
void setLink(Packet aPacket){
link = aPacket;
}
int getId(){
return id;
}
void setId(int anId){
id = anId;
}
int getKind(){
return kind;
}
byte getA1(){
return a1;
}
void setA1(byte aByte){
a1 = aByte;
}
byte[] getA2(){
return a2;
}
}
|