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 */
void canonical(void) { extern int PDQ_DEBUG, streams, nodes; extern char s1[], s2[], s3[], s4[]; extern JOB_TYPE *job; extern NODE_TYPE *node; extern double ErlangR(double arrivrate, double servtime, int servers); // ANSI int k; int m; // servers in MSQ case int c = 0; double X; double Xsat; double Dsat = 0.0; double Ddev; double sumR[MAXSTREAMS]; double devU; double sumU(); char jobname[MAXBUF]; char satname[MAXBUF]; char *p = "canonical()"; if (PDQ_DEBUG) debug(p, "Entering"); for (c = 0; c < streams; c++) { sumR[c] = 0.0; Dsat = 0.0; // Fix submitted by James Newsom, 23 Feb 2011 //Otherwise, stream index can be compared to wrong (old) device index X = job[c].trans->arrival_rate; // find bottleneck node (== largest service demand) for (k = 0; k < nodes; k++) { // Hope to remove single class restriction eventually if (node[k].sched == MSQ && streams > 1) { sprintf(s1, "Only single PDQ stream allowed with MSQ nodes."); errmsg(p, s1); } Ddev = node[k].demand[c]; if (node[k].sched == MSQ) { // multiserver case m = node[k].devtype; // contains number of servers > 0 Ddev /= m; } if (Ddev > Dsat) { Dsat = Ddev; //Since we're about to fall out this k-loop //keep device name in case of error msg sprintf(satname, "%s", node[k].devname); } } // end of k-loop Xsat = 1.0 / Dsat; job[c].trans->saturation_rate = Xsat; if (Dsat == 0) { sprintf(s1, "Dsat = %3.3f", Dsat); errmsg(p, s1); } if (X > Xsat) { getjob_name(jobname, c); sprintf(s1, "\nArrival rate %3.3f for stream \'%s\' exceeds saturation thruput %3.3f of node \'%s\' with demand %3.3f", X, jobname, Xsat, satname, Dsat ); errmsg(p, s1); } for (k = 0; k < nodes; k++) { node[k].utiliz[c] = X * node[k].demand[c]; if (node[k].sched == MSQ) { // multiserver case m = node[k].devtype; // recompute m in every k-loop node[k].utiliz[c] /= m; // per server } devU = sumU(k); // sum all workload classes if (devU > 1.0) { sprintf(s1, "\nTotal utilization of node \"%s\" is %2.2f%% (> 100%%)", node[k].devname, devU * 100 ); errmsg(p, s1); } if (PDQ_DEBUG) printf("Tot Util: %3.4f for %s\n", devU, node[k].devname); switch (node[k].sched) { case FCFS: case PSHR: case LCFS: node[k].resit[c] = node[k].demand[c] / (1.0 - devU); node[k].qsize[c] = X * node[k].resit[c]; break; case MSQ: // Added by NJG on Mon, Apr 2, 2007 node[k].resit[c] = ErlangR(X, node[k].demand[c], m); node[k].qsize[c] = X * node[k].resit[c]; break; case ISRV: node[k].resit[c] = node[k].demand[c]; node[k].qsize[c] = node[k].utiliz[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]; } // end of k-loop job[c].trans->sys->thruput = X; // system throughput job[c].trans->sys->response = sumR[c]; // system response time job[c].trans->sys->residency = X * sumR[c]; // total number in system if (PDQ_DEBUG) { getjob_name(jobname, c); printf("\tX[%s]: %3.4f\n", jobname, job[c].trans->sys->thruput); printf("\tR[%s]: %3.4f\n", jobname, job[c].trans->sys->response); printf("\tN[%s]: %3.4f\n", jobname, job[c].trans->sys->residency); } } // end of c-loop if (PDQ_DEBUG) debug(p, "Exiting"); } // canonical