Google
 

Trailing-Edge - PDP-10 Archives - decus_20tap4_198111 - decus/20-0107/tops.sim
There are 2 other files named tops.sim in the archive. Click here to see a list.
SIMULATION

BEGIN
INTEGER MAXJOB;
REAL SWAPLATENCY,SWAPRATE,PROT0,PROT1,FREECORE, TOTUSERCORE;
REAL NRBUFFERS, COMPQUANT, IOQUANT, INITIALQUANT;

INTEGER BLKSPERCYL, BLKSPERTRACK, NRCYL, DISKSIZE, TRACKSPERCYL;
REAL BLKSPERSEC, SEEKSTART, SEEKCYL;
INTEGER NRCHAN, DRIVESPERKON, KONPERCHAN, NRDRIVES;
REAL OVERHD0,OVERHD1;
INTEGER VERSION;



REF(INFILE) PAR;
TEXT PARBUF;
TEXT P, PARNAME;

REF (OUTFILE) O, RSLTS;
TEXT OBUF, ONAME, RSLTSBUF, RSLTSNAME;



PROCEDURE PARERR;
BEGIN
OUTTEXT ("ERR READING SIMULATION PARAMETERS");
OUTIMAGE;
OUTTEXT (P);
OUTIMAGE;
GOTO ENDRUN;
END;


VERSION:=1;

OUTTEXT ("PARAMETER FILE? ");
BREAKOUTIMAGE;
INIMAGE;
PARNAME:-INTEXT(20);
PAR:-NEW INFILE(PARNAME);
PARBUF:-BLANKS(80);
PAR.OPEN(PARBUF);


OUTTEXT ("REPORT FILE? ");
BREAKOUTIMAGE;
INIMAGE;
ONAME:-INTEXT(20);
O:-NEW OUTFILE(ONAME);
OBUF:-BLANKS(80);
O.OPEN(OBUF);

OUTTEXT ("DETAILED RESULTS FILE? ");
BREAKOUTIMAGE;
INIMAGE;
RSLTSNAME:-INTEXT(20);
RSLTS:-NEW OUTFILE(RSLTSNAME);
RSLTSBUF:-BLANKS(100);
RSLTS.OPEN(RSLTSBUF);




INSPECT PAR DO

BEGIN


INIMAGE;
P:-INTEXT(15);
IF P = "SWAPLATENCY    " THEN SWAPLATENCY:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "SWAPRATE       " THEN SWAPRATE:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "PROT0          " THEN PROT0:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "PROT1          " THEN PROT1:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "FREECORE       " THEN FREECORE:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "MAXJOB         " THEN MAXJOB:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "NRBUFFERS      " THEN NRBUFFERS:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "COMPQUANT      " THEN COMPQUANT:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "IOQUANT        " THEN IOQUANT:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "INITIALQUANT   " THEN INITIALQUANT:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "NRCYL          " THEN NRCYL:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "TRACKSPERCYL   " THEN TRACKSPERCYL:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "BLKSPERTRACK   " THEN BLKSPERTRACK:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "BLKSPERSEC     " THEN BLKSPERSEC:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "NRCHAN         " THEN NRCHAN:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "KONPERCHAN     " THEN KONPERCHAN:= ININT
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "DRIVESPERKON   " THEN DRIVESPERKON:= ININT
ELSE PARERR;




INIMAGE;
P:-INTEXT(15);
IF P = "OVERHD0        "THEN OVERHD0:= INREAL
ELSE PARERR;


INIMAGE;
P:-INTEXT(15);
IF P = "OVERHD1        " THEN OVERHD1:= INREAL
ELSE PARERR;


CLOSE;

END;

DISKSIZE:=NRCYL * TRACKSPERCYL * BLKSPERTRACK;
BLKSPERCYL:=TRACKSPERCYL * BLKSPERTRACK;
NRDRIVES:=NRCHAN*KONPERCHAN*DRIVESPERKON;
TOTUSERCORE:=FREECORE;
BEGIN

REAL PROCEDURE MIN(A,B); REAL A,B;
MIN:=IF A<B THEN A ELSE B;


REAL PROCEDURE MAX(A,B); REAL A,B;
MAX:=IF A > B THEN A ELSE B;


PROCEDURE EVENT(NR,PAR);  INTEGER NR,PAR;

IF WANTEVTMESG(NR) 
THEN	BEGIN
	OUTTIME (TIME);
	OUTTEXT (EVENTMESG(NR));
	OUTINT (PAR,6);
	OUTIMAGE;
	END;

PROCEDURE OUTTIME (T); REAL T;

BEGIN
REAL HOURS, MINS, SECS;

HOURS:=ENTIER(T/3600);
MINS:=ENTIER((T-HOURS*3600)/60);
SECS:=T-HOURS*3600 - MINS*60;

OUTINT (HOURS,2);
OUTTEXT(":");
OUTINT (MINS,2);
OUTTEXT(":");
OUTFIX (SECS,4,7);
OUTTEXT ("  ");

END;



PROCEDURE SCHEDMESG(J,T); REF(JOB)J; REAL T;

IF WANTEVTMESG(17) THEN
BEGIN
OUTTIME (TIME);
OUTTEXT ("JOB ");
OUTINT(J.I, 3);
OUTTEXT("  RUNS FOR ");
OUTFIX(T,3,5);
OUTIMAGE;
END;
PROCEDURE HISEGMESG (J,H); INTEGER J,H;

IF WANTEVTMESG (25) THEN
	BEGIN
	OUTTIME (TIME);
	OUTTEXT ("JOB ");
	OUTINT (J,3);
	OUTTEXT ("  GETS HISEG ");
	OUTINT (H,6);
	OUTIMAGE;
	END;
PROCEDURE INITEVENTARRAY;

BEGIN
REF(INFILE) EVT;
TEXT EVTBUF;
INTEGER I,EVENTPAR;

EVT:-NEW INFILE("EVENTS");
EVTBUF:-BLANKS(80);
EVT.OPEN (EVTBUF);
EVT.INIMAGE;

I:= 1;
INSPECT EVT DO
WHILE NOT ENDFILE DO
	BEGIN
	EVENTPAR:=ININT;
	WANTEVTMESG(I):= (IF EVENTPAR > 0 THEN TRUE ELSE FALSE);
	EVENTMESG(I):-INTEXT(26);
	I:=I+1;
	INIMAGE;
	END;

EVT.CLOSE;

END ***INITEVENTARRAY***;
PROCEDURE INITHISEGS;

BEGIN
REF (HISEG) H;

HISEGCHAIN:-NEW HEAD;


NULLHISEG:-NEW HISEG(1000);
INSPECT NULLHISEG DO
	BEGIN
	SIZE:=0;
	SGNAME:-COPY("NONE  ");
	INCORE:=TRUE;
	END;


H:-NEW HISEG(1001);
H.SGNAME:-COPY("TECO  ");
H.SWAPPEDSIZE:=H.SIZE:=7;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);

H:-NEW HISEG (1002);
H.SGNAME:-COPY ("PIP   ");
H.SWAPPEDSIZE:=H.SIZE:=9;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);


H:-NEW HISEG (1003);
H.SGNAME:-COPY("SOS   ");
H.SWAPPEDSIZE:=H.SIZE:=15;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);

H:-NEW HISEG (1004);
H.SGNAME:-COPY("EDITS ");
H.SWAPPEDSIZE:=H.SIZE:=15;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);

H:-NEW HISEG (1005);
H.SGNAME:-COPY("DIRECT");
H.SWAPPEDSIZE:=H.SIZE:=19;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);


H:-NEW HISEG (1006);
H.SGNAME:-COPY("BASIC ");
H.SWAPPEDSIZE:=H.SIZE:=25;
H.INCORE:=FALSE;
H.INTO (HISEGCHAIN);



END;
LINK CLASS IOREQ;
BEGIN
PROCEDURE INIT;
	BEGIN
	DRIVENR:=RANDINT(1,NRDRIVES, RANDOMVAR);
	DRIVE:-DRIVELIST(DRIVENR);
	BLK:=RANDINT(1, DISKSIZE, RANDOMVAR);
	CYL:=BLK/BLKSPERCYL;
	SECTOR:=BLK - ENTIER(BLK/BLKSPERTRACK)*BLKSPERTRACK;
	END ***INIT***;



