diff options
Diffstat (limited to 'pa8_predict/simulator.c')
-rw-r--r-- | pa8_predict/simulator.c | 837 |
1 files changed, 837 insertions, 0 deletions
diff --git a/pa8_predict/simulator.c b/pa8_predict/simulator.c new file mode 100644 index 0000000..58a5800 --- /dev/null +++ b/pa8_predict/simulator.c @@ -0,0 +1,837 @@ +/* + * File: simulator.c + * + * Original Author: Dr. Alva Couch + * http://www.cs.tufts.edu/~couch/ + */ + +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "simulator.h" + +extern Program programs[PROGRAMS]; + +FILE *output = NULL; /* PC history for statistical analysis */ +FILE *pages = NULL; /* block allocation history */ + +static long sysclock = 0; +static long seed = 0; +static long procs = MAXPROCESSES; + +#define LOG_ALWAYS (1 << 0) +#define LOG_LOAD (1 << 1) +#define LOG_BLOCK (1 << 2) +#define LOG_PAGE (1 << 3) +#define LOG_BRANCH (1 << 4) +#define LOG_DEAD (1 << 5) +#define LOG_QUEUE (1 << 9) + +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> + +// shorthands for assertion handling +#define CHECK(bool) check((bool), #bool, __FILE__, __LINE__) +#define ASSERT(bool) assert((bool), #bool, __FILE__, __LINE__) +#define POSIT(bool) posit((bool), #bool, __FILE__, __LINE__) +#define DIE(reason) die((reason), __FILE__, __LINE__) +#define CARP(reason) carp((reason), __FILE__, __LINE__) + +// always print the result of a test +inline void check(int boolean, char *boolstr, char *file, int line) { + if (!boolean) { + fprintf(stderr, "ERROR: %s failed in line %d of file %s\n", boolstr, line, + file); + } else { + fprintf(stderr, "%s succeeded in line %d of file %s\n", boolstr, line, + file); + } +} + +// die if an assertion fails. +static inline void assert(int boolean, char *boolstr, char *file, int line) { + if (!boolean) { + fprintf(stderr, "Assertion %s failed in line %d of file %s\n", boolstr, + line, file); + exit(1); /* exit(0) means correct execution! */ + } +} + +// report failing assertions without bombing out... keeps running +inline int posit(int boolean, char *boolstr, char *file, int line) { + if (!boolean) + fprintf(stderr, "Assertion %s failed in line %d of file %s\n", boolstr, + line, file); + return boolean; +} + +// die on a fatal error +inline void die(char *condition, char *file, int line) { + fprintf(stderr, "Fatal error: %s at line %d of file %s\n", condition, line, + file); + exit(1); +} + +// print a non-fatal error +inline void carp(char *condition, char *file, int line) { + fprintf(stderr, "Non-fatal error: %s at line %d of file %s\n", condition, + line, file); +} + +static long log_port = LOG_ALWAYS; // logging ports for output +static void sim_log(long type, const char *format, ...) { + va_list ap; + if (log_port & type) { + va_start(ap, format); + fprintf(stderr, "%08ld: ", sysclock); + vfprintf(stderr, format, ap); + va_end(ap); + } +} + +/* keep track of physical page usage */ +static long pagesavail = PHYSICALPAGES; + +static Process *processes[MAXPROCESSES]; + +/* make a binary decision according to a + probability distribution */ +static long binary(double prob) { + if (drand48() < prob) + return 1; + else + return 0; +} + +/* clear a branching engine */ +static void bcontext_clear(Bcontext *c) { + long i; + c->bcount = 0; + c->boffset = 0; + c->bsize = 1; + c->bvalue = 1; + c->brings[0] = 1; + for (i = 1; i < MAXBRINGS; i++) + c->brings[i] = 0; +} + +/* initialize a branching engine */ +static void bcontext_init(Bcontext *c, Branch *b) { + long i; + c->bcount = 0; + c->btype = b->btype; + if (b->btype == GOTO) { + c->boffset = 0; + c->bsize = 1; + c->bvalue = 1; + // c->brings[0]=1; /* old version */ + c->brings[0] = 0x7fffffff; /* keep going forever */ + for (i = 1; i < MAXBRINGS; i++) + c->brings[i] = 0; + } else if (b->btype == IF) { + long cvalue; + c->boffset = 0; + c->bsize = 0; + cvalue = c->bvalue = binary(b->prob); + c->bcount = 0; + // compute future values for if statements + while (c->bsize < MAXBRINGS) { + if (binary(b->prob) == cvalue) { + c->brings[c->bsize]++; + } else { + c->bsize++; + c->brings[c->bsize] = 1; + cvalue = !cvalue; + } + } + } else if (b->btype == FOR) { + c->boffset = 0; + c->bvalue = 1; + c->bsize = 0; + while (c->bsize < MAXBRINGS) { + if (b->max > b->min) { + c->brings[c->bsize++] = lrand48() % (b->max - b->min) + b->min; + } else { + c->brings[c->bsize++] = b->min; + } + c->brings[c->bsize++] = 1; // one failure to escape loop + } + } else if (b->btype == NFOR) { + c->boffset = 0; + c->bvalue = 0; + c->bsize = 0; + while (c->bsize < MAXBRINGS) { + if (b->max > b->min) { + c->brings[c->bsize++] = lrand48() % (b->max - b->min) + b->min; + } else { + c->brings[c->bsize++] = b->min; + } + c->brings[c->bsize++] = 1; // one failure to escape loop + } + } else { + fprintf(stderr, "unknown btype %ld\n", (long)(b->btype)); + } +} + +/* decide whether to branch or not */ +static long bcontext_decide(Bcontext *c) { + long ret = c->bvalue; + c->bcount++; + ASSERT(c->boffset >= 0 && c->boffset < MAXBRINGS); + if (c->bcount >= c->brings[c->boffset]) { + c->boffset = (c->boffset + 1) % c->bsize; + // ASSERT(c->boffset>0); // no wrapping! + c->bcount = 0; + c->bvalue = !c->bvalue; + } + return ret; +} + +static void process_clear(Process *q) { + long i; + q->pc = 0; + q->compute = q->block = 0; + q->program = NULL; + q->pid = -1; + q->kind = -1; + q->nbcontexts = 0; + for (i = 0; i < MAXBRANCHES; i++) { + bcontext_clear(q->bcontexts + i); + } + q->npages = 0; + /* no physical pages assigned */ + for (i = 0; i < MAXPROCPAGES; i++) { + q->pages[i] = -PAGEWAIT - 1; + q->blocked[i] = FALSE; // ALC: so simulator will log first access + } + q->active = FALSE; +} + +/* load a program into a process */ +static void process_load(Process *q, Program *p, int pid, int kind) { + long i; + q->pc = 0; + q->compute = q->block = 0; + q->program = p; + q->pid = pid; + q->kind = kind; + q->nbcontexts = p->nbranches; + ASSERT(p->nbranches >= 0 && p->nbranches < MAXBRANCHES); + for (i = 0; i < p->nbranches; i++) { + bcontext_init(q->bcontexts + i, p->branches + i); + } + // fprintf(stderr,"actual page size for process is %d\n", + // (q->program->size+PAGESIZE-1)/PAGESIZE); + q->npages = MAXPROCPAGES; + for (i = 0; i < MAXPROCPAGES; i++) { + q->pages[i] = -PAGEWAIT - 1; + q->blocked[i] = FALSE; // ALC: so simulator will log first access + } + /* no physical pages assigned */ + q->active = TRUE; /* now running */ +} + +/* unload a process and release all resources */ +static void process_unload(int pnum, Process *q) { + long i; + for (i = 0; i < q->npages; i++) + if (q->pages[i] >= -PAGEWAIT) { + pagesavail++; + q->pages[i] = -PAGEWAIT - 1; + q->blocked[i] = 1; + } + q->active = FALSE; + sim_log(LOG_LOAD, "process %2d; pc %04d: unloaded\n", pnum, q->pc); +} + +/* do a branch if necessary */ +static void process_dobranch(int pnum, Process *q, Branch *b, Bcontext *c) { + if (bcontext_decide(c)) { + // must document where we branched from + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,branch_from\n", sysclock, pnum, + q->pid, q->kind, q->pc); + q->pc = b->whereto; + // and where we branched to + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,branch_to\n", sysclock, pnum, q->pid, + q->kind, q->pc); + sim_log(LOG_BRANCH, "process %2d; pc %04d: branch\n", pnum, q->pc); + } else { + q->pc++; + sim_log(LOG_BRANCH, "process %2d; pc %04d: no branch\n", pnum, q->pc); + } + if (q->pc < 0 || q->pc >= q->program->size) + q->pc = 0; /* start over */ +} + +/* compute one step of a process */ +static long process_step(int pnum, Process *q) { + long pc; + long page; + long max, min; + Branch *b; + Bcontext *c; + + if (!q) + return FALSE; + pc = q->pc; + page = q->pc / PAGESIZE; + if (!q->active) { + return FALSE; + } + + /* if page swapped out, don't allow to run */ + if (q->pages[page] != 0) { + if (!q->blocked[page]) { + sim_log(LOG_BLOCK, "process=%2d page=%3d blocked\n", pnum, page); + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,blocked\n", sysclock, pnum, q->pid, + q->kind, q->pc); + q->blocked[page] = TRUE; + } + q->block++; + return TRUE; + } else { + if (q->blocked[page]) { + sim_log(LOG_BLOCK, "process=%2d page=%3d unblocked\n", pnum, page); + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,unblocked\n", sysclock, pnum, + q->pid, q->kind, q->pc); + q->blocked[page] = FALSE; + } + q->compute++; + } + + /* should I exit */ + ASSERT(q->program->nexits >= 0 && q->program->nexits <= MAXEXITS); + min = 0; + max = q->program->nexits - 1; + while (min + 1 < max) { + long mid = (min + max) / 2; + if (pc == q->program->exits[mid]) { + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,exit\n", sysclock, pnum, q->pid, + q->kind, q->pc); + return FALSE; + } else if (pc < q->program->exits[mid]) + max = mid; + else + min = mid; + } + if (pc == q->program->exits[min] || pc == q->program->exits[max]) { + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,exit\n", sysclock, pnum, q->pid, + q->kind, q->pc); + return FALSE; + } + b = q->program->branches; + c = q->bcontexts; + ASSERT(q->program->nbranches >= 0 && q->program->nbranches <= MAXBRANCHES); + min = 0; + max = q->program->nbranches - 1; + while (min + 1 < max) { + long mid = (min + max) / 2; + if (pc == b[mid].wherefrom) { + process_dobranch(pnum, q, b + mid, c + mid); + return TRUE; + } else if (pc < b[mid].wherefrom) + max = mid; + else + min = mid; + } + if (pc == b[min].wherefrom) { + process_dobranch(pnum, q, b + min, c + min); + return TRUE; + } + if (pc == b[max].wherefrom) { + process_dobranch(pnum, q, b + max, c + max); + return TRUE; + } + q->pc++; /* default action */ + if (q->pc < 0 || q->pc > q->program->size) { + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,out_of_range\n", sysclock, pnum, + q->pid, q->kind, q->pc); + q->pc = 0; /* start over */ + if (output) + fprintf(output, "%ld,%d,%ld,%ld,%ld,restart\n", sysclock, pnum, q->pid, + q->kind, q->pc); + } + return TRUE; +} + +/* public routine: swap one page out */ +int pageout(int process, int page) { + if (process < 0 || process >= procs || !processes[process] || + !processes[process]->active || page < 0 || + page >= processes[process]->npages) + return FALSE; + if (processes[process]->pages[page] < 0) + return TRUE; /* on its way out */ + if (processes[process]->pages[page] > 0) + return FALSE; /* not available to swap out */ + sim_log(LOG_PAGE, "process=%2d page=%3d start pageout\n", process, page); + if (pages) + fprintf(pages, "%ld,%d,%d,%ld,%ld,going\n", sysclock, process, page, + processes[process]->pid, processes[process]->kind); + processes[process]->pages[page] = -1; + return TRUE; +} + +/* public routine: swap one page in */ +int pagein(int process, int page) { + if (process < 0 || process >= procs || !processes[process] || + !processes[process]->active || page < 0 || + page >= processes[process]->npages) + return FALSE; + if (processes[process]->pages[page] >= 0) + return TRUE; /* on its way */ + if (pagesavail == 0) + return FALSE; + if (processes[process]->pages[page] >= -PAGEWAIT) + return FALSE; /* not yet out */ + sim_log(LOG_PAGE, "process=%2d page=%3d start pagein\n", process, page); + if (pages) + fprintf(pages, "%ld,%d,%d,%ld,%ld,coming\n", sysclock, process, page, + processes[process]->pid, processes[process]->kind); + processes[process]->pages[page] = PAGEWAIT; + pagesavail--; + return TRUE; +} + +/*============ + job queue + ============*/ + +static long queuetype[QUEUESIZE]; +static Process queue[QUEUESIZE]; +static long queueend; +static void initqueue() { + long i; + for (i = 0; i < QUEUESIZE; i++) + queuetype[i] = lrand48() % PROGRAMS; + /* + long repeats; + for (repeats=0; repeats<10; repeats++) + for (i=0; i<QUEUESIZE; i++) { + int j=lrand48()%QUEUESIZE; + long temp=queuetype[i]; queuetype[i]=queuetype[j]; + queuetype[j]=temp; + } + */ + for (int i = 0; i < QUEUESIZE; i++) { + process_clear(queue + i); + process_load(queue + i, programs + queuetype[i], i, queuetype[i]); + } + + queueend = 0; +} +static Process *dequeue() { + if (queueend < QUEUESIZE) + return queue + queueend++; + else + return NULL; +} +static long empty() { return queueend >= QUEUESIZE; } + +/*=========================== + control of all processes + ===========================*/ + +static void allprint() { + int i, j; + fprintf(stderr, "\nprocess "); + for (i = 0; i < MAXPROCESSES / 2; i++) { + if (i) + fprintf(stderr, " | "); + if (processes[i] && processes[i]->active) { + fprintf(stderr, " %02d", i); + } else { + fprintf(stderr, " --"); + } + } + fprintf(stderr, "\n"); + fprintf(stderr, "pc "); + for (i = 0; i < MAXPROCESSES / 2; i++) { + if (i) + fprintf(stderr, " | "); + if (processes[i] && processes[i]->active) { + fprintf(stderr, "%04ld", processes[i]->pc); + } else { + fprintf(stderr, "----"); + } + } + fprintf(stderr, "\n"); + for (j = 0; j < MAXPROCPAGES; j++) { + fprintf(stderr, "page%02d ", j); + for (i = 0; i < MAXPROCESSES / 2; i++) { + if (i) + fprintf(stderr, " |"); + if (processes[i] && processes[i]->active) { + int pcblock = processes[i]->pc / PAGESIZE; + if (j == pcblock) { + if (processes[i]->pages[j] > 0) + fprintf(stderr, "*i%3ld", processes[i]->pages[j]); + else if (processes[i]->pages[j] == 0) + fprintf(stderr, "*=in "); + else if (processes[i]->pages[j] == -100) + fprintf(stderr, "*=out"); + else + fprintf(stderr, "*o%3ld", 100 + processes[i]->pages[j]); + // fprintf(stderr,"*%4d",processes[i]->pages[j]); + } else { + if (processes[i]->pages[j] > 0) + fprintf(stderr, " i%3ld", processes[i]->pages[j]); + else if (processes[i]->pages[j] == 0) + fprintf(stderr, " =in "); + else if (processes[i]->pages[j] == -100) + fprintf(stderr, " =out"); + else + fprintf(stderr, " o%3ld", 100 + processes[i]->pages[j]); + // fprintf(stderr," %4d",processes[i]->pages[j]); + } + } else { + fprintf(stderr, " ----"); + } + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "------------------------------------------------------------" + "----------------\n"); + fprintf(stderr, "process "); + for (i = MAXPROCESSES / 2; i < MAXPROCESSES; i++) { + if (i - MAXPROCESSES / 2) + fprintf(stderr, " | "); + if (processes[i] && processes[i]->active) { + fprintf(stderr, " %02d", i); + } else { + fprintf(stderr, " --"); + } + } + fprintf(stderr, "\n"); + fprintf(stderr, "pc "); + for (i = MAXPROCESSES / 2; i < MAXPROCESSES; i++) { + if (i - MAXPROCESSES / 2) + fprintf(stderr, " | "); + if (processes[i] && processes[i]->active) { + fprintf(stderr, "%04ld", processes[i]->pc); + } else { + fprintf(stderr, "----"); + } + } + fprintf(stderr, "\n"); + for (j = 0; j < MAXPROCPAGES; j++) { + fprintf(stderr, "page%02d ", j); + for (i = MAXPROCESSES / 2; i < MAXPROCESSES; i++) { + if (i - MAXPROCESSES / 2) + fprintf(stderr, " |"); + if (processes[i] && processes[i]->active) { + int pcblock = processes[i]->pc / PAGESIZE; + if (j == pcblock) { + if (processes[i]->pages[j] > 0) + fprintf(stderr, "*i%3ld", processes[i]->pages[j]); + else if (processes[i]->pages[j] == 0) + fprintf(stderr, "*=in "); + else if (processes[i]->pages[j] == -100) + fprintf(stderr, "*=out"); + else + fprintf(stderr, "*o%3ld", 100 + processes[i]->pages[j]); + // fprintf(stderr,"*%4d",processes[i]->pages[j]); + } else { + if (processes[i]->pages[j] > 0) + fprintf(stderr, " i%3ld", processes[i]->pages[j]); + else if (processes[i]->pages[j] == 0) + fprintf(stderr, " =in "); + else if (processes[i]->pages[j] == -100) + fprintf(stderr, " =out"); + else + fprintf(stderr, " o%3ld", 100 + processes[i]->pages[j]); + // fprintf(stderr," %4d",processes[i]->pages[j]); + } + } else { + fprintf(stderr, " ----"); + } + } + fprintf(stderr, "\n"); + } + fprintf(stderr, "------------------------------------------------------------" + "----------------\n"); +} + +static void endit() { + allprint(); + exit(0); +} + +static void allinit() { + long i; + initqueue(); + for (i = 0; i < MAXPROCESSES; i++) + processes[i] = NULL; + for (i = 0; i < procs; i++) { + // zero out pages from processes + if (!empty()) { + processes[i] = dequeue(); + + sim_log(LOG_LOAD, "process %2d; pc %04d: loaded\n", i, processes[i]->pc); + if (output) + fprintf(output, "%ld,%ld,%ld,%ld,%ld,load\n", sysclock, i, + processes[i]->pid, processes[i]->kind, processes[i]->pc); + if (pages) { + long j; + for (j = 0; j < MAXPROCPAGES; j++) + fprintf(pages, "%ld,%ld,%ld,%ld,%ld,out\n", sysclock, i, j, + processes[i]->pid, processes[i]->kind); + } + } + } +} + +static void allscore() { + int i; + int block = 0; + int compute = 0; + for (i = 0; i < QUEUESIZE; i++) { + block += queue[i].block; + compute += queue[i].compute; + } + sim_log(LOG_ALWAYS, "simulation ends\n"); + sim_log(LOG_ALWAYS, "%d blocked cycles\n", block); + sim_log(LOG_ALWAYS, "%d compute cycles\n", compute); + sim_log(LOG_ALWAYS, "ratio blocked/compute=%g\n", + (double)block / (double)compute); +} + +static void allstep() { + long i; + for (i = 0; i < procs; i++) { + if (!process_step(i, processes[i])) { + if (processes[i] && processes[i]->active) { + // document final PC position + if (output) + fprintf(output, "%ld,%ld,%ld,%ld,%ld,unload\n", sysclock, i, + processes[i]->pid, processes[i]->kind, processes[i]->pc); + if (pages) { + long j; + for (j = 0; j < MAXPROCPAGES; j++) + fprintf(pages, "%ld,%ld,%ld,%ld,%ld,out\n", sysclock, i, j, + processes[i]->pid, processes[i]->kind); + } + process_unload(i, processes[i]); + } + processes[i] = NULL; + if (!empty()) { + processes[i] = dequeue(); + sim_log(LOG_LOAD, "process %2d; pc %04d: loaded\n", i, + processes[i]->pc); + if (output) + fprintf(output, "%ld,%ld,%ld,%ld,%ld,load\n", sysclock, i, + processes[i]->pid, processes[i]->kind, processes[i]->pc); + } + } + } +} + +static long alldone() { + long i; + for (i = 0; i < procs; i++) { + if (processes[i] && processes[i]->active) + return FALSE; + } + return TRUE; +} + +static int allblocked() { + int allfree = 0; + int runnable = 0; + int memwait = 0; + int freewait = 0; + int i, stat; + for (i = 0; i < procs; i++) + if (processes[i] && processes[i]->active) { + stat = processes[i]->pages[(int)(processes[i]->pc / PAGESIZE)]; + if (stat > 0) + memwait++; /* waiting for swap in */ + else if (stat == 0) + runnable++; /* ok */ + else if (stat < -PAGEWAIT) + allfree++; /* free */ + else + freewait++; /* waiting for swap out */ + } + + if (allfree && !memwait && !runnable && !freewait) { + sim_log(LOG_DEAD, "%d process pcs waiting for swap in\n", memwait); + sim_log(LOG_DEAD, "%d process pcs runnable\n", runnable); + sim_log(LOG_DEAD, "%d process pcs waiting for swap out\n", freewait); + sim_log(LOG_DEAD, "%d process pcs swapped out\n", allfree); + sim_log(LOG_DEAD, "All needed pages swapped out!\n"); + // allprint(); + return 1; + } else { + return 0; + } +} + +static void allage() { + long i; + for (i = 0; i < procs; i++) { + if (processes[i] && processes[i]->active) { + long j; + for (j = 0; j < processes[i]->npages; j++) { + if (processes[i]->pages[j] == 0) + ; + else if (processes[i]->pages[j] < -PAGEWAIT) + ; + else if (processes[i]->pages[j] > 0) { + processes[i]->pages[j]--; + if (processes[i]->pages[j] == 0) { + sim_log(LOG_PAGE, "process=%2d page=%3d end pagein\n", i, j); + if (pages) + fprintf(pages, "%ld,%ld,%ld,%ld,%ld,in\n", sysclock, i, j, + processes[i]->pid, processes[i]->kind); + } + } else if (processes[i]->pages[j] < 0 && + processes[i]->pages[j] >= -PAGEWAIT) { + processes[i]->pages[j]--; + if (processes[i]->pages[j] < -PAGEWAIT) { + sim_log(LOG_PAGE, "process=%2d page=%3d end pageout\n", i, j); + if (pages) + fprintf(pages, "%ld,%ld,%ld,%ld,%ld,out\n", sysclock, i, j, + processes[i]->pid, processes[i]->kind); + pagesavail++; + } + } + } + } + } +} + +static void callyou() { + long i, j; + Pentry pentry[MAXPROCESSES]; + for (i = 0; i < MAXPROCESSES; i++) { + if (processes[i]) { + pentry[i].active = processes[i]->active; + pentry[i].pc = processes[i]->pc; + pentry[i].npages = processes[i]->npages; + for (j = 0; j < processes[i]->npages; j++) { + pentry[i].pages[j] = (processes[i]->pages[j] == 0); + } + for (; j < MAXPROCPAGES; j++) + pentry[i].pages[j] = FALSE; + } else { + pentry[i].active = FALSE; + pentry[i].pc = 0; + pentry[i].npages = 0; + for (j = 0; j < MAXPROCPAGES; j++) + pentry[i].pages[j] = FALSE; + } + } + pageit(pentry); /* call your routine */ +} + +int main(int argc, char **argv) { + + long i, errors = 0, help = 0; + + signal(SIGINT, endit); + + log_port = LOG_ALWAYS; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-help") == 0) { + help++; + } else if (strcmp(argv[i], "-all") == 0) { + log_port |= LOG_LOAD | LOG_BLOCK | LOG_PAGE | LOG_BRANCH; + } else if (strcmp(argv[i], "-load") == 0) { + log_port |= LOG_LOAD; + } else if (strcmp(argv[i], "-block") == 0) { + log_port |= LOG_BLOCK; + } else if (strcmp(argv[i], "-page") == 0) { + log_port |= LOG_PAGE; + } else if (strcmp(argv[i], "-branch") == 0) { + log_port |= LOG_BRANCH; + } else if (strcmp(argv[i], "-dead") == 0) { + log_port |= LOG_DEAD; + } else if (strcmp(argv[i], "-seed") == 0) { + if (sscanf(argv[++i], "%ld", &seed) != 1) { + fprintf(stderr, "%s: could not read random seed from command line\n", + argv[0]); + errors++; + } else if (seed < 1 || seed > ((1 << 30) - 1)) { + fprintf(stderr, "%s: random seed must be between 1 and %d\n", argv[0], + (1 << 30) - 1); + errors++; + } + } else if (strcmp(argv[i], "-csv") == 0) { + output = fopen("output.csv", "w"); + if (!output) { + fprintf(stderr, "%s: could not open output.csv for writing\n", argv[0]); + errors++; + } + pages = fopen("pages.csv", "w"); + if (!pages) { + fprintf(stderr, "%s: could not open pages.csv for writing\n", argv[0]); + errors++; + } + } else if (strcmp(argv[i], "-procs") == 0) { + if (sscanf(argv[++i], "%ld", &procs) != 1) { + fprintf(stderr, + "%s: could not read number of processors from command line\n", + argv[0]); + errors++; + } else if (procs < 1 || procs > MAXPROCESSES) { + fprintf(stderr, "%s: number of processors must be between 1 and %d\n", + argv[0], MAXPROCESSES); + errors++; + } + } else { + fprintf(stderr, "t4: unrecognized argument %s\n", argv[i]); + errors++; + } + } + if (errors || help) { + fprintf(stderr, "%s usage: %s \n", argv[0], argv[0]); + fprintf(stderr, " -all log everything\n"); + fprintf(stderr, " -load log loading of processes\n"); + fprintf(stderr, " -unload log unloading of processes\n"); + fprintf(stderr, " -branch log program branches\n"); + fprintf(stderr, " -page log page in and out\n"); + fprintf(stderr, " -seed 512 set random seed to 512\n"); + fprintf(stderr, " -procs 4 run only four processors\n"); + fprintf(stderr, " -dead detect deadlocks\n"); + fprintf(stderr, + " -csv generate output.csv and pages.csv for graphing\n"); + if (errors) { + return EXIT_FAILURE; + } else { + return EXIT_SUCCESS; + } + } + if (seed == 0) { + seed = (time(NULL) * 38491 + 71831 + time(NULL) * time(NULL)) & + ((1 << 30) - 1); + } + srand48(seed); + sim_log(LOG_ALWAYS, "random seed %d\n", seed); + sim_log(LOG_ALWAYS, "using %d processors\n", procs); + + allinit(); + while (!alldone()) { // all processes inactive + allstep(); // advance time one tick; if process done, reload + allage(); // advance time for page wait variables. + callyou(); // call your program + sysclock++; // remember new time. + allblocked(); // deadlock detection + } + allscore(); + + return EXIT_SUCCESS; +} |