®PL168.¯ The following files accompany the article entitled "The Qsim Simulation Toolkit," by Roy E. Kimbrell, Linda Correll, and Robert Bass, BYTE July 1989, page 259. ============================== EG1.C ============================== /* first example in the article */ #include #include "sim.h" #include "sim_lib.h" #include DEFINE_CREATE(customers); DEFINE_QUEUE(q_loan_officer); DEFINE_QUEUE(q_Biff); QUEUE_STRUCT *q_array[]={&q_loan_officer_q,&q_Biff_q}; #define NUM_QUEUES (sizeof(q_array)/sizeof(QUEUE_STRUCT *)) DEFINE_SERVICE(s_loan_officer); DEFINE_SERVICE(s_Biff); SERV_DATA *s_array[]={&s_loan_officer_s,&s_Biff_s}; #define NUM_SERVS (sizeof(s_array)/sizeof(SERV_DATA *)) void decision_1(ENTITY *); void decision_2(ENTITY *); void term(ENTITY *); void stop(void); void main(int ac,char **av) { long runtime=0; extern long strtol(); if (ac > 1) runtime = strtol(av[1],0,0); SCHEDULE(customers,0,0); SCHEDULE(stop,0,(double)runtime); engine(); } CREATE(customers,now,0,expon(15.0),q_loan_officer) QUEUE(q_loan_officer,s_loan_officer) SERVICE(s_loan_officer,2,unfrm(20.0,30.0),decision_1) void decision_1(ENTITY *entity) { TRACE(decision_1); /* debug code */ PR_ENTITY(entity); /* debug code */ if (drand() < .6) term(entity); else q_Biff(entity); } QUEUE(q_Biff,s_Biff) SERVICE(s_Biff,1,normal(45.0,10.0),decision_2) void decision_2(ENTITY *entity) { TRACE(decision_2); /* debug code */ PR_ENTITY(entity); /* debug code */ if (drand() < .85) term(entity); else q_loan_officer(entity); } static systime_t total_time, max_time, min_time = FLT_MAX; static unsigned count; void term(ENTITY *entity) { systime_t tis; TRACE(term); /* debug code */ PR_ENTITY(entity); /* debug code */ count++; tis = now - entity->time; total_time += tis; if (max_time < tis) max_time = tis; if (min_time > tis) min_time = tis; free(entity); } void stop(void) { int i; TRACE(stop); printf("Total time in system = %10.4f, count = %d\n", total_time,count); printf("Average time in system = %10.4f\n",total_time/count); printf("Max time in system = %10.4f\n",max_time); printf("Min time in system = %10.4f\n",min_time); printf("\nSERVICES: name|total|total busy|utilization|\n\ ---------------|-----|----------|-----------|\n"); for (i=0;iname, s_array[i]->total, s_array[i]->total_busy, (s_array[i]->srvtime) ? s_array[i]->total_busy/s_array[i]->srvtime : 0 ); printf("\nQUEUES: name|max_len|cur_len|total_wait|count|\ average_wait|\n\ ---------------|-------|-------|----------|-----|------------|\n"); for (i=0;iname, q_array[i]->max_len, q_array[i]->cur_len, q_array[i]->total_wait, q_array[i]->count, (q_array[i]->count) ? q_array[i]->total_wait/q_array[i]->count : 0 ); exit(0); } ============================== ERLANG.C ============================== #include #include "sim_lib.h" double erlang(double u,unsigned k) { double r=1; unsigned i; for (i=1; i #include "sim_lib.h" double expon(double mean) { return (-mean*log(drand())); } ============================== NORMAL.C ============================== #include #include "sim_lib.h" static flag=0; static double norm2, oldu, olds; double normal(double u,double s) { double r1, r2, a, b, w=2, norm1, t; if (flag & oldu == u & olds == s){ flag = 0; return norm2; } while (w > 1){ r1 = drand(); r2 = drand(); a = 2.0 * r1 - 1.0; b = 2.0 * r2 - 1.0; w = a*a + b*b; } t = sqrt(-2.0 * log(w)/w) * s; norm1 = a*t + u; norm2 = b*t + u; flag = 1; oldu = u; olds = s; return norm1; } ============================== RLNORM.C ============================== #include double normal(double,double); double rlnorm(double u,double s) { double sigma, mu; sigma = log(s*s/(u*u) + 1.0); mu = log(u) - sigma/2; return exp(normal(mu,sqrt(sigma))); } ============================== SIM.C ============================== /* sim.c -- simulation system code */ #include #include #define DEF_SPACE #include "sim.h" void engine(void) { EVENT *event; for(;;){ TRACE(engine); if (!(event = nextevent())) return; if (event->time > now) now = event->time; (*event->f)(event->entity); free(event); } } EVENT *nextevent(void) { EVENT *top; extern EVENT *sched; extern systime_t now; TRACE(nextevent); if (top = sched) sched = sched->next; return top; } ENTITY *create(systime_t time,double feature) { ENTITY *new; extern id_t entity_id; TRACE(create); new = (ENTITY *)calloc(1,sizeof(ENTITY)); new->id = entity_id++; new->time = time; new->feature[0] = feature; return new; } void sdump(void) { EVENT *sp; extern EVENT *sched; sp = sched; while (sp){ #ifdef DEBUG printf("\tevent=%x, time=%f, f=%s, next=%x, entity=%x\n", sp,sp->time,sp->fs,sp->next,sp->entity); #else printf("\tevent=%x, time=%f, next=%x, entity=%x\n", sp,sp->time,sp->next,sp->entity); #endif if (sp->entity) printf("\tevent->entity->id=%ld, time=%f, feature[0]=%d\n", sp->entity->id,sp->entity->time,sp->entity->feature[0]); printf("\n"); sp = sp->next; } } #ifdef DEBUG void schedule(void (*f)(), char *fs, ENTITY *entity, systime_t time) #else void schedule(void (*f)(), ENTITY *entity, systime_t time) #endif { EVENT *sp, *event, *temp, *prev; extern EVENT *sched; TRACE(schedule); event = (EVENT *)calloc(1,sizeof(EVENT)); event->time = time; #ifdef DEBUG event->fs = fs; #endif event->f = f; event->entity = entity; if (!sched){ sched = event; SDUMP(); return; } if (sched->time > time){ temp = sched; sched = event; event->next = temp; SDUMP(); return; } sp = sched; while (sp && time >= sp->time){ prev = sp; sp = sp->next; } prev->next = event; event->next = sp; SDUMP(); return; } void qdump(QUEUE_STRUCT *q) { ENTITY * ep; printf("\t* qdump: max= %d, current = %d, min=%d *\n", q->max_len,q->cur_len,q->min_len); ep = q->top; while (ep){ PR_ENTITY(ep); ep = ep->next; } printf("\t* end of dump *\n"); } ENTITY *topq(QUEUE_STRUCT *q) { return q->top; } void nq(q,entity) QUEUE_STRUCT * q; ENTITY * entity; { entity->next = (ENTITY *)0; if (q->end){ q->end->next = entity; q->end = entity; } else q->top = q->end = entity; q->count++; entity->qtime = now; q->cur_len++; if (q->max_len < q->cur_len) q->max_len = q->cur_len; #ifdef DEBUG qdump(q); #endif } ENTITY *dq(QUEUE_STRUCT *q) { ENTITY * p; p = q->top; if (p) q->top = q->top->next; if (p == q->end) q->end = (ENTITY *)0; if (p){ q->total_wait += now - p->qtime; q->cur_len--; if (q->min_len > q->cur_len) q->min_len = q->cur_len; } #ifdef DEBUG qdump(q); #endif return p; } ============================== SIM.H ============================== /* sim.h -- simulation system definitions */ typedef long id_t; typedef double systime_t; struct entity { id_t id; systime_t time, qtime; double feature[1]; struct entity * next; }; typedef struct entity ENTITY; struct event{ systime_t time; #ifdef DEBUG char *fs; #endif void (*f)(); ENTITY *entity; struct event *next; }; typedef struct event EVENT; struct queue{ char * name; ENTITY *top, *end; unsigned short max_len, cur_len, min_len, count; systime_t total_wait; }; typedef struct queue QUEUE_STRUCT; struct serv_data{ char * name; unsigned long total; double total_busy, srvtime; }; typedef struct serv_data SERV_DATA; void sdump(); #ifdef DEBUG void schedule(void(*)(),char *,ENTITY *,systime_t /* time */); #else void schedule(void(*)(),ENTITY *,systime_t /* time */); #endif void engine(); EVENT *nextevent(); ENTITY *create(systime_t /* time of creation */,double /* feature */); ENTITY *topq(QUEUE_STRUCT * /* entity queue */), *dq(QUEUE_STRUCT * /* entity queue */); void nq(QUEUE_STRUCT * /* entity queue */, ENTITY *); #ifndef DEF_SPACE extern double now; /* current time in system */ extern EVENT *sched; extern id_t entity_id; #else double now; /* current time in system */ EVENT *sched; id_t entity_id; #endif #ifdef DEBUG #define TRACE(name) printf("%f " #name "\n",now); #define SDUMP() sdump() #define PR_ENTITY(entity) \ if (entity) printf("\tentity: id=%ld, time=%f, feature=%f, next=%x\n",\ entity->id,entity->time,entity->feature[0],entity->next);\ else printf("\tentity=0\n"); #else #define TRACE(name) #define SDUMP() #define PR_ENTITY(entity) #endif #ifdef DEBUG #define SCHEDULE(name,entity,time) \ schedule(name,#name,(ENTITY *)(entity),(systime_t)(time)); #else #define SCHEDULE(name,entity,time) \ schedule(name,(ENTITY *)(entity),(systime_t)(time)); #endif #define DEFINE_CREATE(name) \ void name(); #define CREATE(name,create_time,feature,create_freq,service) \ void name()\ {\ extern systime_t now;\ TRACE(name);\ service(create((systime_t)create_time,(double)feature));\ SCHEDULE(name,0,now+create_freq);\ } #define DEFINE_SERVICE(name) \ systime_t name(ENTITY *);\ SERV_DATA name##_s={#name}; #define SERVICE(name,nservers,delay,next) \ double name(entity)\ ENTITY *entity;\ {\ static systime_t srvtime[nservers], wait_time;\ extern systime_t now;\ unsigned short i;\ TRACE(name);\ PR_ENTITY(entity);\ for (i=0;i= 0){\ dq(&name##_q);\ SCHEDULE(name,0,srvtime);\ }\ /* compute statistics */\ } ============================== SIM_LIB.H ============================== /* sim_lib.h function definitions for the statistical simulation library u - mean s - standard deviation k - number of samples a, b - limits mode - middle or peak of a triangular distribution */ double erlang(double u, unsigned k); double expon(double u); double normal(double u, double s); double rlnorm(double u, double s); double triag(double a, double mode, double b); double unfrm(double a, double b); double drand(void); ============================== TRIAG.C ============================== #include #include "sim_lib.h" double triag(double a,double mode,double b) { double r; r = drand(); if (r <= (mode-a)/(b-a)) return a + sqrt((mode-a)*(b-a)*r); else return b - sqrt((b-mode)*(b-a)*(1-r)); } ============================== UNFRM.C ============================== #include #include #include "sim_lib.h" #define min(a,b) (((a) < (b)) ? (a) : (b)) double unfrm(double a,double b) { return (drand()*fabs(a-b)+min(a,b)); }