INTEGER DRIVENR, BLK, NRBLKS, CYL, SECTOR;
REF (DISKDRIVE) DRIVE;
REF (IOPROCESS) OWNER;

END ***CLASS IOREQ ***;
PROCESS CLASS DISKDRIVE;
BEGIN
REAL PROCEDURE LATENCY;

BEGIN
REAL T,SECTOR, DIST;

T:=TIME*BLKSPERSEC;
SECTOR:= T - ENTIER(T/BLKSPERTRACK)*BLKSPERTRACK;
DIST:=(IF SECTOR < R.SECTOR THEN R.SECTOR - SECTOR
	ELSE R.SECTOR - SECTOR + BLKSPERTRACK);
LATENCY:=DIST/BLKSPERSEC;

END ***PROCEDURE LATENCY***;



INTEGER NR;
REF (CONTROLLER) MYKON;
REF(CHANNEL) MYCHAN;
BOOLEAN DOINGSEEK, WAITINGXFER, SEARCHING, DOINGXFER;
INTEGER SEEKS, XFERS, BLOCKS;
INTEGER CURCYL, TARGETCYL, DIST, BESTDIST;
REF(HEAD) POSWAITQUEUE;
REF(IOREQ) R, BESTREQ;


POSWAITQUEUE:-NEW HEAD;
WHILE  NOT F.ENDFILE  OR REQSPENDING > 0 DO
BEGIN

IF POSWAITQUEUE.EMPTY OR MYKON.BUSY THEN PASSIVATE
ELSE
BEGIN
R:-POSWAITQUEUE.FIRST;
BESTREQ:-NONE;
BESTDIST:=NRCYL+1;
WHILE NOT R == NONE DO
	BEGIN
	DIST:=ABS(R.CYL - CURCYL);
	IF DIST < BESTDIST
	THEN	BEGIN
		BESTDIST:=DIST;
		BESTREQ:- R;
		END;
	R:-R.SUC;
	END;

R:-BESTREQ;
R.OUT;
TARGETCYL:=R.CYL;

IF BESTDIST > 0 
THEN	BEGIN
	DOINGSEEK:=TRUE;
	EVENT (12,NR);
	HOLD (SEEKSTART + SEEKCYL*BESTDIST);
	DOINGSEEK:=FALSE;
	CURCYL:=TARGETCYL;
	EVENT (13,NR);
	SEEKS:=SEEKS + 1;
	END;

WAITINGXFER:=TRUE;
R.INTO (MYCHAN.XFERWAITQUEUE);
ACTIVATE (MYCHAN) AFTER THIS PROCESS;
PASSIVATE;

XFERS:=XFERS+1;
END;
END ***WHILE  NOT F.ENDFILE ***;

HOLD (100000);

END ***PROCESS DISKDRIVE***;

CLASS CONTROLLER (NRDRIVES);	INTEGER NRDRIVES;

BEGIN
BOOLEAN BUSY;
REF(CHANNEL) MYCHAN;
REF(DISKDRIVE) ARRAY DRIVELIST(1:NRDRIVES);
END;
PROCESS CLASS CHANNEL (NRKON);		INTEGER NRKON;
BEGIN
BOOLEAN SEARCHING, DOINGXFER;
REF(IOREQ) R, BESTREQ;
REF (HEAD) XFERWAITQUEUE;
REF(CONTROLLER) ARRAY KONLIST (1:NRKON);

INTEGER I;
REAL LATENCY, BESTSOFAR;

XFERWAITQUEUE:-NEW HEAD;

WHILE NOT F.ENDFILE OR REQSPENDING > 0  DO
BEGIN

IF XFERWAITQUEUE.EMPTY  THEN PASSIVATE
ELSE
BEGIN

R:-XFERWAITQUEUE.FIRST;
BESTREQ:-NONE;
BESTSOFAR:=1000000;
WHILE NOT R == NONE DO
	BEGIN
	LATENCY:=R.DRIVE.LATENCY;
	IF LATENCY < BESTSOFAR 
	THEN	BEGIN
		BESTSOFAR:=LATENCY;
		BESTREQ:-R;
		END;
	R:-R.SUC;
	END;

R:-BESTREQ;
R.OUT;
LATENCY:=BESTSOFAR;

R.DRIVE.MYKON.BUSY:=TRUE;
R.DRIVE.WAITINGXFER:=FALSE;
R.DRIVE.SEARCHING:=SEARCHING:=TRUE;
R.NRBLKS:=NRBUFFERS - R.OWNER.J.FULLBUFS;
IF R.NRBLKS > R.OWNER.J.BLKSNEEDED  - R.OWNER.J.FULLBUFS
	THEN R.NRBLKS:= R.OWNER.J.BLKSNEEDED - R.OWNER.J.FULLBUFS;
EVENT(14,R.DRIVE.NR);
HOLD (LATENCY);

R.DRIVE.SEARCHING:=SEARCHING:=FALSE;
R.DRIVE.DOINGXFER:=DOINGXFER:=TRUE;
EVENT (8,R.DRIVE.NR);
HOLD (R.NRBLKS/BLKSPERSEC);
R.DRIVE.DOINGXFER:=DOINGXFER:=FALSE;
R.DRIVE.MYKON.BUSY:=FALSE;
R.DRIVE.BLOCKS:=R.DRIVE.BLOCKS +  R.NRBLKS;
EVENT (9,R.DRIVE.NR);
ACTIVATE(R.OWNER);

INSPECT R.DRIVE.MYKON DO
	FOR I:= 1 STEP 1 UNTIL NRDRIVES DO
		ACTIVATE DRIVELIST(I) ;

END;

END ***WHILE STATEMENT***;

HOLD (100000);

END ***CLASS CHANNEL ***;
PROCEDURE INITDISKDATA;

BEGIN
INTEGER I, J, K, DRIVENR, NRKON, NRDRIVES;

REF(CHANNEL)C;
REF(CONTROLLER)KON;
REF(DISKDRIVE)D;

DRIVENR:= 1;
FOR I:= 1 STEP 1 UNTIL NRCHAN DO
	BEGIN
	C:-NEW CHANNEL(KONPERCHAN);
	CHANLIST(I):-C;
	ACTIVATE C;

	NRKON:=C.NRKON;
	FOR J := 1 STEP 1 UNTIL NRKON DO

		BEGIN
		KON:-NEW CONTROLLER(DRIVESPERKON);
		C.KONLIST(J):-KON;
		KON.MYCHAN:-C;

		NRDRIVES:=KON.NRDRIVES;
		FOR K:= 1 STEP 1 UNTIL NRDRIVES DO
			
			BEGIN
			D:- NEW DISKDRIVE;
			KON.DRIVELIST(K):- D;
			D.MYKON:-KON;
			D.MYCHAN:-C;
			D.NR:=DRIVENR;
			DRIVELIST(DRIVENR):-D;
			DRIVENR:=DRIVENR+1;
			ACTIVATE D;
			END;
		END;
	END;

OUTTEXT ("DISK DATA INITED");
OUTIMAGE;

END ***INIT DISKDATA ***;
LINK CLASS REQUEST;

BEGIN
REAL CPUTIME, DISKBLKS,  KCT, THINKTIME;
REAL STARTTIME,SERVICETIME, JOBNR, CORE, TIMEIN;
TEXT PROGRAM;
END;







HEAD CLASS QUEUE;
BEGIN

PROCEDURE UPDATE;
BEGIN
SUM:= SUM + CARDINAL*(TIME - LASTCHANGE);
LASTCHANGE:=TIME;
END;

TEXT QNAME;
REAL LASTCHANGE, SUM;
END;
REF (REQUEST) PROCEDURE NEXTREQ;

BEGIN
REF (REQUEST) REQ;
REQ:-NEW REQUEST;
REQSPENDING:=REQSPENDING + 1;


