//int PDQ_CreateNode(char *name, int device, int sched) void PDQ_CreateNode(char *name, int device, int sched) { extern NODE_TYPE *node; extern char s1[], s2[]; extern int nodes; extern int PDQ_DEBUG; char *p = "PDQ_CreateNode"; FILE* out_fd; if (PDQ_DEBUG) { debug(p, "Entering"); out_fd = fopen("PDQ.out", "a"); fprintf(out_fd, "name : %s device : %d sched : %d\n", name, device, sched); //PJP this really needed to be fclose //close(out_fd); fclose(out_fd); } if (k > MAXNODES) { sprintf(s1, "Allocating \"%s\" exceeds %d max nodes", name, MAXNODES); errmsg(p, s1); } if (strlen(name) >= MAXCHARS) { sprintf(s1, "Nodename \"%s\" is longer than %d characters", name, MAXCHARS); errmsg(p, s1); } strcpy(node[k].devname, name); if (sched == MSQ && device < 0) { // interpret node as multiserver and // number of servers must be positive integer sprintf(s1, "Must specify MSQ node with CEN equal to positive number of servers"); errmsg(p, s1); } node[k].devtype = device; node[k].sched = sched; if (PDQ_DEBUG) { typetostr(s1, node[k].devtype); typetostr(s2, node[k].sched); PRINTF("\tNode[%d]: %s %s \"%s\"\n", k, s1, s2, node[k].devname); resets(s1); resets(s2); }; if (PDQ_DEBUG) debug(p, "Exiting"); // update global node count k = ++nodes; } // PDQ_CreateNode
int getnode_index(char *name) { char *p = "getnode_index()"; extern char s1[]; int k = 0; if (PDQ_DEBUG) debug(p, "Entering"); for (k = 0; k < nodes; k++) { if (strcmp(node[k].devname, name) == 0) { if (PDQ_DEBUG) { resets(s1); sprintf(s1, "node:\"%s\" index: %d", name, k); debug(p, s1); resets(s1); debug(p, "Exiting"); } return (k); } } /* if you are here, you're in deep yoghurt! */ resets(s1); sprintf(s1, "Node name \"%s\" not found at index: %d", name, k); errmsg(p, s1); g_debug("[getnode_index] Bad return value"); return -1; } /* getnode_index */
int getjob_index(char *wname) { char *p = "getjob_index()"; extern char s1[]; int n = 0; if (PDQ_DEBUG) debug(p, "Entering"); // g_debugf("=====> wname -> \"%s\"\n", wname); if (wname) { for (n = 0; n < streams; n++) { char *job_term_name; if (0) { g_debugf("n[%d] &job[%p]\n", n, &(job[n])); g_debugf("job[]:[%p]\n", &(job[n])); g_debugf("job[].term:[%p]\n", &(job[n].term)); g_debugf("job[].term->name:[%s]\n", job[n].term->name); } if (job[n].term) job_term_name = job[n].term->name; else job_term_name = "UNDEFINED"; // g_debugf("job_term_name:[%s]\n", job_term_name); if ((strcmp(job_term_name, wname) == 0) || (strcmp(job[n].batch->name, wname) == 0) || (strcmp(job[n].trans->name, wname) == 0)) { if (PDQ_DEBUG) { resets(s1); sprintf(s1, "stream:\"%s\" index: %d", wname, n); debug(p, s1); resets(s1); debug(p, "Exiting"); } return (n); } } } // g_debug("*** CRITICAL *** function needs to return something!\n"); return -1; } /* getjob_index */
void namex(int i, char *s, char *r) /* append index i to string s and return it in r */ { extern char s1[], s2[]; extern void resets(); resets(r); resets(s1); resets(s2); strcpy(s1, s); itoa(i, s2); strcat(s1, s2); strcpy(r, s1); }
void create_batch_stream(int net, char* label, double number) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; char *p = "create_batch_stream()"; if (PDQ_DEBUG) debug(p, "Entering"); /***** using global value of n *****/ strcpy(job[c].batch->name, label); job[c].should_be_class = BATCH; job[c].network = net; job[c].batch->pop = number; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s \"%s\"; N: %3.1f\n", c, s1, job[c].batch->name, job[c].batch->pop); resets(s1); } if (PDQ_DEBUG) debug(p, "Exiting"); } // create_batch_stream
void create_term_stream(int circuit, char *label, double pop, double think) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; char *p = "create_term_stream()"; if (PDQ_DEBUG) debug(p, "Entering"); strcpy(job[c].term->name, label); job[c].should_be_class = TERM; job[c].network = circuit; job[c].term->think = think; job[c].term->pop = pop; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s \"%s\"; N: %3.1f, Z: %3.2f\n", c, s1, job[c].term->name, job[c].term->pop, job[c].term->think ); resets(s1); } if (PDQ_DEBUG) debug(p, "Exiting"); } // create_term_stream
void PDQ_SetTUnit(char* unitName) { extern char tUnit[]; extern int streams; char *p = "PDQ_SetTUnit()"; // Flag this, otherwise a user may not know why their units don't show up // in the PDQ report. if (streams == 0) { errmsg(p, "Must call CreateOpen or CreateClosed first\n"); } if (strlen(unitName) > 10) errmsg(p, "Name > 10 characters"); resets(tUnit); strcpy(tUnit, unitName); } // PDQ_SetTUnit
void WidgetGL::keyPressEvent(QKeyEvent *e) { switch( e->key() ) { case Qt::Key_Space: { resets(); } break; case Qt::Key_F: m_fullscreen = !m_fullscreen; fullScreen(m_fullscreen); updateGL(); break; case Qt::Key_L://是否使用色彩混合,高亮 { blend = !blend; if(blend) { glEnable(GL_BLEND);//色彩融合和深度缓存不能同时开启 glDisable(GL_DEPTH_TEST); } else { glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); } updateGL(); } break; case Qt::Key_Z: { bAnimate = !bAnimate; if( bAnimate ) timer->start(40); else timer->stop(); } break; case Qt::Key_Escape: close(); } }
//------------------------------------------------------------------------- // Subroutines //------------------------------------------------------------------------- void create_transaction(int net, char* label, double lambda) { extern JOB_TYPE *job; extern char s1[]; extern int PDQ_DEBUG; strcpy(job[c].trans->name, label); job[c].should_be_class = TRANS; job[c].network = net; job[c].trans->arrival_rate = lambda; if (PDQ_DEBUG) { typetostr(s1, job[c].should_be_class); PRINTF("\tStream[%d]: %s\t\"%s\";\tLambda: %3.1f\n", c, s1, job[c].trans->name, job[c].trans->arrival_rate); resets(s1); } } // create_transaction
void PDQ_Init(char *name) { extern char model[]; extern char s1[]; extern char tUnit[]; extern char wUnit[]; extern int demand_ext; extern int method; extern double tolerance; // These 3 globals are reset = 0 at the end of this proc extern int nodes; extern int streams; extern int demands; // set = 1 by SetDemand() extern int prev_init; extern NODE_TYPE *node; extern JOB_TYPE *job; extern TERMINAL_TYPE *tm; extern BATCH_TYPE *bt; extern TRANSACTION_TYPE *tx; extern SYSTAT_TYPE *sys; extern int PDQ_DEBUG; extern void allocate_nodes(); extern void allocate_jobs(); char *p = "PDQ_Init()"; if (PDQ_DEBUG) debug(p, "Entering"); if (strlen(name) > MAXCHARS) { resets(s1); sprintf(s1, "Model name > %d characters", MAXCHARS); errmsg(p, s1); } // There may be multiple Inits in the same model if (prev_init) { for (c = 0; c < MAXSTREAMS; c++) { if (job[c].term) { if (job[c].term->sys) { PDQ_FREE(job[c].term->sys); job[c].term->sys = NULL; job[c].batch->sys = NULL; job[c].trans->sys = NULL; } PDQ_FREE(job[c].term); job[c].term = NULL; } if (job[c].batch) { if (job[c].batch->sys) { PDQ_FREE(job[c].batch->sys); job[c].term->sys = NULL; job[c].batch->sys = NULL; job[c].trans->sys = NULL; } PDQ_FREE(job[c].batch); job[c].batch = NULL; } if (job[c].trans) { if (job[c].trans->sys) { PDQ_FREE(job[c].trans->sys); job[c].term->sys = NULL; job[c].batch->sys = NULL; job[c].trans->sys = NULL; } PDQ_FREE(job[c].trans); job[c].trans = NULL; } } // over c loop if (job) { PDQ_FREE(job); job = NULL; } if (node) { PDQ_FREE(node); node = NULL; } resets(model); resets(wUnit); resets(tUnit); } // Copy user-supplied name string into PDQ global model[] strcpy(model, name); Comment[0] = '\0'; // NULL string demand_ext = VOID; method = VOID; tolerance = TOL; allocate_nodes(MAXNODES+1); allocate_jobs(MAXSTREAMS+1); /********************************************************************************** On 12/6/06 John Strunk (Carnegie Mellon Univ.) sent the following comment: "My code analyzes a large number of models within a single invocation, so I call PDQ::Init to re-init the state before each model is analyzed. Unfortunately, a large portion of execution time (of my whole program) is spent in PDQ_Init, and I've tracked it down to the nested loop at PDQ_Build.c:130. Perhaps it would be possible to remove this set of loops entirely since calloc in allocate_*() right above that inits the memory to zero. These changes can provide a 6x speedup in my application." for (cc = 0; cc < MAXSTREAMS; cc++) { for (kk = 0; kk < MAXNODES; kk++) { node[kk].devtype = VOID; node[kk].sched = VOID; node[kk].demand[cc] = 0.0; node[kk].resit[cc] = 0.0; node[kk].qsize[cc] = 0.0; } job[cc].should_be_class = VOID; job[cc].network = VOID; } NJG on Tue, Apr 3, 2007 Since the speedup would be nearly an order of magnitude, it's worth a try. I was probably being overly defensive when I originally zeroed out every array element. After commenting out the above loops, a simple PDQ test (no re-Init calls), does not reveal any integrity problems. The VOID constant in PDQ_Lib.h also set to zero instead of -1. **********************************************************************************/ // reset circuit counters nodes = streams = demands = 0; c = k = 0; prev_init = TRUE; if (PDQ_DEBUG) { debug(p, "Exiting"); } } /* PDQ_Init */
//------------------------------------------------------------------------- int PDQ_CreateClosed_p(char *name, int should_be_class, double *pop, double *think) { extern char s1[]; extern int streams; extern char tUnit[]; extern char wUnit[]; extern int PDQ_DEBUG; char *p = "PDQ_CreateClosed()"; FILE *out_fd; if (PDQ_DEBUG) { debug(p, "Entering"); out_fd = fopen("PDQ.out", "a"); fprintf(out_fd, "name : %s should_be_class : %d pop : %f think : %f\n", name, should_be_class, *pop, *think); //PJP This really should be fclose //close(out_fd); fclose(out_fd); } if (strlen(name) >= MAXCHARS) { sprintf(s1, "Nodename \"%s\" is longer than %d characters", name, MAXCHARS); errmsg(p, s1); } if (c > MAXSTREAMS) { PRINTF("c = %d\n", c); sprintf(s1, "Allocating \"%s\" exceeds %d max streams", name, MAXSTREAMS); errmsg(p, s1); } switch (should_be_class) { case TERM: if (*pop == 0.0) { resets(s1); sprintf(s1, "Stream: \"%s\", has zero population", name); errmsg(p, s1); } create_term_stream(CLOSED, name, *pop, *think); // Set default units strcpy(wUnit, "Users"); strcpy(tUnit, "Sec"); break; case BATCH: if (*pop == 0.0) { resets(s1); sprintf(s1, "Stream: \"%s\", has zero population", name); errmsg(p, s1); } create_batch_stream(CLOSED, name, *pop); // Set default units strcpy(wUnit, "Jobs"); strcpy(tUnit, "Sec"); break; default: sprintf(s1, "Unknown stream: %d", should_be_class); errmsg(p, s1); break; } if (PDQ_DEBUG) debug(p, "Exiting"); c = ++streams; return(0); // silence gcc warnings } // PDQ_CreateClosed
void PDQ_CreateMultiserverClosed(int servers, char *name, int device, int sched) { extern NODE_TYPE *node; extern char s1[], s2[]; extern int nodes; extern int PDQ_DEBUG; FILE* out_fd; char *p = "PDQ_CreateMultiserverClosed"; // hack to force FESC node type //sched = FESC; //device = servers; if (PDQ_DEBUG) { debug(p, "Entering"); out_fd = fopen("PDQ.out", "a"); fprintf(out_fd, "name : %s device : %d sched : %d\n", name, device, sched); //The following should really be fclose // close(out_fd); fclose(out_fd); } if (streams > 1) { sprintf(s1, "Only single workload allowed with CreateMultiserverClosed()\n"); errmsg(p, s1); } if (k > 1) { sprintf(s1, "Allocating \"%s\" exceeds %d max nodes", name, MAXNODES); errmsg(p, s1); } if (strlen(name) >= MAXCHARS) { sprintf(s1, "Nodename \"%s\" is longer than %d characters", name, MAXCHARS); errmsg(p, s1); } strcpy(node[k].devname, name); if (servers <= 0) { // number of servers must be positive integer sprintf(s1, "Must specify a positive number of servers"); errmsg(p, s1); } // Added by NJG on Dec 29, 2018 node[k].devtype = device; node[k].sched = sched; node[k].servers = servers; if (PDQ_DEBUG) { typetostr(s1, node[k].devtype); typetostr(s2, node[k].sched); PRINTF("\tNode[%d]: %s %s \"%s\"\n", k, s1, s2, node[k].devname); resets(s1); resets(s2); }; if (PDQ_DEBUG) debug(p, "Exiting"); // update global node count k = ++nodes; } // PDQ_CreateMultiserverClosed
void approx(void) { extern int PDQ_DEBUG, iterations, streams, nodes; extern char s1[], s2[], s3[], s4[]; extern double tolerance; extern JOB_TYPE *job; extern NODE_TYPE *node; extern void typetostr(); extern void getjob_name(); int k, c; int should_be_class; double sumQ(); double sumR[MAXSTREAMS]; double delta = 2 * TOL; int iterate; char jobname[MAXBUF]; NODE_TYPE *last; char *p = "approx()"; if (PDQ_DEBUG) debug(p, "Entering"); if (nodes == 0 || streams == 0) errmsg(p, "Network nodes and streams not defined."); #ifndef __R_PDQ if ((last = (NODE_TYPE *) calloc(sizeof(NODE_TYPE), nodes)) == NULL) #else if ((last = (NODE_TYPE *) Calloc((size_t) nodes, NODE_TYPE )) == NULL) #endif errmsg(p, "Node (last) allocation failed!\n"); iterations = 0; if (PDQ_DEBUG) { sprintf(s1, "\nIteration: %d", iterations); debug(p, s1); resets(s1); } /* initialize all queues */ for (c = 0; c < streams; c++) { should_be_class = job[c].should_be_class; for (k = 0; k < nodes; k++) { switch (should_be_class) { case TERM: last[k].qsize[c] = node[k].qsize[c] = job[c].term->pop / nodes; break; case BATCH: last[k].qsize[c] = node[k].qsize[c] = job[c].batch->pop / nodes; break; default: break; } if (PDQ_DEBUG) { getjob_name(jobname, c); sprintf(s2, "Que[%s][%s]: %3.4f (D=%f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s2); resets(jobname); } } /* over k */ } /* over c */ do { iterations++; if (PDQ_DEBUG) { sprintf(s1, "\nIteration: %d", iterations); debug(p, s1); resets(s1); } for (c = 0; c < streams; c++) { getjob_name(jobname, c); sumR[c] = 0.0; if (PDQ_DEBUG) { sprintf(s1, "\nStream: %s", jobname); debug(p, s1); resets(s1); } should_be_class = job[c].should_be_class; for (k = 0; k < nodes; k++) { if (PDQ_DEBUG) { sprintf(s2, "Que[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s1); } /* approximate avg queue length */ switch (should_be_class) { double N; case TERM: N = job[c].term->pop; node[k].avqsize[c] = sumQ(k, c) + (node[k].qsize[c] * (N - 1.0) / N); break; case BATCH: N = job[c].batch->pop; node[k].avqsize[c] = sumQ(k, c) + (node[k].qsize[c] * (N - 1.0) / N); break; default: typetostr(s1, should_be_class); sprintf(s2, "Unknown should_be_class: %s", s1); errmsg(p, s2); resets(s2); break; } if (PDQ_DEBUG) { sprintf(s2, "<Q>[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].avqsize[c], delta ); debug(p, s2); resets(s2); } /* residence times */ switch (node[k].sched) { case FCFS: case PSHR: case LCFS: node[k].resit[c] = node[k].demand[c] * (node[k].avqsize[c] + 1.0); break; case ISRV: node[k].resit[c] = node[k].demand[c]; break; default: typetostr(s1, node[k].sched); sprintf(s2, "Unknown queue type: %s", s1); errmsg(p, s2); break; } sumR[c] += node[k].resit[c]; if (PDQ_DEBUG) { PRINTF("\tTot ResTime[%s] = %3.4f\n", jobname, sumR[c]); PRINTF("\tnode[%s].qsize[%s] = %3.4f\n", node[k].devname, jobname, node[k].qsize[c] ); PRINTF("\tnode[%s].demand[%s] = %3.4f\n", node[k].devname, jobname, node[k].demand[c] ); PRINTF("\tnode[%s].resit[%s] = %3.4f\n", node[k].devname, jobname, node[k].resit[c] ); } } /* over k */ /* system throughput, residency & response-time */ switch (should_be_class) { case TERM: job[c].term->sys->thruput = (job[c].term->pop / (sumR[c] + job[c].term->think)); job[c].term->sys->response = (job[c].term->pop / job[c].term->sys->thruput) - job[c].term->think; job[c].term->sys->residency = job[c].term->pop - (job[c].term->sys->thruput * job[c].term->think); if (PDQ_DEBUG) { sprintf(s2, "\tTERM<X>[%s]: %5.4f", jobname, job[c].term->sys->thruput); debug(p, s2); resets(s2); sprintf(s2, "\tTERM<R>[%s]: %5.4f", jobname, job[c].term->sys->response); debug(p, s2); resets(s2); } break; case BATCH: job[c].batch->sys->thruput = job[c].batch->pop / sumR[c]; job[c].batch->sys->response = (job[c].batch->pop / job[c].batch->sys->thruput); job[c].batch->sys->residency = job[c].batch->pop; if (PDQ_DEBUG) { sprintf(s2, "\t<X>[%s]: %3.4f", jobname, job[c].batch->sys->thruput); debug(p, s2); resets(s2); sprintf(s2, "\t<R>[%s]: %3.4f", jobname, job[c].batch->sys->response); debug(p, s2); resets(s2); } break; default: sprintf(s1, "Unknown should_be_class: %s", should_be_class); errmsg(p, s1); break; } resets(jobname); } /* over c */ /* update queue sizes */ for (c = 0; c < streams; c++) { getjob_name(jobname, c); should_be_class = job[c].should_be_class; iterate = FALSE; if (PDQ_DEBUG) { sprintf(s1, "Updating queues of \"%s\"", jobname); PRINTF("\n"); debug(p, s1); resets(s1); } for (k = 0; k < nodes; k++) { switch (should_be_class) { case TERM: node[k].qsize[c] = job[c].term->sys->thruput * node[k].resit[c]; break; case BATCH: node[k].qsize[c] = job[c].batch->sys->thruput * node[k].resit[c]; break; default: sprintf(s1, "Unknown should_be_class: %s", should_be_class); errmsg(p, s1); break; } /* check convergence */ delta = fabs((double) (last[k].qsize[c] - node[k].qsize[c])); if (delta > tolerance) /* for any node */ iterate = TRUE; /* but complete all queue updates */ last[k].qsize[c] = node[k].qsize[c]; if (PDQ_DEBUG) { sprintf(s2, "Que[%s][%s]: %3.4f (D=%1.5f)", node[k].devname, jobname, node[k].qsize[c], delta); debug(p, s2); resets(s2); } } /* over k */ resets(jobname); } /* over c */ if (PDQ_DEBUG) debug(p, "Update complete"); } while (iterate); /* cleanup */ if (last) { PDQ_FREE(last); last = NULL; } if (PDQ_DEBUG) debug(p, "Exiting"); } /* approx */
int main(void) { extern int nodes, streams; extern JOB_TYPE *job; extern NODE_TYPE *node; extern char s1[]; char transCD[MAXCHARS], transRQ[MAXCHARS], transSU[MAXCHARS]; char dummyCD[MAXCHARS], dummyRQ[MAXCHARS], dummySU[MAXCHARS]; char nodePC[MAXCHARS], nodeFS[MAXCHARS], nodeGW[MAXCHARS]; char nodeMF[MAXCHARS], nodeTR[MAXCHARS]; double demand[MAXPROC][MAXDEV], util[MAXDEV], udsk[MAXDEV], udasd[MAXDEV], RTexpect[MAXPROC]; double fsd, RTmean, ulan, ufs, uws, ugw, umf; int work, dev, i, j; /* Disk-array data structures probably should go into PDQ_Build.c one day. */ devarray_type *FDarray; devarray_type *MDarray; if ((FDarray = (devarray_type *) calloc(sizeof(devarray_type), 10)) == NULL) errmsg("", "FDarray allocation failed!\n"); if ((MDarray = (devarray_type *) calloc(sizeof(devarray_type), 10)) == NULL) errmsg("", "MDarray allocation failed!\n"); for (i = 0; i < FS_DISKS; i++) { FDarray[i].id = FD + i; resets(s1); sprintf(s1, "FSDK%d", i); strcpy(FDarray[i].label, s1); } for (i = 0; i < MF_DISKS; i++) { MDarray[i].id = MD + i; resets(s1); sprintf(s1, "MFDK%d", i); strcpy(MDarray[i].label, s1); } /* CPU service times are calculated from instruction counts tabulated in original 1993 CMG paper. */ demand[CD_Req][PC] = 200 * k / PC_MIPS; demand[CD_Rpy][PC] = 100 * k / PC_MIPS; demand[RQ_Req][PC] = 150 * k / PC_MIPS; demand[RQ_Rpy][PC] = 200 * k / PC_MIPS; demand[SU_Req][PC] = 300 * k / PC_MIPS; demand[SU_Rpy][PC] = 300 * k / PC_MIPS; demand[Req_CD][FS] = 50 * k / FS_MIPS; demand[Req_RQ][FS] = 70 * k / FS_MIPS; demand[Req_SU][FS] = 10 * k / FS_MIPS; demand[CD_Msg][FS] = 35 * k / FS_MIPS; demand[RQ_Msg][FS] = 35 * k / FS_MIPS; demand[SU_Msg][FS] = 35 * k / FS_MIPS; demand[GT_Snd][GW] = 50 * k / GW_MIPS; demand[GT_Rcv][GW] = 50 * k / GW_MIPS; demand[MF_CD][MF] = 50 * k / MF_MIPS; demand[MF_RQ][MF] = 150 * k / MF_MIPS; demand[MF_SU][MF] = 20 * k / MF_MIPS; /* Service time on the LAN to send and recv packets from any of the PC desktop, the file server or the SNA gateway. 8 bits per Byte. */ demand[LAN_TX][PC] = (double) TR_Bytes * 8 / TR_Mbps; demand[LAN_TX][FS] = (double) TR_Bytes * 8 / TR_Mbps; demand[LAN_TX][GW] = (double) TR_Bytes * 8 / TR_Mbps; /* * File server disk IOs = number of accesses x caching / (max IOs / Sec) */ for (i = 0; i < FS_DISKS; i++) { demand[Req_CD][FDarray[i].id] = (1.0 * 0.5 / 128.9) / FS_DISKS; demand[Req_RQ][FDarray[i].id] = (1.5 * 0.5 / 128.9) / FS_DISKS; demand[Req_SU][FDarray[i].id] = (0.2 * 0.5 / 128.9) / FS_DISKS; demand[CD_Msg][FDarray[i].id] = (1.0 * 0.5 / 128.9) / FS_DISKS; demand[RQ_Msg][FDarray[i].id] = (1.5 * 0.5 / 128.9) / FS_DISKS; demand[SU_Msg][FDarray[i].id] = (0.5 * 0.5 / 128.9) / FS_DISKS; } /* Mainframe DASD IOs = (#accesses / (max IOs/Sec)) / #disks */ for (i = 0; i < MF_DISKS; i++) { demand[MF_CD][MDarray[i].id] = (2.0 / 60.24) / MF_DISKS; demand[MF_RQ][MDarray[i].id] = (4.0 / 60.24) / MF_DISKS; demand[MF_SU][MDarray[i].id] = (1.0 / 60.24) / MF_DISKS; } /* Now, start building the PDQ model... */ PDQ_Init(scenario); /* Define physical resources as PDQ queueing nodes. */ strcpy(nodePC, "PCDESK"); strcpy(nodeFS, "FSERVR"); strcpy(nodeGW, "GATWAY"); strcpy(nodeMF, "MFRAME"); strcpy(nodeTR, "TRLAN"); PDQ_CreateNode(nodePC, CEN, FCFS); PDQ_CreateNode(nodeFS, CEN, FCFS); PDQ_CreateNode(nodeGW, CEN, FCFS); PDQ_CreateNode(nodeMF, CEN, FCFS); for (i = 0; i < FS_DISKS; i++) { PDQ_CreateNode(FDarray[i].label, CEN, FCFS); } for (i = 0; i < MF_DISKS; i++) { PDQ_CreateNode(MDarray[i].label, CEN, FCFS); } /* * NOTE: Although the token ring LAN is a passive computational device, it * is treated as a separate node so as to agree with the results presented * in the original CMG 1993 paper. */ PDQ_CreateNode(nodeTR, CEN, FCFS); /* * Because the desktop PCs are all of the same type and emitting the same * homogeneous transaction workload, the focus can be placed on the * response time performance of a single PC workstation and generalized to * the others. Rather than having N * 3 workload streams or classes, we * simply model 2 PC desktops: the "real" one of interest and a dummy PC * representing the remaining (N-1) * 3 streams. */ strcpy(transCD, "CatDisplay"); strcpy(transRQ, "RemotQuote"); strcpy(transSU, "StatUpdate"); /* Aggregate transactions */ strcpy(dummyCD, "CatDispAgg"); strcpy(dummyRQ, "RemQuotAgg"); strcpy(dummySU, "StatUpdAgg"); PDQ_CreateOpen(transCD, 1 * 4.0 * TPS); PDQ_CreateOpen(transRQ, 1 * 8.0 * TPS); PDQ_CreateOpen(transSU, 1 * 1.0 * TPS); PDQ_CreateOpen(dummyCD, (USERS - 1) * 4.0 * TPS); PDQ_CreateOpen(dummyRQ, (USERS - 1) * 8.0 * TPS); PDQ_CreateOpen(dummySU, (USERS - 1) * 1.0 * TPS); /* Define the service demands on each physical resource. CD request + reply chain from workflow diagram Note that only the "real" PC demand is defined, and the aggregated (N-1) PCs. */ /******************* RQ request + reply chain ... *******************/ PDQ_SetDemand(nodePC, transCD, demand[CD_Req][PC] + (5 * demand[CD_Rpy][PC])); PDQ_SetDemand(nodeFS, transCD, demand[Req_CD][FS] + (5 * demand[CD_Msg][FS])); PDQ_SetDemand(nodeFS, dummyCD, demand[Req_CD][FS] + (5 * demand[CD_Msg][FS])); PDQ_SetDemand(nodeGW, transCD, demand[GT_Snd][GW] + (5 * demand[GT_Rcv][GW])); PDQ_SetDemand(nodeGW, dummyCD, demand[GT_Snd][GW] + (5 * demand[GT_Rcv][GW])); PDQ_SetDemand(nodeMF, transCD, demand[MF_CD][MF]); PDQ_SetDemand(nodeMF, dummyCD, demand[MF_CD][MF]); for (i = 0; i < FS_DISKS; i++) { fsd = demand[Req_CD][FDarray[i].id] + (5 * demand[CD_Msg][FDarray[i].id]); PDQ_SetDemand(FDarray[i].label, transCD, fsd); PDQ_SetDemand(FDarray[i].label, dummyCD, fsd); } for (i = 0; i < MF_DISKS; i++) { PDQ_SetDemand(MDarray[i].label, transCD, demand[MF_CD][MDarray[i].id]); PDQ_SetDemand(MDarray[i].label, dummyCD, demand[MF_CD][MDarray[i].id]); } /* NOTE:Synchronous process execution causes data for the CD transaction to cross the LAN 12 times as depicted in the following parameterization of PDQ_SetDemand. */ PDQ_SetDemand(nodeTR, transCD, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (5 * demand[LAN_TX][GW]) + (5 * demand[LAN_TX][FS]) + (5 * demand[LAN_TX][PC])); PDQ_SetDemand(nodeTR, dummyCD, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (5 * demand[LAN_TX][GW]) + (5 * demand[LAN_TX][FS]) + (5 * demand[LAN_TX][PC])); /******************* RQ request + reply chain ... *******************/ PDQ_SetDemand(nodePC, transRQ, demand[RQ_Req][PC] + (3 * demand[RQ_Rpy][PC])); PDQ_SetDemand(nodeFS, transRQ, demand[Req_RQ][FS] + (3 * demand[RQ_Msg][FS])); PDQ_SetDemand(nodeFS, dummyRQ, demand[Req_RQ][FS] + (3 * demand[RQ_Msg][FS])); for (i = 0; i < FS_DISKS; i++) { PDQ_SetDemand(FDarray[i].label, transRQ, demand[Req_RQ][FDarray[i].id] + (3 * demand[RQ_Msg][FDarray[i].id])); PDQ_SetDemand(FDarray[i].label, dummyRQ, demand[Req_RQ][FDarray[i].id] + (3 * demand[RQ_Msg][FDarray[i].id])); } PDQ_SetDemand(nodeGW, transRQ, demand[GT_Snd][GW] + (3 * demand[GT_Rcv][GW])); PDQ_SetDemand(nodeGW, dummyRQ, demand[GT_Snd][GW] + (3 * demand[GT_Rcv][GW])); PDQ_SetDemand(nodeMF, transRQ, demand[MF_RQ][MF]); PDQ_SetDemand(nodeMF, dummyRQ, demand[MF_RQ][MF]); for (i = 0; i < MF_DISKS; i++) { PDQ_SetDemand(MDarray[i].label, transRQ, demand[MF_RQ][MDarray[i].id]); PDQ_SetDemand(MDarray[i].label, dummyRQ, demand[MF_RQ][MDarray[i].id]); } PDQ_SetDemand(nodeTR, transRQ, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (3 * demand[LAN_TX][GW]) + (3 * demand[LAN_TX][FS]) + (3 * demand[LAN_TX][PC])); PDQ_SetDemand(nodeTR, dummyRQ, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (3 * demand[LAN_TX][GW]) + (3 * demand[LAN_TX][FS]) + (3 * demand[LAN_TX][PC])); /******************* SU request + reply chain *******************/ PDQ_SetDemand(nodePC, transSU, demand[SU_Req][PC] + demand[SU_Rpy][PC]); PDQ_SetDemand(nodeFS, transSU, demand[Req_SU][FS] + demand[SU_Msg][FS]); PDQ_SetDemand(nodeFS, dummySU, demand[Req_SU][FS] + demand[SU_Msg][FS]); for (i = 0; i < FS_DISKS; i++) { PDQ_SetDemand(FDarray[i].label, transSU, demand[Req_SU][FDarray[i].id] + demand[SU_Msg][FDarray[i].id]); PDQ_SetDemand(FDarray[i].label, dummySU, demand[Req_SU][FDarray[i].id] + demand[SU_Msg][FDarray[i].id]); } PDQ_SetDemand(nodeGW, transSU, demand[GT_Snd][GW] + demand[GT_Rcv][GW]); PDQ_SetDemand(nodeGW, dummySU, demand[GT_Snd][GW] + demand[GT_Rcv][GW]); PDQ_SetDemand(nodeMF, transSU, demand[MF_SU][MF]); PDQ_SetDemand(nodeMF, dummySU, demand[MF_SU][MF]); for (i = 0; i < MF_DISKS; i++) { PDQ_SetDemand(MDarray[i].label, transSU, demand[MF_SU][MDarray[i].id]); PDQ_SetDemand(MDarray[i].label, dummySU, demand[MF_SU][MDarray[i].id]); } PDQ_SetDemand(nodeTR, transSU, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (1 * demand[LAN_TX][GW]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][PC])); PDQ_SetDemand(nodeTR, dummySU, (1 * demand[LAN_TX][PC]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][GW]) + (1 * demand[LAN_TX][GW]) + (1 * demand[LAN_TX][FS]) + (1 * demand[LAN_TX][PC])); PDQ_SetDebug(FALSE); PDQ_SetWUnit("Trans"); PDQ_Solve(CANON); if (PRINT_REPORT) { PDQ_Report(); } /* Break out each tx response time together with resource utilizations. The order of print out is the same as the 1993 CMG paper. */ /* Mean response times reported in the CMG93 paper */ RTexpect[0] = 0.2754; RTexpect[1] = 0.2625; RTexpect[2] = 0.1252; RTexpect[3] = 0.2624; RTexpect[4] = 0.2470; RTexpect[5] = 0.1120; printf("*** Metric breakout for \"%s\" with %d clients ***\n\n", scenario, USERS); printf("Transaction\t R (Sec)\t CMG paper\n"); printf("-----------\t -------\t ---------\n"); for (work = 0; work < streams; work++) { resets(s1); strcpy(s1, job[work].trans->name); RTmean = PDQ_GetResponse(TRANS, s1); printf("%-15s\t%10.4f\t%10.4f\n", s1, RTmean, RTexpect[work]); } printf("\n\n"); /* * Get node utilizations. This is a bit of a hack and should be written as * a subroutine. */ for (dev = 0; dev < nodes; dev++) { util[dev] = 0.0; /* reset array */ for (work = 0; work < streams; work++) { util[dev] += 100 * PDQ_GetUtilization(node[dev].devname, job[work].trans->name, TRANS); } } for (dev = 0; dev < nodes; dev++) { for (i = 0; i < MF_DISKS; i++) { if (strcmp(node[dev].devname, MDarray[i].label) == 0) { udasd[i] = util[dev]; } } for (i = 0; i < FS_DISKS; i++) { if (strcmp(node[dev].devname, FDarray[i].label) == 0) { udsk[i] = util[dev]; } } if (strcmp(node[dev].devname, nodePC) == 0) { uws = util[dev]; } if (strcmp(node[dev].devname, nodeGW) == 0) { ugw = util[dev]; } if (strcmp(node[dev].devname, nodeFS) == 0) { ufs = util[dev]; } if (strcmp(node[dev].devname, nodeMF) == 0) { umf = util[dev]; } if (strcmp(node[dev].devname, nodeTR) == 0) { ulan = util[dev]; } } printf("PDQ Node \t %% Busy\t CMG paper\n"); printf("-------- \t -------\t ---------\n"); printf("%-15s\t%10.4f\t%10.4f\n", "Token ring", ulan, 49.3333); printf("%-15s\t%10.4f\t%10.4f\n", "PC Desktop", uws, 0.5802); printf("%-15s\t%10.4f\t%10.4f\n", "File server", ufs, 11.9157); printf("%-15s\t%10.4f\t%10.4f\n", "Gateway CPU", ugw, 60.4167); printf("%-15s\t%10.4f\t%10.4f\n", "Mainframe", umf, 14.0873); for (i = 0; i < FS_DISKS; i++) { printf("%s%d\t%10.4f\t%10.4f\n", "FS disks", FDarray[i].id, udsk[i], 59.0028); } for (i = 0; i < MF_DISKS; i++) { printf("%s%d\t%10.4f\t%10.4f\n", "DASD disk", MDarray[i].id, udasd[i], 35.5502); } } /* main */