/**********************************************************************/ /* */ /* File "smpl.c" */ /* smpl Simulation Subsystem */ /* */ /* C Version 1.10 (C) 1987 M. H. MacDougall */ /* Oct. 22, 1987 All Rights Reserved */ /* */ /**********************************************************************/ #include "smpl.h" #define nl 30000 /* element pool length - 30000 */ #define ns 27680 /* name space length - 27680 */ #define pl 58 /* printer page length (lines used */ #define sl 23 /* screen page length by 'smpl' */ #define FF 12 /* form feed */ static FILE *display, *opf; /* A inicializacao das duas variaveis acima, feita quando da definicao, como abaixo, no texto original do programa, causa erro na compilacao: "Initializer element is not constant". A inicializacao passou a ser feita na funcao smpl(). */ /* *display=stdout, */ /* screen display file */ /* *opf=stdout; */ /* current output destination */ static int event, /* current simulation event */ token, /* last token dispatched */ blk, /* next available block index */ avl, /* available element list header */ evl, /* event list header */ fchn, /* facility descriptor chain header */ avn, /* next available namespace position */ tr, /* event trace flag */ mr, /* monitor activation flag */ lft=sl; /* lines left on current page/screen */ static real clock, /* current simulation time */ start, /* simulation interval start time */ tl; /* last trace message issue time */ static int l1[nl], l2[nl], /* facility descriptor, */ l3[nl]; /* queue, & */ static real /* event list */ l4[nl], /* element pool */ l5[nl]; static char name[ns]; /* model, facility, & table name space */ /*--------------- INITIALIZE SIMULATION SUBSYSTEM ------------------*/ void smpl(int m, char *s) { int i; static int rns=1; display=opf=stdout; /* inicializacao e feita aqui */ blk=1; avl=-1; avn=0; /* element pool & namespace headers */ evl=fchn=0; /* event list & descriptor chain headers */ clock=start=tl=0.0; /* sim., interval start, last trace times */ event=tr=0; /* current event no. & trace flags */ for (i=0; i namespace */ rns=stream(rns); rns=++rns>15? 1:rns; /* set random no. stream */ mr=(m>0)? 1:0; /* set monitor flag */ /* if (mr) then {opf=display; init_mtr(1);} */ } /*----------------------- RESET MEASUREMENTS -----------------------*/ void reset() { resetf(); start=clock; } /*--------------------------- SAVE NAME ----------------------------*/ static int save_name(char *s, int m) { int i,n; n=strlen(s); if (n>m) then n=m; if (avn+n>ns) then error(2,0); /* namespace exhausted */ i=avn; avn+=n+1; strncpy(&name[i],s,n); if (n==m) then name[avn++]='\0'; return(i); } /*------------------------- GET MODEL NAME -------------------------*/ char *mname() { return(name); } /*------------------------ GET FACILITY NAME -----------------------*/ char *fname(int f) { return(&name[l3[f+1]]); } /*--------------------------- GET BLOCK ----------------------------*/ static int get_blk(int n) { int i; if (blk==0) then error(3,0); /* block request after schedule */ i=blk; blk+=n; if (blk>=nl) then error(1,0); /* element pool exhausted */ return(i); } /*-------------------------- GET ELEMENT ---------------------------*/ static int get_elm() { int i; if (avl<=0) then { if (avl==0) then error(1,0); /* empty element list */ /* if (mr && !tr) then init_mtr(2);*/ /* build the free element list from the block of elements */ /* remaining after all facilities have been defined */ for (i=blk; i<(nl-1); i++) l1[i]=i+1; avl=blk; blk=0; } i=avl; avl=l1[i]; return(i); } /*------------------------- RETURN ELEMENT -------------------------*/ static void put_elm(int i) { l1[i]=avl; avl=i; } /*------------------------- SCHEDULE EVENT -------------------------*/ void schedule(int ev, real te, int tkn) { int i; if (te<0.0) then error(4,0); /* negative event time */ i=get_elm(); l2[i]=tkn; l3[i]=ev; l4[i]=0.0; l5[i]=clock+te; enlist(&evl,i); if (tr) then msg(1,tkn,"",ev,0); } /*--------------------------- CAUSE EVENT --------------------------*/ void cause(int *ev, int *tkn) { int i; if (evl==0) then error(5,0); /* empty event list */ i=evl; *tkn=token=l2[i]; *ev=event=l3[i]; clock=l5[i]; evl=l1[i]; put_elm(i); /* delink element & return to pool */ if (tr) then msg(2,*tkn,"",event,0); /* if (mr && (tr!=3)) then mtr(tr,0);*/ } /*-------------------------- RETURN TIME ---------------------------*/ double time() { return(clock); } /*-------------------------- CANCEL EVENT --------------------------*/ int cancel(int ev) { int pred,succ=evl,tkn; while((succ!=0) && (l3[succ]!=ev)) {pred=succ; succ=l1[pred];} if (succ==0) then return(-1); tkn=l2[succ]; if (tr) then msg(3,tkn,"",l3[succ],0); if (succ==evl) then evl=l1[succ]; /* unlink event */ else l1[pred]=l1[succ]; /* list entry & */ put_elm(succ); /* deallocate it */ return(tkn); } /*------------------------- SUSPEND EVENT --------------------------*/ static int suspend(int tkn) { int pred,succ=evl; while((succ!=0) && (l2[succ]!=tkn)) {pred=succ; succ=l1[pred];} if (succ==0) then error(6,0); /* no event scheduled for token */ if (succ==evl) then evl=l1[succ]; /* unlink event */ else l1[pred]=l1[succ]; /* list entry */ if (tr) then msg(6,-1,"",l3[succ],0); return(succ); } /*-------------- ENTER ELEMENT IN QUEUE OR EVENT LIST --------------*/ static void enlist(int *head, int elm) { /* 'head' points to head of queue/event list */ int pred,succ; real arg,v; arg=l5[elm]; succ=*head; while (1) { /* scan for position to insert entry: event list is order- */ /* ed in ascending 'arg' values, queues in descending order */ if (succ==0) then break; /* end of list */ else { v=l5[succ]; if (*head==evl) then { /* event list */ if (v>arg) then break; } else { /* queue: if entry is for a preempted token */ /* (l4, the remaining event time, >0), insert */ /* entry at beginning of its priority class; */ /* otherwise, insert it at the end */ if ((v0.0))) then break; } } pred=succ; succ=l1[pred]; } l1[elm]=succ; if (succ!=*head) then l1[pred]=elm; else *head=elm; } /*----------------------- DEFINE FACILITY --------------------------*/ int facility(char *s, int n) { int f,i; f=get_blk(n+2); l1[f]=n; l3[f+1]=save_name(s,(n>1 ? 14:17)); if (fchn==0) then fchn=f; else {i=fchn; while(l2[i+1]) i=l2[i+1]; l2[i+1]=f;} if (tr) then msg(13,-1,fname(f),f,0); return(f); } /*--------------- RESET FACILITY & QUEUE MEASUREMENTS --------------*/ static void resetf() { int i=fchn,j; while (i) { l4[i]=l4[i+1]=l5[i+1]=0.0; for (j=i+2; j<=(i+l1[i]+1); j++) {l3[j]=0; l4[j]=0.0;} i=l2[i+1]; /* advance to next facility */ } start=clock; } /*------------------------ REQUEST FACILITY ------------------------*/ int request(int f, int tkn, int pri) { int i,r; if (l2[f] 0 for proper enqueueing */ /* (see 'enlist'). Update facility & server stati- */ /* stics for the preempted token, and set r = 0 to */ /* reserve the facility for the preempting token. */ if (tr) then msg(8,tkn,fname(f),2,0); j=l1[k]; i=suspend(j); ev=l3[i]; te=l5[i]-clock; if (te==0.0) then te=1.0e-99; put_elm(i); enqueue(f,j,l2[k],ev,te); if (tr) then {msg(10,-1,"",j,l3[f]); msg(12,-1,fname(f),tkn,0);} l3[k]++; l4[k]+=clock-l5[k]; l2[f]--; l4[f+1]++; r=0; } } if (r==0) then { /* reserve server k of facility */ l1[k]=tkn; l2[k]=pri; l5[k]=clock; l2[f]++; } return(r); } /*------------------------ RELEASE FACILITY ------------------------*/ void release(int f, int tkn) { int i,j=0,k,m; real te; /* locate server (j) reserved by releasing token */ k=f+1+l1[f]; /* index of last server element */ for (i=f+2; i<=k; i++) if (l1[i]==tkn) then {j=i; break;} if (j==0) then error(7,0); /* no server reserved */ l1[j]=0; l3[j]++; l4[j]+=clock-l5[j]; l2[f]--; if (tr) then msg(9,tkn,fname(f),0,0); if (l3[f]>0) then { /* queue not empty: dequeue request ('k' = */ /* index of element) & update queue measures */ k=l1[f+1]; l1[f+1]=l1[k]; te=l4[k]; l5[f+1]+=l3[f]*(clock-l5[f]); l3[f]--; l4[f]++; l5[f]=clock; if (tr) then msg(11,-1,"",l2[k],l3[f]); if (te==0.0) then then { /* blocked request: place request at head of event */ /* list (so its facility request can be re-initiated */ /* before any other requests scheduled for this time) */ l5[k]=clock; l1[k]=evl; evl=k; m=4; } else { /* return after preemption: reserve facility for de- */ /* queued request & reschedule remaining event time */ l1[j]=l2[k]; l2[j]=(int)l5[k]; l5[j]=clock; l2[f]++; if (tr) then msg(12,-1,fname(f),l2[k],0); l5[k]=clock+te; enlist(&evl,k); m=5; } if (tr) then msg(m,-1,"",l3[k],0); } } /*----------------------- GET FACILITY STATUS ----------------------*/ int status(int f) { return(l2[f]==l1[f]); } /*-------------------- GET CURRENT QUEUE LENGTH --------------------*/ int inq(int f) { return(l3[f]); } /*-------------------- GET FACILITY UTILIZATION --------------------*/ double U(int f) { int i; real b=0.0,t=clock-start; if (t>0.0) then { for (i=f+2; i<=f+l1[f]+1; i++) b+=l4[i]; b/=t; } return(b); } /*---------------------- GET MEAN BUSY PERIOD ----------------------*/ double B(int f) { int i,n=0; real b=0.0; for (i=f+2; i<=f+l1[f]+1; i++) {b+=l4[i]; n+=l3[i];} return((n>0)? b/n:b); } /*-------------------- GET AVERAGE QUEUE LENGTH --------------------*/ double Lq(int f) { real t=clock-start; return((t>0.0)? (l5[f+1]/t):0.0); } /*----------------------- TURN TRACE ON/OFF ------------------------*/ void trace(int n) { switch(n) { case 0: tr=0; break; case 1: case 2: case 3: tr=n; tl=-1.0; newpage(); break; case 4: end_line(); break; default: break; } } /*-------------------- GENERATE TRACE MESSAGE ----------------------*/ static void msg(int n, int i, char *s, int q1, int q2) { static char *m[14] = {"","SCHEDULE","CAUSE","CANCEL", " RESCHEDULE"," RESUME"," SUSPEND","REQUEST","PREEMPT", "RELEASE"," QUEUE"," DEQUEUE"," RESERVE","FACILITY"}; if (clock>tl) /* print time stamp (if time has advanced) */ then {tl=clock; fprintf(opf," time %-12.3f ",clock);} else fprintf(opf,"%21s",m[0]); if (i>=0) /* print token number if specified */ then fprintf(opf,"-- token %-4d -- ",i); else fprintf(opf,"-- -- "); fprintf(opf,"%s %s",m[n],s); /* print basic message */ switch(n) { /* append qualifier */ case 1: case 2: case 3: case 4: case 5: case 6: fprintf(opf," EVENT %d",q1); break; case 7: case 8: switch(q1) { case 0: fprintf(opf,": RESERVED"); break; case 1: fprintf(opf,": QUEUED (inq = %d)",q2); break; case 2: fprintf(opf,": INTERRUPT"); break; default: break; } break; case 9: break; case 10: case 11: fprintf(opf," token %d (inq = %d)",q1,q2); break; case 12: fprintf(opf," for token %d",q1); break; case 13: fprintf(opf,": f = %d",q1); break; default: break; } fprintf(opf,"\n"); end_line(); } /*------------------------- TRACE LINE END -------------------------*/ static void end_line() { if ((--lft)==0) then { /* end of page/screen. for trace 1, advance page if print- */ /* er output; screen output is free-running. for trace 2, */ /* pause on full screen; for trace 3, pause after line. */ switch(tr) { case 1: if (opf==display) then lft=sl; else endpage(); break; case 2: if (mr) then {putchar('\n'); lft=sl; pause();} else endpage(); break; case 3: lft=sl; break; } } if (tr==3) then pause(); } /*----------------------------- PAUSE ------------------------------*/ void pause() { /* pause execution via 'mtr' call (if active) */ /* if (mr) then mtr(tr,1); else */ getchar(); } /*------------------ DISPLAY ERROR MESSAGE & EXIT ------------------*/ void error(int n, char *s) { FILE *dest; static char *m[8]={"Simulation Error at Time ", "Empty Element Pool", "Empty Name Space", "Facility Defined After Queue/Schedule", "Negative Event Time", "Empty Event List", "Preempted Token Not in Event List", "Release of Idle/Unowned Facility"}; dest=opf; while (1) { /* send messages to both printer and screen */ fprintf(dest,"\n**** %s%.3f\n",m[0],clock); if (n) fprintf(dest," %s\n",m[n]); if (s) fprintf(dest," %s\n",s); if (dest==display) then break; else dest=display; } if (opf!=display) then report(); /* if (mr) then mtr(0,1); */ exit(0); } /*------------------------ GENERATE REPORT -------------------------*/ void report() { newpage(); reportf(); endpage(); } /*-------------------- GENERATE FACILITY REPORT --------------------*/ void reportf() { int f; if ((f=fchn)==0) then fprintf(opf,"\nno facilities defined: report abandoned\n"); else { /* f = 0 at end of facility chain */ while(f) {f=rept_page(f); if (f>0) then endpage();} } } /*---------------------- GENERATE REPORT PAGE ----------------------*/ static int rept_page(int fnxt) { int f,i,n; char fn[19]; static char *s[7]={ "smpl SIMULATION REPORT", " MODEL: ", "TIME: ", "INTERVAL: ", "MEAN BUSY MEAN QUEUE OPERATION COUNTS", " FACILITY UTIL. ", " PERIOD LENGTH RELEASE PREEMPT QUEUE"}; fprintf(opf,"\n%51s\n\n\n",s[0]); fprintf(opf,"%-s%-54s%-s%11.3f\n",s[1],mname(),s[2],clock); fprintf(opf,"%68s%11.3f\n\n",s[3],clock-start); fprintf(opf,"%75s\n",s[4]); fprintf(opf,"%s%s\n",s[5],s[6]); f=fnxt; lft-=8; while (f && lft--) { n=0; for (i=f+2; i<=f+l1[f]+1; i++) n+=l3[i]; if (l1[f]==1) then sprintf(fn,"%s",fname(f)); else sprintf(fn,"%s[%d]",fname(f),l1[f]); fprintf(opf," %-17s%6.4f %10.3f %13.3f %11d %9d %7d\n", fn,U(f),B(f),Lq(f),n,(int)l4[f+1],(int)l4[f]); f=l2[f+1]; } return(f); } /*--------------------------- COUNT LINES --------------------------*/ int lns(int i) { lft-=i; if (lft<=0) then endpage(); return(lft); } /*---------------------------- END PAGE ----------------------------*/ void endpage() { /*int c,key;*/ if (opf==display) then { /* screen output: push to top of screen & pause */ while(lft>0) {putc('\n',opf); lft--;} /* printf("\n[ENTER] to continue:"); getchar(); */ /* if (mr) then clr_scr(); else */ printf("\n\n"); } else if (lft