INSPECT F DO

	BEGIN
	INSPECT REQ DO
		BEGIN
		STARTTIME:=ININT/60;
		THINKTIME:=ININT/60;
		SERVICETIME:=ININT/60;
		INCHAR;
		PROGRAM:-INTEXT(6);
		CORE:=ININT;
		CPUTIME:=ININT/60;
		JOBNR:=ININT;
		DISKBLKS:=ININT;
	
		IF CORE > TOTUSERCORE THEN
			BEGIN
			OUTTEXT ("ERR -- REQ WITH SIZE > TOTAL USER CORE");
			OUTIMAGE;
			OUTTEXT ("CONTINUING WITH SIZE - TOTAL USER CORE ");
			OUTIMAGE;
			CORE:=TOTUSERCORE;
			END;
		
		IF STARTTIME < LASTSTARTTIME
		THEN	BEGIN
			OUTTEXT ("ERR -- INPUT RECORDS OUT OF ORDER");
			OUTIMAGE;
			GOTO ENDRUN;
			END
		ELSE	LASTSTARTTIME:=STARTTIME;

		END;
	INIMAGE;

	END;
NEXTREQ:-REQ;
END;
PROCEDURE ASSIGN(SEG);	REF (SEGMENT) SEG;

BEGIN
REAL INCREASE;

INCREASE:=SEG.SIZE -  SEG.COREASSIGNED;

IF INCREASE > FREECORE THEN
	OUTTEXT ("ERR IN ASSIGN -- SEG TOO LARGE")
	ELSE  FREECORE:=FREECORE - INCREASE;


IF SEG.BEINGSWAPPED THEN
	BEGIN
	OUTTEXT("ERR --SEG ASSIGNED CORE WHILE BEING SWAPPED");
	OUTIMAGE;
	END;

EVENT (20, SEG.I);

SEG.COREASSIGNED:=SEG.SIZE;

END;



PROCEDURE DEASSIGN (SEG);	REF(SEGMENT) SEG;

BEGIN

IF SEG.BEINGSWAPPED THEN
	BEGIN
	OUTTEXT ("ERR -- SEG DEASSIGNED WHILE BEING SWAPPED");
	OUTIMAGE;
	END;

IF SEG.INCORE
THEN	SEG.INCORE:=FALSE

ELSE	BEGIN
	OUTTEXT ("ERR--DEASSING FOR SEG NOT IN CORE");
	OUTIMAGE;
	END;

FREECORE:=FREECORE + SEG.COREASSIGNED;
SEG.COREASSIGNED:=0;

EVENT (21,SEG.I);

END;
PROCESS CLASS SCANNER;
BEGIN
REF (JOB) J;
BOOLEAN RESTART;

PROCEDURE SCANFOR(Q); REF(QUEUE)Q;

IF NOT RESTART THEN
BEGIN
J:-Q.FIRST;

WHILE J =/= NONE AND NOT RESTART DO
	BEGIN
	PASSIVATE;
	J:-J.SUC;
	END;
END ***SCANFOR***;


PROCEDURE SCANBACK (Q); REF(QUEUE) Q;

IF NOT RESTART THEN
BEGIN
J:-Q.LAST;
WHILE J =/= NONE AND NOT RESTART DO
	BEGIN
	PASSIVATE;
	J:-J.PRED;
	END;
END ***SCANBACK***;

END ***CLASS SCANNER ***;
PROCESS CLASS SEGMENT(I);  INTEGER I;
BEGIN
TEXT SGNAME;
REAL SIZE, COREASSIGNED,SWAPPEDSIZE;

BOOLEAN INCORE, BEINGSWAPPED, EXPANDING;
END;


SEGMENT CLASS HISEG;

BEGIN
INTEGER INCORECNT;
BOOLEAN PROCEDURE INSWAPPABLE;
INSWAPPABLE:= NOT INCORE;

BOOLEAN PROCEDURE OUTSWAPPABLE;

BEGIN
OUTSWAPPABLE:=(	IF INCORECNT > 0
		THEN	FALSE
		ELSE	IF COREASSIGNED = 0
			THEN	FALSE
			ELSE	TRUE);

IF SWAPPER.INJOB =/= NONE
THEN	BEGIN
	IF SWAPPER.INJOB.H == THIS HISEG
	THEN	OUTSWAPPABLE:=FALSE;
	END;
END ***OUTSWAPPABLE***;


END ***HISEG***;
SEGMENT CLASS JOB;
BEGIN

BOOLEAN PROCEDURE SWAPWAIT;
SWAPWAIT:=NOT INCORE OR BEINGSWAPPED OR EXPANDING
		OR NOT H.INCORE OR H.BEINGSWAPPED;

BOOLEAN PROCEDURE RUNNABLE;
RUNNABLE:= INCORE AND NOT BEINGSWAPPED AND NOT EXPANDING
		AND NOT IOWAIT
		AND H.INCORE AND NOT H.BEINGSWAPPED;



BOOLEAN PROCEDURE INSWAPPABLE;

INSWAPPABLE:=NOT INCORE OR EXPANDING OR NOT H.INCORE;

BOOLEAN PROCEDURE OUTSWAPPABLE;

OUTSWAPPABLE:= ( IF NOT INCORE  THEN FALSE
		ELSE IF BEINGSWAPPED THEN FALSE
		ELSE IF PROTECTTIME > TIME THEN FALSE
		ELSE TRUE);


PROCEDURE MYHISEG;

BEGIN
REF (HISEG) H1;

H:-NULLHISEG;

H1:-HISEGCHAIN.FIRST;

WHILE H1 =/= NONE DO
	BEGIN
	IF H1.SGNAME = R.PROGRAM THEN
		BEGIN
		H:-H1;
		H1:-NONE;
		END
	ELSE H1:-H1.SUC;
	END ***WHILE H1=/=NONE;


END ***MYHISEG***;
PROCEDURE MYNEXTREQ;

BEGIN
NEXTREQTIME:=0;

INSPECT R DO NEXTREQTIME:=STARTTIME + THINKTIME + SERVICETIME;


WHILE REQSTACK(I).EMPTY AND NOT F.ENDFILE  AND
	(IF R =/= NONE THEN R.STARTTIME <  NEXTREQTIME  + 10 ELSE TRUE )DO
	BEGIN
	R:-NEXTREQ;

	IF JOBLIST(R.JOBNR).STARTED
	THEN	R.INTO(REQSTACK (R.JOBNR))

	ELSE	BEGIN
		OUTTEXT ("ERR -- REQ FOR JOB THAT WAS NOT STARTED");
		OUTIMAGE;
		OUTTEXT ("DURING JOB INITIALIZATION");
		OUTIMAGE;
		OUTTEXT ("RECORDS OUT OF ORDER ?");
		OUTIMAGE;
		OUTTEXT ("CONTINUING  -- THAT REQ IGNORED");
		REQSPENDING:=REQSPENDING - 1;
		END;

	END;

R:-REQSTACK(I).FIRST;

IF R == NONE THEN EVENT(28,I)
ELSE
BEGIN

R.OUT;
HOLD (R.THINKTIME);
EVENT (18,I);


R.TIMEIN:=TIME;

WHILE BEINGSWAPPED DO HOLD (.1);



IF MYQUEUE =/= STOPQ THEN
	BEGIN
	OUTTEXT ("ERR -- REQ FOR JOB NOT IN STOP Q");
	OUTIMAGE;
	END;

IF R.PROGRAM = SGNAME
THEN	BEGIN
	SIZE:=R.CORE - H.SIZE;
	IF SIZE < 1 THEN SIZE:=1;

	IF INCORE
	THEN	BEGIN
		IF COREASSIGNED < SIZE
		THEN	BEGIN
			IF FREECORE < SIZE - COREASSIGNED
			THEN	EXPANDING:=TRUE
			ELSE	ASSIGN (THIS SEGMENT);
			END;
		IF COREASSIGNED > SIZE THEN ASSIGN (THIS SEGMENT);
		END

	ELSE	IF SIZE < SWAPPEDSIZE THEN SWAPPEDSIZE:=SIZE;
	END

ELSE	BEGIN
	IF INCORE
	THEN	BEGIN
		H.INCORECNT:=H.INCORECNT-1;
		SIZE:=1;
		ASSIGN(THIS SEGMENT);
		MYHISEG;
		H.INCORECNT:=H.INCORECNT+1;
		SIZE:=R.CORE - H.SIZE;
		IF SIZE < 1 THEN SIZE:=1;
		IF FREECORE < SIZE - COREASSIGNED
		THEN	EXPANDING:= TRUE
		ELSE	ASSIGN (THIS SEGMENT);
		END
	
	ELSE	BEGIN
		MYHISEG;
		SIZE:=R.CORE - H.SIZE;
		IF SIZE < 1 THEN SIZE:= 1;
		SWAPPEDSIZE:=1;
		END;

	SGNAME:-COPY(R.PROGRAM);
	HISEGMESG(I,H.I);
	IO.REQ.INIT;
	END;

