/***************************************************************************** ** ** Simulation of a Closed Queueing Network with FCFS servers ** (revised by Mineo Takai) ** This is simulation of a closed network with N fully connected ** switches. Each switch is a tandem queue of Q fifo servers. ** A job that arrives at a queue is served sequentially (FCFS) ** by the Q servers and is thereafter routed to one of the ** N neighboring switches (including itself) with equal probability. ** ** Entities defined in the program: ** (1) driver: initiate the simulation ** (2) router: distributing jobs to N neighbors ** (3) queue: model the tandem queue ** *****************************************************************************/ #include #include #define MAXROUTERS 128 #define REPORT_STAT 0 enum {False = 0, True}; entity router(ename, int, int, int); entity queue(ename, ename, clocktype, clocktype, int, int); clocktype ShiftedExpon(clocktype, clocktype, unsigned short [3]); int SelectQueue(int, int, unsigned short [3]); message JobMsg { clocktype ArrivedTime; }; message FirstQueuesMsg { ename Ename[MAXROUTERS]; }; message RoutersMsg { ename Ename[MAXROUTERS]; }; message SourceMsg { ename Ename; }; message ReadyToStartMsg { /* empty */ }; message StartMsg { /* empty */ }; /* ------------------------------------------------------------------------- driver(int argc, char **argv) Creates "NumRouters" routers and "NumQueues" queues for each router. Parameters are taken up from the command line. The default setting is: NumRouters = 16 NumQueues = 5 NumJobs = 96 (initial number of jobs for a router) MeanTime = 10 (mean service time for a job on a queue) MaxSimClock = 30000 ------------------------------------------------------------------------- */ entity driver(int argc, char **argv) { ename *EnameArray[MAXROUTERS]; message FirstQueuesMsg FirstQueues; message RoutersMsg Routers; int i, j; int NumRouters, NumQueues, NumJobs, MeanTime, MaxSimClock; if (argc < 5) { if (argc != 1) { fprintf(stderr, "Not enough number of parameters\n" "Use default set of parameters\n"); } NumRouters = 16; NumQueues = 5; NumJobs = 96; MeanTime = 10; MaxSimClock = 30000; } else { sscanf(argv[1], "%d", &NumRouters); sscanf(argv[2], "%d", &NumQueues); sscanf(argv[3], "%d", &NumJobs); sscanf(argv[4], "%d", &MeanTime); sscanf(argv[5], "%d", &MaxSimClock); } printf("CQNF Configuration simulated:\n"); printf(" Number of routers = %d\n", NumRouters); printf(" Number of queues/router = %d\n", NumQueues); printf(" Number of jobs/router = %d\n", NumJobs); printf(" Average job servicing time = %d\n", MeanTime); printf(" Maximum simulation clock = %d\n", MaxSimClock); if (NumQueues < 1 || NumRouters < 1){ printf("Number of queues and routers must be more than 1\n"); return; } for (i = 0; i < NumRouters; i++) { EnameArray[i] = (ename *)calloc(NumQueues + 1, sizeof(ename)); if (EnameArray[i] == NULL) { pc_printf("Run out of memory to make an array of enames\n"); } } setmaxclock(MaxSimClock); /*** Create "NumRouters" router entities ***/ /*** Save the enames to EnameArray[*][0] ***/ for (i = 0; i < NumRouters; i++) { EnameArray[i][0] = new router(self, i, NumJobs, NumRouters) at i; add_source(EnameArray[i][0]); } /*** Create "NumQueues" queue entities ***/ /*** Save the enames to EnameArray[*][1 -- NumQueues] ***/ for (i = 0; i < NumRouters; i++) { /*** The last queue sends jobs to the router entity ***/ EnameArray[i][NumQueues] = new queue(self, EnameArray[i][0], 1, MeanTime, i * NumQueues + j, NumRouters) at i; add_source(EnameArray[i][NumQueues]); for (j = NumQueues - 1; j > 0; j--){ EnameArray[i][j] = new queue(self, EnameArray[i][j + 1], 1, MeanTime, i * NumQueues + j, NumRouters) at i; add_source(EnameArray[i][j]); } } /*** Make a message that contains all the enames ***/ /*** of the first queue of the tandem queues ***/ for (i = 0; i < NumRouters; i++) { FirstQueues.Ename[i] = EnameArray[i][1]; } /*** Send out Dests to all the routers ***/ for (i = 0; i < NumRouters; i++) { send FirstQueues to EnameArray[i][0]; } /*** For parallel execution, notify the entities ***/ /*** of the enames of source entities ***/ /*** Send out Source message to entities ***/ /*** which has only one source entity ***/ for (i = 0; i < NumRouters; i++) { send SourceMsg{EnameArray[i][NumQueues]} to EnameArray[i][0]; } for (i = 0; i < NumRouters; i++) { for (j = 2; j <= NumQueues; j++) { send SourceMsg{EnameArray[i][j - 1]} to EnameArray[i][j]; } } /*** Make a message that contains all the enames ***/ /*** of the routers ***/ for (i = 0; i < NumRouters; i++) { Routers.Ename[i] = EnameArray[i][0]; } /*** Send out Sources to the first queue ***/ for (i = 0; i < NumRouters; i++) { send Routers to EnameArray[i][1]; } /*** Receive acknowledgement from all the entities ***/ for (i = 0; i < NumRouters; i++) { for (j = 0; j <= NumQueues; j++){ receive (ReadyToStartMsg finish); } } /*** Start off the simulation ***/ for (i = 0; i < NumRouters; i++) { for (j = 0; j <= NumQueues; j++) { send StartMsg{} to EnameArray[i][j]; } } } /* ------------------------------------------------------------------------- entity router(ename Creator, int RouterID, int NumJobs, int NumRouters) ename Creator: ename of the parent entity int RouterID: ID number of the router int NumJobs: Number of jobs at the beginning of simulation int NumRouters: Total number of routers ------------------------------------------------------------------------- */ entity router(ename Creator, int RouterID, int NumJobs, int NumRouters) { int i; unsigned short seed[3]; ename FirstQueueEnames[MAXROUTERS]; int DestQueueID; ename source; int NumRoutedJobs = 0; /*** Initialize seed values for the random numbers ***/ seed[0] = 1; seed[1] = RouterID; seed[2] = RouterID; add_dest(Creator); receive (FirstQueuesMsg FirstQueues) { for (i = 0; i < NumRouters; i++) { FirstQueueEnames[i] = FirstQueues.Ename[i]; add_dest(FirstQueueEnames[i]); } } receive (SourceMsg Source) { source = Source.Ename; } add_source(source); send ReadyToStartMsg{} to Creator; receive (StartMsg Start); del_dest(Creator); del_source(Creator); /*** Start simulation ***/ for (i = 0; i < NumJobs; i++) { DestQueueID = SelectQueue(0, NumRouters - 1, seed); send JobMsg { simclock() } to FirstQueueEnames[DestQueueID]; NumRoutedJobs++; } while (1) { setlookahead(1, CLOCKTYPE_MAX); receive (JobMsg Job) { message JobMsg NewJob; NewJob = Job; NewJob.ArrivedTime = simclock() + 1; DestQueueID = SelectQueue(0, NumRouters - 1, seed); send NewJob to FirstQueueEnames[DestQueueID] after 1; NumRoutedJobs++; } } finalize { if (REPORT_STAT) { pc_printf("Router (%d):\n" " Number of jobs routed: %d\n", RouterID, NumRoutedJobs); } } } /* ------------------------------------------------------------------------- entity queue(Creator, Dest, LowestServiceTime, MeanTime, QueueID, NumRouters) ename Creator: ename of the parent entity ename Dest: ename of the entity to send out messages clocktype LowestServiceTime: lower bound of the service time clocktype MeanTime: mean service time for a job int QueueID: ID number of the queue int NumRouters: Total number of routers ------------------------------------------------------------------------- */ entity queue(ename Creator, ename Dest, clocktype LowestServiceTime, clocktype MeanTime, int QueueID, int NumRouters) { unsigned short seed[3]; int ServiceTime; ename source[MAXROUTERS]; clocktype LastTimeFinishedJob = 0; clocktype IdleTime = 0; int NumServicedJobs = 0; clocktype WaitedTime = 0; /*** Initialize seed values for the random numbers ***/ seed[0] = 1; seed[1] = QueueID; seed[2] = QueueID; add_dest(Creator); add_dest(Dest); receive (SourceMsg Source) { add_source(Source.Ename); } or receive (RoutersMsg Routers) { int i; for (i = 0; i < NumRouters; i++) { add_source(Routers.Ename[i]); } } send ReadyToStartMsg {} to Creator; ServiceTime = ShiftedExpon(MeanTime - LowestServiceTime, LowestServiceTime, seed); #ifndef NO_PRESAMPLING setlookahead(ServiceTime, CLOCKTYPE_MAX); #else setlookahead(LowestServiceTime, CLOCKTYPE_MAX); #endif receive (StartMsg start); del_dest(Creator); del_source(Creator); for (;;) { #ifndef NO_PRESAMPLING setlookahead(ServiceTime, CLOCKTYPE_MAX); #else setlookahead(LowestServiceTime, CLOCKTYPE_MAX); #endif receive (JobMsg Job) { message JobMsg NewJob = Job; NumServicedJobs++; if (simclock() > LastTimeFinishedJob) { IdleTime += simclock() - LastTimeFinishedJob; } WaitedTime += simclock() - Job.ArrivedTime; hold(ServiceTime); LastTimeFinishedJob = simclock(); NewJob.ArrivedTime = simclock(); send NewJob to Dest; } ServiceTime = ShiftedExpon(MeanTime - LowestServiceTime, LowestServiceTime, seed); } finalize { if (REPORT_STAT) { pc_printf("Queue (%d):\n" " Number of jobs serviced: %d\n" " Average waiting time for jobs to be serviced: %f\n" " Idle time during the simulation: %d\n", QueueID, NumServicedJobs, (float)WaitedTime / (float)NumServicedJobs, IdleTime); } } } /* ------------------------------------------------------------------------- int SelectQueue(int LowestID, int HighestID, unsigned short seed[3]) int LowestID: Lowest ID number generated int HighestID: Highest ID number generated unsigned short seed[3]: Random number seeds ------------------------------------------------------------------------- */ int SelectQueue(int LowestID, int HighestID, unsigned short seed[3]) { const long RandomValue = pc_nrand(seed); int Diff; int Base; if (LowestID < 0 || HighestID < 0) { fprintf(stderr, "ID number should be positive\n"); exit(0); } else if (LowestID == HighestID) { return LowestID; } else if (LowestID > HighestID) { Diff = LowestID - HighestID; Base = HighestID; } else { Diff = HighestID - LowestID; Base = LowestID; } return (int)(RandomValue % (Diff + 1)) + Base; } /* ------------------------------------------------------------------------- clocktype ShiftedExpon(ExponMean, ShiftTime, seed) clocktype ExponMean: Mean value of exponantial distribution clocktype ShiftTime: Constant value unsigned short seed[3]: Random number seeds ------------------------------------------------------------------------- */ clocktype ShiftedExpon(clocktype ExponMean, clocktype ShiftTime, unsigned short seed[3]) { double ExponValue = -log(1.0 - pc_erand(seed)) * ExponMean; return (clocktype)(ExponValue + 0.5 + (double)ShiftTime); }