END;

END ***MYNEXTREQ***;
PROCEDURE REQUEUE (POS, Q, QUANT); 	INTEGER POS; REF (QUEUE) Q;
					REAL QUANT;
BEGIN
MYQUEUE.UPDATE;
Q.UPDATE;
MYQUEUE:-Q;
IF POS=FRONT THEN FOLLOW (Q)
ELSE INTO (Q);

CPUQUANTUMLEFT:=QUANT;

IF WANTEVTMESG(22)
THEN	BEGIN
	OUTTIME (TIME);
	OUTTEXT ("JOB ");
	OUTINT (I,3);
	OUTTEXT (" MOVED TO ");
	IF POS = FRONT THEN OUTTEXT ("FRONT OF ")
	ELSE OUTTEXT ("REAR OF ");
	OUTTEXT (Q.QNAME);
	OUTIMAGE;
	END;

END;

PROCEDURE QUANTUMREQUEUE;

BEGIN

IF MYQUEUE==PQ1 OR MYQUEUE==PQ3 THEN
	REQUEUE (REAR, PQ2,COMPQUANT)

	ELSE REQUEUE (REAR, PQ3, COMPQUANT);


END  ***QUANTUMREQUEUE***;


PROCEDURE UPDATEACTCNT;

BEGIN
INTEGER I;
REAL T;

I:=NRACTIVENOW;
T:=TIME - ACTCHNGTIME;
ACTJOBWT(I):=ACTJOBWT(I) + T;
TOTACTIVE:=TOTACTIVE + T;
SUMACTIVE:=SUMACTIVE + I*T;
ACTCHNGTIME:=TIME;
END ***UPDATEACTCNT***;
! **************** MAIN SECTION OF CLASS  JOB *****************;


REF(HISEG) H;
REF(REQUEST)R;
REF(QUEUE)MYQUEUE;
REF (IOPROCESS) IO;

REAL NEXTREQTIME;
REAL FULLBUFS, BLKSNEEDED, CPUTIMENEEDED, CPUB4IO, CPUPERBLK;

BOOLEAN IOACTIVE,IODONE, IOWAIT, STARTED, NEEDSREQUEUE;

REAL CPUQUANTUMLEFT, PROTECTTIME;


IO:-NEW IOPROCESS (THIS JOB);
ACTIVATE IO;
STARTED:=TRUE;
INCORE:=FALSE;
REQUEUE (REAR, STOPQ, 0);
MYNEXTREQ;

WHILE R =/= NONE DO

BEGIN

FULLBUFS:=0;


IF R.DISKBLKS = 0 THEN
	BEGIN
	BLKSNEEDED:=0;
	CPUTIMENEEDED:=CPUPERBLK:=R.CPUTIME;
	CPUB4IO:=R.CPUTIME+1000000;
	END

ELSE	BEGIN
	BLKSNEEDED:=R.DISKBLKS;
	IF R.CPUTIME = 0 THEN R.CPUTIME:=.01;
				!MUST HAVE CPU PER BLK > 0  OR
				DISPATCHER WILL BE CONFUSED;
	CPUPERBLK:=R.CPUTIME/R.DISKBLKS;
	CPUB4IO:=CPUPERBLK/2;
	CPUTIMENEEDED:=R.CPUTIME;
	END;


REQUEUE (FRONT, PQ1, INITIALQUANT);

UPDATEACTCNT;
NRACTIVENOW:=NRACTIVENOW + 1;

PASSIVATE;
EVENT(19,I);
REQSPENDING:=REQSPENDING - 1;

UPDATEACTCNT;
NRACTIVENOW:=NRACTIVENOW - 1;

MYNEXTREQ;

END ***WHILE R =/= NONE***;

HOLD (100000);

END ***CLASS JOB***;
PROCESS CLASS IOPROCESS (J); 	REF(JOB) J;

BEGIN
REF(IOREQ) REQ;


REQ:-NEW IOREQ;
REQ.OWNER:-THIS IOPROCESS;
REQ.INIT;

PASSIVATE;

WHILE J.R =/= NONE DO

BEGIN
EVENT (10,J.I);
WHILE J.FULLBUFS < NRBUFFERS  AND J.BLKSNEEDED > J.FULLBUFS DO
	BEGIN
	J.IOACTIVE:=TRUE;
	EVENT (24,J.I);
	REQ.INTO(REQ.DRIVE.POSWAITQUEUE);
	ACTIVATE REQ.DRIVE AFTER THIS PROCESS;
	PASSIVATE;
	J.FULLBUFS:= J.FULLBUFS +  REQ.NRBLKS;
	IF J.IOWAIT
	THEN	BEGIN
		J.IODONE:=TRUE;
		J.NEEDSREQUEUE:=TRUE;
		END;
	END *** WHILE J.FULLBUFS < NRBUFFERS ***;

J.IOACTIVE:=FALSE;
EVENT (11,J.I);
PASSIVATE;
END ***WHILE  J.R =/= NONE ***;

HOLD (100000);

END CLASS IOPROCESS;
!*******************************************************************


			SWAPPER


**********************************************************************;


SCANNER CLASS OSCANOBJ;

WHILE RESTART DO
BEGIN
RESTART:=FALSE;
SCANBACK (STOPQ);
SCANBACK(PQ3);
SCANBACK(PQ2);
SCANBACK(PQ1);
WHILE NOT RESTART DO PASSIVATE;

END ***OSCANOBJ***;


SCANNER CLASS ISCANOBJ;

WHILE RESTART DO
BEGIN
RESTART:=FALSE;
SCANFOR(PQ1);
SCANFOR(PQ2);
SCANFOR(PQ3);
WHILE NOT RESTART DO PASSIVATE;

END ***ISCANOBJ***;
PROCESS CLASS SWAPPEROBJ;

BEGIN

PROCEDURE SWAPOUT;
BEGIN
REF (JOB) J;


OSCAN.RESTART:=TRUE;
ACTIVATE OSCAN;
J:-OSCAN.J;
OUTJOB:-NONE;
AVAIL:=0;
BESTSOFAR:=0;
AMTSHORT:=CORENEEDED - FREECORE;

WHILE AVAIL < AMTSHORT AND J =/= NONE AND J =/= INJOB DO

BEGIN
IF J.OUTSWAPPABLE THEN
	BEGIN
	AVAILHERE:=J.SIZE +  J.H.SIZE/J.H.INCORECNT;

	AVAIL:=AVAIL + AVAILHERE;
	IF AVAILHERE > BESTSOFAR THEN
		BEGIN
		BESTSOFAR:=AVAILHERE;
		OUTJOB:-J;
		END;
	END;

ACTIVATE OSCAN;
J:-OSCAN.J;
END;
IF AVAIL < AMTSHORT THEN
	BEGIN
	STUCK:=TRUE;
	TIMESSTUCK:=TIMESSTUCK + 1;
	OUTJOB:-NONE;
	END

ELSE	BEGIN
	J:-OUTJOB;
	EVENT(4,J.I);
	J.BEINGSWAPPED:=TRUE;
	J.H.INCORECNT:=J.H.INCORECNT-1;
	IF J.H.OUTSWAPPABLE THEN
		BEGIN
		J.H.BEINGSWAPPED:=TRUE;
		J.H.SWAPPEDSIZE:=J.H.COREASSIGNED;
		EVENT(5,J.H.I);
		HOLD (SWAPLATENCY + (J.H.COREASSIGNED/SWAPRATE));
		PSWPDOUT:=PSWPDOUT + J.H.COREASSIGNED;
		J.H.BEINGSWAPPED:=FALSE;
		DEASSIGN(J.H);
		END;

	WHILE J.IOACTIVE DO PASSIVATE;

	J.SWAPPEDSIZE:=J.COREASSIGNED;
	EVENT(6,J.I);
	HOLD (SWAPLATENCY +  (J.COREASSIGNED/SWAPRATE));
	XFERSOUT:=XFERSOUT + 1;
	PSWPDOUT:=PSWPDOUT + J.COREASSIGNED;
	J.EXPANDING:=FALSE;
	J.BEINGSWAPPED:=FALSE;
	DEASSIGN(J);
	END;


END ***SWAPOUT***;
PROCEDURE SWAPIN;

BEGIN
REF(JOB)J;

ISCAN.RESTART:=TRUE;
ACTIVATE ISCAN;

J:-ISCAN.J;
STUCK:=FALSE;

WHILE (IF J =/= NONE THEN NOT J.INSWAPPABLE ELSE FALSE) DO
	BEGIN
	ACTIVATE ISCAN;
	J:-ISCAN.J;
	END;
IF J == NONE THEN PASSIVATE
ELSE	BEGIN
	INJOB:-J;
	EVENT(1,J.I);
	CORENEEDED:=J.SIZE - J.COREASSIGNED + ( IF NOT J.H.INCORE
			THEN J.H.SIZE ELSE 0);
	WHILE CORENEEDED > FREECORE AND NOT STUCK DO
		SWAPOUT;

	IF NOT STUCK THEN

	BEGIN
	IF NOT J.H.INCORE THEN
		BEGIN
		ASSIGN(J.H);
		J.H.BEINGSWAPPED:=TRUE;
		EVENT(2,J.H.I);
		HOLD(SWAPLATENCY + J.H.SWAPPEDSIZE/SWAPRATE);
		PSWPDIN:=PSWPDIN + J.H.SWAPPEDSIZE;
		J.H.BEINGSWAPPED:=FALSE;
		J.H.INCORE:=TRUE;
		CORENEEDED:=CORENEEDED - INJOB.H.SIZE;
	
		WHILE CORENEEDED > FREECORE AND NOT STUCK DO
			SWAPOUT;
	
		END;
	END ***IF NOT STUCK***;

	IF NOT STUCK THEN
	BEGIN
	IF NOT J. INCORE THEN
	BEGIN
	ASSIGN (J);
	J.BEINGSWAPPED:=TRUE;
	EVENT(3,J.I);
	HOLD (SWAPLATENCY + (J.SWAPPEDSIZE/SWAPRATE));
	PSWPDIN:=PSWPDIN + J.SWAPPEDSIZE;
	XFERSIN:=XFERSIN + 1;
	J.BEINGSWAPPED:=FALSE;
	J.H.INCORECNT:=J.H.INCORECNT+1;
	J.INCORE:=TRUE;
	J.PROTECTTIME:=TIME + PROT0 + PROT1*((2*J.SIZE) - 1);
	END;

	 J.EXPANDING:=FALSE;
	END

	ELSE EVENT(7,J.I);

	END;
	PASSIVATE;


END ***SWAPIN ***;
BOOLEAN STUCK;
REAL CORENEEDED;
REF(OSCANOBJ) OSCAN;
REF(ISCANOBJ) ISCAN;
REAL AVAIL, AMTSHORT, AVAILHERE,BESTSOFAR;
REF(JOB) INJOB,OUTJOB;
INTEGER TIMESSTUCK, XFERSIN, XFERSOUT;
REAL PSWPDIN, PSWPDOUT;


ISCAN:-NEW ISCANOBJ;
OSCAN:-NEW OSCANOBJ;

WHILE NOT F.ENDFILE  OR REQSPENDING > 0 DO
	SWAPIN;

HOLD (100000);

END ***SWAPPEROBJ***;


!**********************************************************************


			DISPATCHER


**********************************************************************;




SCANNER CLASS SCHEDSCANOBJ;

WHILE  RESTART DO
BEGIN
RESTART:=FALSE;
SCANFOR(PQ1);
SCANFOR(PQ2);
SCANFOR(PQ3);
WHILE NOT RESTART DO PASSIVATE;

END  **SCHEDSCANOBJ***;



PROCESS CLASS DISPOBJ;	!SYSTEM DISPATCHER;

BEGIN

REF (JOB) PROCEDURE NEXTJOB;
BEGIN


BLOCKEDPQJOB:=FALSE;
SCHEDCALLS:=SCHEDCALLS + 1;

SSCANNER.RESTART:=TRUE;
ACTIVATE SSCANNER;

WHILE 
	(IF SSCANNER.J =/= NONE  THEN NOT SSCANNER.J.RUNNABLE
		ELSE FALSE)  DO
		BEGIN
		IF J.SWAPWAIT THEN BLOCKEDPQJOB:=TRUE;
		ACTIVATE SSCANNER;
		END;

IF SSCANNER.J == NONE THEN NEXTJOB:- NULLJOB
	ELSE NEXTJOB:-SSCANNER.J;
END  ***NEXTJOB ***;
PROCEDURE UPDATEQUEUES;

BEGIN
INTEGER I;
FOR I:= 1 STEP 1 UNTIL MAXJOB DO
	BEGIN
	J:-JOBLIST(I);
	IF J.NEEDSREQUEUE THEN
		BEGIN
		IF J.IODONE THEN
			BEGIN
			J.REQUEUE (FRONT, PQ1, IOQUANT);
			J.IODONE:=J.IOWAIT:=FALSE;
			END
		ELSE	IF J.IOWAIT
			THEN	J.REQUEUE (REAR, IOWAITQ, 0);
		J.NEEDSREQUEUE:=FALSE;
		END;
	END;

END ***UPDATEQUEUES ***;

PROCEDURE UPDATETIMES (T,J); REAL T; REF(JOB) J;

!ARGUMENT T IS HOW LONG JOB JUST RAN;
INSPECT J DO

BEGIN
CPUTIMENEEDED:= CPUTIMENEEDED - T;
CPUB4IO:=CPUB4IO - T;
CPUQUANTUMLEFT:=CPUQUANTUMLEFT - T;
TIMETILLTICK:=TIMETILLTICK - T;
END;
PROCEDURE RECORDINT(J);  REF(JOB) J;

BEGIN
REAL STRECH, T, T2;
INTEGER I, I2;

INSPECT J.R DO

BEGIN
NRINT:=NRINT + 1;
RESPONSETIME:=TIME - TIMEIN;

IF WANTEVTMESG(29)
THEN	BEGIN
	OUTTEXT ("RESPONSE TIMES: ");
	OUTFIX (SERVICETIME,2,8);
	OUTFIX (RESPONSETIME,2,8);
	OUTIMAGE;
	END;

		INSPECT RSLTS DO
		BEGIN
		OUTFIX (STARTTIME,2,8);
		OUTFIX (THINKTIME,2,8);
		OUTFIX (SERVICETIME,2,8);
		OUTFIX (RESPONSETIME,2,8);
		OUTFIX (RESPONSETIME - SERVICETIME,2,8);
		OUTTEXT (" ");
		OUTTEXT (PROGRAM);
		OUTINT (CORE,4);
		OUTFIX (CPUTIME,2,8);
		OUTINT (JOBNR,4);
		OUTINT (DISKBLKS,6);
		OUTIMAGE;
		END;


RESPTOT:=RESPTOT + RESPONSETIME;
RESPSQTOT:=RESPSQTOT + (RESPONSETIME**2);
ASERVTOT:=ASERVTOT + SERVICETIME;
ASERVSQTOT:=ASERVSQTOT + (SERVICETIME**2);
PRODTOT:=PRODTOT + RESPONSETIME * SERVICETIME;

RESPDIFF:=RESPONSETIME - SERVICETIME;
DIFFTOT:=DIFFTOT + RESPDIFF;
DIFFABSTOT:=DIFFABSTOT + ABS(RESPDIFF);

TOTCPU:=TOTCPU  + CPUTIME;
TOTWAIT:=TOTWAIT + RESPONSETIME;
TOTDSK:=TOTDSK + DISKBLKS;


IF RESPONSETIME < 60 THEN
	BEGIN
	I:= 1;
	T:= .5;
	END
ELSE	BEGIN
	I:= 8;
	T:= 60;
	END;


	IF RESPONSETIME < 1920 THEN
		BEGIN
		WHILE T < RESPONSETIME DO
			BEGIN
			I:=I+1;
			T:=T*2;
			END;
		END

	ELSE	I:= 14;

RESPTIMECNT(I):=RESPTIMECNT(I) + 1;
RESPTIMEWT(I):=RESPTIMEWT(I) + CPUTIME;


IF CPUTIME < .4
THEN	BEGIN
	TOTSHRTCNT:= TOTSHRTCNT + 1;
	TOTSHRTWT:=TOTSHRTWT + CPUTIME;
	SHRTRESPCNT(I) :=SHRTRESPCNT(I) + 1;
	SHRTRESPWT(I) := SHRTRESPWT(I) + CPUTIME;
	END

ELSE	BEGIN
	TOTLONGCNT:=TOTLONGCNT + 1;
	TOTLONGWT:=TOTLONGWT + CPUTIME;
	LONGRESPCNT(I):=LONGRESPCNT(I) + 1;
	LONGRESPWT(I):=LONGRESPWT(I) + CPUTIME;

	STRECH:=RESPONSETIME/CPUTIME;
	IF STRECH > 80 THEN I2:=7
	ELSE	BEGIN
		T2:=2.5;
		I2:=1;
		WHILE T2 < STRECH DO
			BEGIN
			T2:=T2*2;
			I2:=I2+1;
			END;
		END;

	RESPCATCNT(I2):=RESPCATCNT(I2) + 1;
	RESPCATWT(I2):=RESPCATWT(I2) + CPUTIME;
	END;




END ***INSPECT  R ***;

END ***RECORDINT ***;
!**********************************************************************

			MAIN SECTION OF DISPATCHER

**********************************************************************;


REF(SCHEDSCANOBJ) SSCANNER;
REAL TIMETILLTICK,T,T2;
REF (JOB) J, OLDJOB;
BOOLEAN BLOCKEDPQJOB;
REAL USERTIME, IDLETIME, LOSTTIME, OVERHDTIME;
INTEGER SECTICS, MINSECS;
INTEGER NRACTIVEJOBS,ACTTOT, ACTCNT;
INTEGER CONTEXTSWITCHES, SCHEDCALLS, UUOS, NRINT;

REAL RESPONSETIME;
REAL RESPTOT, RESPDIFF, DIFFTOT, DIFFABSTOT;
REAL RESPSQTOT,ASERVTOT, ASERVSQTOT, PRODTOT;
REAL TOTCPU, TOTWAIT, TOTDSK;


INTEGER ARRAY RESPTIMECNT(1:14);
REAL ARRAY RESPTIMEWT(1:14);

INTEGER ARRAY SHRTRESPCNT (1:14);
INTEGER TOTSHRTCNT;
REAL ARRAY SHRTRESPWT (1:14);
REAL TOTSHRTWT;

INTEGER ARRAY LONGRESPCNT(1:14);
INTEGER TOTLONGCNT;

REAL ARRAY LONGRESPWT (1:14);
REAL TOTLONGWT;

INTEGER ARRAY RESPCATCNT (1:7);
REAL ARRAY RESPCATWT (1:7);



SSCANNER:-NEW SCHEDSCANOBJ;

SECTICS:=-1;
MINSECS:=0;

WHILE NOT F.ENDFILE  OR REQSPENDING > 0 DO
	BEGIN
	EVENT(23,0);
	TIMETILLTICK:=(1/60);

	SECTICS:=SECTICS + 1;
	IF SECTICS = 60
	THEN	BEGIN
		EVENT (26,0);
		SECTICS:= 0;
		MINSECS:=MINSECS + 1;
		IF MINSECS = 60
		THEN	BEGIN
			EVENT (27,0);
			MINSECS:= 0;
			END;
		END;

	UPDATEQUEUES;

	ACTIVATE SWAPPER;

	NRACTIVEJOBS:=PQ1.CARDINAL + PQ2.CARDINAL + PQ3.CARDINAL
			+ IOWAITQ.CARDINAL;
	ACTTOT:= ACTTOT + NRACTIVEJOBS;
	ACTCNT:=ACTCNT + 1;

	T:= (1/60)*(OVERHD0 + NRACTIVEJOBS*OVERHD1);
	HOLD (T);
	OVERHDTIME:=OVERHDTIME + T;
	TIMETILLTICK:=TIMETILLTICK - T;

	WHILE TIMETILLTICK > 0 DO

	BEGIN
	IF J =/= NULLJOB THEN OLDJOB:- J;
	J:-NEXTJOB;
				!RUN THE SELECTED JOB;
	IF J =/= OLDJOB  AND J =/= NULLJOB
		THEN CONTEXTSWITCHES:=CONTEXTSWITCHES + 1;
	INSPECT J DO

	BEGIN
	T:=MIN(TIMETILLTICK,CPUTIMENEEDED);
				!T IS MAX TIME JOB CAN RUN BEFORE CLOCK
				TICK OR COMPLETION OF REQUEST, ASSUMING
				IT DOES NOT HAVE TO WAIT FOR IO;

	WHILE T > 0 AND NOT IOWAIT DO
	BEGIN

	T2:= MIN(T,CPUB4IO);
	IF T2 > 0 THEN
	BEGIN
	SCHEDMESG(J,T2);

				!T2 IS TIME UNTIL EITHER RUNTIME EXPIRES
				OR JOB NEEDS MORE IO;
	HOLD(T2);

	IF J =/= NULLJOB THEN USERTIME:= USERTIME + T2
	ELSE	IF BLOCKEDPQJOB THEN LOSTTIME:=LOSTTIME + T2
		ELSE IDLETIME:= IDLETIME + T2;

	END;

	!NOW WE HAVE EITHER (1) CLOCK TICK, (2) IO REQUEST, 
		OR (3) INTERACTION COMPLETE;

	T:=T - T2;

	UPDATETIMES(T2,J);

	IF CPUB4IO <= 0 
	THEN	BEGIN
		IF FULLBUFS > 0
		THEN	BEGIN
			UUOS:=UUOS+1;
			FULLBUFS:=FULLBUFS - 1;
			BLKSNEEDED:=BLKSNEEDED - 1;

			IF BLKSNEEDED > 0 
			THEN	BEGIN
				CPUB4IO:= CPUPERBLK;
				IF FULLBUFS <= 1 AND NOT IOACTIVE
				  THEN ACTIVATE IO;
				END
			ELSE	CPUB4IO:=10000000;
			EVENT (15,J.I);
			END
		ELSE	BEGIN
			IOWAIT:=TRUE;
			NEEDSREQUEUE:=TRUE;
			IF NOT IOACTIVE THEN ACTIVATE IO;
			EVENT (16, J.I);
			END;
		END;


	END ***WHILE T > 0 AND NOT IOWAIT ***;


	IF NOT IOWAIT THEN
		BEGIN
		IF CPUQUANTUMLEFT <= 0 THEN QUANTUMREQUEUE;
	
		IF CPUTIMENEEDED <= 0 THEN
			BEGIN
			IF BLKSNEEDED > 0 
			THEN	BEGIN
				OUTTEXT ("ERR IN DISPATCHER ");
				OUTIMAGE;
				OUTTEXT ("STILL NEED IO AT END OF INT");
				OUTIMAGE;
				END;
			J.PROTECTTIME:=0;
			J.REQUEUE (REAR, STOPQ, 0);
			RECORDINT(J);	!UPDATE INTERACTION DATA;
			ACTIVATE(J);
			END;
		END  ***IF NOT IOWAIT ***;
	END; ! ***INSPECT J DO  (I.E. RUN SELECTED JOB) ***;

	END ***WHILE TIMTILLTICK > 0 ***;


	END ***WHILE NOT F.ENDFILE***;

ENDTIME:=TIME;

HOLD (.01);

FOR I:= 1 STEP 1 UNTIL 6 DO
	QUEUELIST(I).UPDATE;



HOLD (100000);

END ***CLASS DISPOBJ ***;
PROCEDURE REPORT;

BEGIN


PROCEDURE RPTHDR;

INSPECT O DO
BEGIN
OUTIMAGE;
OUTIMAGE;
OUTIMAGE;
OUTTEXT("             T O P S - 1 0    S I M U L A T I O N   R E P O R T ");
OUTIMAGE;
OUTIMAGE;
OUTIMAGE;
OUTTEXT("TOPS.SIM VERSION ");
OUTINT(VERSION,3);
OUTIMAGE;

OUTTEXT("TRACE FILE: ");
OUTTEXT(FNAME);
OUTIMAGE;

OUTTEXT("PARAMETER FILE: ");
OUTTEXT(PARNAME);
OUTIMAGE;

OUTTEXT("REPORT FILE: ");
OUTTEXT(ONAME);
OUTIMAGE;

OUTTEXT("DETAILED RESULTS FILE: ");
OUTTEXT(RSLTSNAME);
OUTIMAGE;
OUTIMAGE;
OUTIMAGE;
OUTTEXT("TOTAL TIME SIMULATED: ");
OUTFIX(ENDTIME,0,6);
OUTTEXT(" SECONDS");
OUTIMAGE;
OUTIMAGE;
END;
PROCEDURE RPTRSP;

INSPECT O DO
INSPECT DISPATCHER DO
BEGIN

INTEGER N,I;
REAL CORREL, SUM, S;



N:=NRINT;
OUTIMAGE;
OUTIMAGE;
OUTTEXT  ("NR INTERACTIONS: ");
OUTINT  (N,6);
OUTIMAGE;

OUTIMAGE;
OUTTEXT  ("AVE DIFF: ");
OUTFIX (DIFFTOT/N, 3, 8);
OUTIMAGE;

OUTTEXT  ("AVE ABS DIFF: ");
OUTFIX (DIFFABSTOT/N, 3, 8);
OUTIMAGE;

OUTTEXT("CORREL COEF: ");
CORREL:=(PRODTOT - (RESPTOT*ASERVTOT)/N) / 
	   SQRT((RESPSQTOT - (RESPTOT**2)/N) * (ASERVSQTOT - (ASERVTOT**2)/N));

OUTFIX (CORREL, 2, 6);
OUTIMAGE;

OUTIMAGE;

OUTTEXT("NR JOBS ");
OUTINT (MAXJOBNR,3);
OUTIMAGE ;

OUTTEXT("TOTAL CPU TIME ");
OUTFIX (TOTCPU,3,8);


OUTTEXT(" = ");
OUTFIX (100*TOTCPU/ENDTIME,1,5);
OUTTEXT(" % USER ");
OUTIMAGE ;

OUTTEXT("TOTAL DSK BLKS ");
OUTINT (TOTDSK, 6);
OUTTEXT("  = ");
OUTFIX (TOTDSK/ENDTIME, 0,4);
OUTTEXT(" BLKS/SEC ");
OUTIMAGE ;



OUTTEXT("TOTAL USER WAIT TIME ");
OUTFIX (TOTWAIT,0,6);
OUTTEXT( " SEC  = ");
OUTFIX (TOTWAIT/MAXJOBNR,0,6);
OUTTEXT(" SEC PER USER ");
OUTIMAGE ;
OUTIMAGE ;


OUTTEXT("NR ACTIVE JOBS");
OUTIMAGE; 
OUTTEXT("      NR     %       CUMULATIVE ");
OUTIMAGE ;

SUM:= 0;
FOR I:= 0 STEP 1 UNTIL 19 DO
	IF SUM < TOTACTIVE THEN
	BEGIN
	OUTINT (I,8);
	OUTFIX (100*ACTJOBWT(I)/TOTACTIVE,1,8);
	SUM:=SUM +  ACTJOBWT(I);
	OUTFIX (100*SUM/TOTACTIVE,1,8);
	OUTIMAGE ;
	END;

OUTIMAGE ;
OUTTEXT("AVE NR ACTIVE JOBS =");
OUTFIX (SUMACTIVE/TOTACTIVE,1,5);
OUTIMAGE ;
OUTIMAGE ;
BEGIN
PROCEDURE RESPREP (CNT, WT, CNTTOT, WTTOT);


INTEGER ARRAY CNT;
REAL ARRAY WT;
INTEGER CNTTOT;
REAL WTTOT;

BEGIN
INTEGER I, CUMCNT;
REAL T, CUMWT;


IF  CNTTOT > 0 THEN
BEGIN
OUTTEXT ("                 NR       %     CUM    %CPU     CUM");
OUTIMAGE;

CUMCNT:=CUMWT:= 0;

FOR I:= 1 STEP 1 UNTIL 14 DO
IF CUMCNT < CNTTOT THEN
BEGIN
IF I < 8 THEN
	BEGIN
	OUTFIX (.5*(2**(I-1)),1,6);
	OUTTEXT (" SEC ");
	END

ELSE	BEGIN
	OUTFIX (2**(I-8),1,6);
	OUTTEXT (" MIN ");
	END;


OUTINT (CNT(I),8);

OUTFIX (100*CNT(I)/CNTTOT,1,8);
CUMCNT:= CUMCNT + CNT(I);

OUTFIX (100*CUMCNT/CNTTOT,1,8);
IF WTTOT > 0 THEN
	BEGIN
	OUTFIX (100*WT(I)/WTTOT,1,8);
	CUMWT:=CUMWT + WT(I);
	OUTFIX (100*CUMWT/WTTOT,1,8);
	END;
OUTIMAGE ;
END;

OUTTEXT ("           ");
OUTINT(CNTTOT,8);
OUTIMAGE;

OUTIMAGE ;
OUTIMAGE ;

END;
END ***PROCEDURE RESPREP***;
OUTTEXT ("RESPONSE TIMES -- ALL INTERACTIONS ");

OUTIMAGE ;
OUTIMAGE ;

RESPREP (RESPTIMECNT, RESPTIMEWT, NRINT, TOTCPU);

OUTTEXT ("RESPONSE TIMES -- INTERACTIONS < .4 SEC CPUTIME ");
OUTIMAGE ;
OUTIMAGE ;

RESPREP (SHRTRESPCNT, SHRTRESPWT, TOTSHRTCNT, TOTSHRTWT);

OUTIMAGE ;
OUTIMAGE ;


OUTTEXT ("RESPONSE TIMES -- INTERACTIONS > .4 SEC CPUTIME ");
OUTIMAGE ;
OUTIMAGE ;
RESPREP (LONGRESPCNT, LONGRESPWT, TOTLONGCNT, TOTLONGWT);

OUTIMAGE ;
OUTIMAGE ;
END;



OUTTEXT ("STRETCH FACTORS -- INTERACTIONS > .4 SEC CPU TIME");
OUTIMAGE ;
OUTTEXT ("FACTOR    NR       %     CUM     WT%     CUM ");
OUTIMAGE;

S:=T:=0;

FOR I:= 1 STEP 1 UNTIL 7 DO
IF S < TOTLONGCNT THEN
BEGIN
OUTFIX (2.5*(2**I),1,6);
OUTINT(RESPCATCNT(I),6);
OUTFIX (100*RESPCATCNT(I)/TOTLONGCNT,1,8);
S:=S + RESPCATCNT(I);
OUTFIX (100*S/TOTLONGCNT,1,8);
OUTFIX (100*RESPCATWT(I)/TOTLONGWT,1,8);
T:=T + RESPCATWT(I);
OUTFIX (100*T/TOTLONGWT,1,8);
OUTIMAGE;
END;
OUTIMAGE ;
OUTIMAGE ;

END ***RPTRST***;
PROCEDURE RPTCPU;
INSPECT O DO
INSPECT DISPATCHER DO
BEGIN
OUTIMAGE;
OUTIMAGE;
OUTTEXT ("CPU UTILIZATION");
OUTIMAGE;
OUTIMAGE;
OUTTEXT ("% IDLE: ");
OUTFIX (100*IDLETIME/ENDTIME, 1, 6);
OUTIMAGE;

OUTTEXT ("% LOST: ");

OUTFIX (100*LOSTTIME/ENDTIME, 1,6);
OUTIMAGE;

OUTTEXT ("% OVHD: ");
OUTFIX (100*OVERHDTIME/ENDTIME,1,6);
OUTIMAGE;


OUTTEXT ("% USER: ");
OUTFIX (100*USERTIME/ENDTIME, 1,6);
OUTIMAGE;
OUTIMAGE;


OUTTEXT ("SCHEDULER CALLS: ");
OUTINT (SCHEDCALLS, 6);
OUTIMAGE;

OUTTEXT("CONTEXT SWITCHES: ");
OUTINT (CONTEXTSWITCHES, 6);
OUTIMAGE;

OUTTEXT ("UUOS: ");
OUTINT (UUOS,6);
OUTIMAGE;
OUTIMAGE;

END ***RPTCPU***;
PROCEDURE RPTSWP;

INSPECT O DO
BEGIN
OUTTEXT ("SWAPPING DATA");
OUTIMAGE;
OUTIMAGE;

OUTTEXT ("INPUT TRANSFERS: ");
OUTINT (SWAPPER.XFERSIN,6);
OUTIMAGE;

OUTTEXT ("PAGES SWAPPED IN: ");
OUTFIX (SWAPPER.PSWPDIN,0,6);
OUTIMAGE;

OUTTEXT ("OUTPUT TRANSFERS: ");
OUTINT (SWAPPER.XFERSOUT,6);
OUTIMAGE;

OUTTEXT ("PAGES SWAPPED OUT: ");
OUTFIX (SWAPPER.PSWPDOUT,0,6);
OUTIMAGE;

OUTTEXT ("TIMES STUCK: ");
OUTINT (SWAPPER.TIMESSTUCK,6);
OUTIMAGE;
OUTIMAGE;

END ***PROCEDURE RPTSWP***;
PROCEDURE RPTQUEUELEN;

INSPECT O DO
BEGIN
OUTTEXT("AVE QUEUE LENGTHS ");
OUTIMAGE;
OUTIMAGE;
FOR I:= 1 STEP 1 UNTIL 6 DO
	BEGIN
	INSPECT QUEUELIST(I) DO
		BEGIN
		OUTTEXT (QNAME);
		IF LASTCHANGE > 0 THEN
		OUTFIX (SUM/LASTCHANGE,3,8)
		ELSE OUTFIX (0,3,8);
		OUTIMAGE;
		END;
	END;

OUTIMAGE;
END ***RPTQUEUELEN ***;
PROCEDURE RPTDISK;

INSPECT O DO
BEGIN
REF(CHANNEL) C;
REF(CONTROLLER) KON;
REF(DISKDRIVE)D;
INTEGER I, J, K, NRKON, NRDRIVES;
INTEGER SEEKTOT, XFERTOT, BLOCKTOT;


OUTTEXT ("DISK STATISTICS ");
OUTIMAGE;
OUTIMAGE;

FOR I:= 1 STEP 1 UNTIL NRCHAN DO

	BEGIN
	C:-CHANLIST(I);

	NRKON:=C.NRKON;
	FOR J:= 1 STEP 1 UNTIL NRKON DO
		
		BEGIN
		KON:-C.KONLIST(J);

		NRDRIVES:=KON.NRDRIVES;
		FOR K:= 1 STEP 1 UNTIL NRDRIVES DO
	
			BEGIN
			D:-KON.DRIVELIST(K);
			SEEKTOT:=SEEKTOT + D.SEEKS;
			XFERTOT:=XFERTOT + D.XFERS;
			BLOCKTOT:= BLOCKTOT + D.BLOCKS;


			END;
		END;
	END;
OUTTEXT ("SEEKS: ");
OUTINT (SEEKTOT,5);
OUTIMAGE;
OUTTEXT ("TRANSFERS: ");
OUTINT (XFERTOT,5);
OUTIMAGE;
OUTTEXT ("BLOCKS: ");
OUTINT (BLOCKTOT,5);
OUTIMAGE;

END ***RPTDISK ***;
!MAIN SECTION OF PROCEDURE REPORT;

OUTTEXT ("TOTAL TIME SIMULATED = ");
OUTTIME (ENDTIME);


INSPECT O DO
BEGIN

RPTHDR;

RPTRSP;

RPTCPU;

RPTSWP;


RPTDISK;

END;
END ***PROCEDURE REPORT***;
!**********************************************************************
**********************************************************************
*********************************************************************

	STARTING MAIN PROGRAM


**********************************************************************
**********************************************************************
********************************************************************;




INTEGER RANDOMVAR,I,J, DRIVENR;
TEXT BUFFER, EBUF, FNAME;
REF (DISPOBJ) DISPATCHER;
REF (SWAPPEROBJ) SWAPPER;
REF (QUEUE) PQ1,PQ2,PQ3,STOPQ,IOWAITQ,NULLQ;
REF (INFILE) F;
REF (OUTFILE) ERRFILE;

REF (REQUEST) R;
REF (HEAD) HISEGCHAIN;

REF (CHANNEL) ARRAY CHANLIST (1:8);
REF (DISKDRIVE) ARRAY DRIVELIST (1:64);
REF(HEAD) ARRAY REQSTACK (1:MAXJOB);
REF(JOB) ARRAY JOBLIST (1:MAXJOB);
REF (QUEUE) ARRAY QUEUELIST (1:6);
REF(HISEG) NULLHISEG;

REF(JOB) NULLJOB;

REF(CHANNEL) C;
REF(DISKDRIVE) D;

BOOLEAN ARRAY WANTEVTMESG (1:100);
TEXT ARRAY EVENTMESG (1:100);
INTEGER REQSPENDING;
INTEGER FRONT, REAR;
REAL ENDTIME, LASTSTARTTIME;
INTEGER MAXJOBNR;

REAL ARRAY ACTJOBWT (0:20);
REAL ACTCHNGTIME, TOTACTIVE, SUMACTIVE;
INTEGER NRACTIVENOW;
INITEVENTARRAY;

OUTTEXT ("TRACE FILE? ");
BREAKOUTIMAGE;
INIMAGE;
FNAME:-INTEXT(20);
F:-NEW INFILE (FNAME);

BUFFER:-BLANKS(80);
F.OPEN(BUFFER);
F.INIMAGE;

INITDISKDATA;


FRONT:=1;
REAR:=2;





NULLQ:-NEW QUEUE;
NULLQ.QNAME:-COPY("NULL QUEUE     ");
IOWAITQ:-NEW QUEUE;
IOWAITQ.QNAME:-COPY("IOWAIT QUEUE   ");
STOPQ:-NEW QUEUE;
STOPQ.QNAME:-COPY("STOP QUEUE     ");
PQ1:-NEW QUEUE;
PQ1.QNAME:-COPY("PQ1            ");
PQ2:-NEW QUEUE;
PQ2.QNAME:-COPY("PQ2            ");
PQ3:-NEW QUEUE;
PQ3.QNAME:-COPY("PQ3            ");

QUEUELIST(1):-PQ1;
QUEUELIST(2):-PQ2;
QUEUELIST(3):-PQ3;
QUEUELIST(4):-IOWAITQ;
QUEUELIST(5):-STOPQ;
QUEUELIST(6):-NULLQ;

INITHISEGS;

NULLJOB:-NEW JOB(0);

INSPECT NULLJOB DO
	CPUQUANTUMLEFT:=CPUTIMENEEDED:=CPUB4IO:=CPUPERBLK:=100000000;


FOR  I:= 1 STEP 1 UNTIL MAXJOB DO
	BEGIN
	REQSTACK(I):-NEW HEAD;
	JOBLIST(I):-NEW  JOB(I);

	INSPECT JOBLIST(I) DO
		BEGIN
		MYQUEUE:-NULLQ;
		REQUEUE (REAR, NULLQ, 0);
		SIZE:=SWAPPEDSIZE:=1;
		INCORE:=EXPANDING:=FALSE;
		COREASSIGNED:=0;
		H:-NULLHISEG;
		STARTED:=FALSE;
		END;


	END;


OUTTEXT("INITIALIZING JOBS"); OUTIMAGE;
REQSPENDING:=0;

WHILE (IF R =/= NONE THEN R.STARTTIME= 0 ELSE TRUE)  DO
	BEGIN
	R:-NEXTREQ;
	R.INTO(REQSTACK(R.JOBNR));
	ACTIVATE JOBLIST(R.JOBNR) DELAY (1/60);
	IF R.JOBNR > MAXJOBNR THEN MAXJOBNR:=R.JOBNR;
	END;

SWAPPER:-NEW SWAPPEROBJ;
OUTTEXT("STARTING SWAPPER"); OUTIMAGE;
ACTIVATE SWAPPER;

OUTTEXT ("STARTING DISPATCHER"); OUTIMAGE;
DISPATCHER:-NEW DISPOBJ;
ACTIVATE DISPATCHER;

OUTTEXT("INITIALIZATION COMPLETE");
OUTIMAGE;
HOLD(36000);
REPORT;

END;

ENDRUN:

END;