// clang-format off /* C version of the systems programming language benchmark ** Author: M. J. Jordan Cambridge Computer Laboratory. ** ** Modified by: M. Richards, Nov 1996 ** to be ANSI C and runnable on 64 bit machines + other minor changes ** Modified by: M. Richards, 20 Oct 1998 ** made minor corrections to improve ANSI compliance (suggested ** by David Levine) ** Modified by: Jeremy Singer, 25 May 2022 ** adapted to use uintptr_t for compatibility with architectures ** that do not have word-sized pointers (e.g. CHERI) ** also adapted to use Boehm-Demers-Weiser GC instead of system ** malloc, when compiled with -DGC ** ** Compile with, say ** ** gcc -o bench bench.c ** ** or ** ** gcc -o bench100 -Dbench100 bench.c (for a version that obeys ** the main loop 100x more often) */ // #include #include #include // #include // #include "harness.h" // #include "stddefines.h" // #ifdef GC // #include "gc.h" // #define MALLOC GC_MALLOC // #else // #define MALLOC malloc // #endif // GC // #define malloc tiny_malloc // #define free tiny_free void* tiny_malloc(size_t); void tiny_free(void*); #ifdef bench100 #define Count 10000*100 #define Qpktcountval 2326410 #define Holdcountval 930563 #else #define Count 10000 #define Qpktcountval 23246 #define Holdcountval 9297 #endif #define TRUE 1 #define FALSE 0 #define MAXINT 32767 #define BUFSIZE 3 #define I_IDLE 1 #define I_WORK 2 #define I_HANDLERA 3 #define I_HANDLERB 4 #define I_DEVA 5 #define I_DEVB 6 #define PKTBIT 1 #define WAITBIT 2 #define HOLDBIT 4 #define NOTPKTBIT !1 #define NOTWAITBIT !2 #define NOTHOLDBIT 0XFFFB #define S_RUN 0 #define S_RUNPKT 1 #define S_WAIT 2 #define S_WAITPKT 3 #define S_HOLD 4 #define S_HOLDPKT 5 #define S_HOLDWAIT 6 #define S_HOLDWAITPKT 7 #define K_DEV 1000 #define K_WORK 1001 struct packet { struct packet *p_link; int p_id; int p_kind; int p_a1; char p_a2[BUFSIZE+1]; }; struct task { struct task *t_link; int t_id; int t_pri; struct packet *t_wkq; int t_state; struct task *(*t_fn)(struct packet *); uintptr_t t_v1; uintptr_t t_v2; }; char alphabet[28] = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"; struct task *tasktab[11] = {(struct task *)10,0,0,0,0,0,0,0,0,0,0}; struct task *tasklist = 0; struct task *tcb; long taskid; uintptr_t v1; uintptr_t v2; int qpktcount = 0; int holdcount = 0; int tracing = 0; int layout = 0; void append(struct packet *pkt, struct packet *ptr); void createtask(int id, int pri, struct packet *wkq, int state, struct task *(*fn)(struct packet *), uintptr_t v1, uintptr_t v2) { struct task *t = (struct task *)tiny_malloc(sizeof(struct task)); tasktab[id] = t; t->t_link = tasklist; t->t_id = id; t->t_pri = pri; t->t_wkq = wkq; t->t_state = state; t->t_fn = fn; t->t_v1 = v1; t->t_v2 = v2; tasklist = t; } struct packet *pkt(struct packet *link, int id, int kind) { int i; struct packet *p = (struct packet *)tiny_malloc(sizeof(struct packet)); for (i=0; i<=BUFSIZE; i++) p->p_a2[i] = 0; p->p_link = link; p->p_id = id; p->p_kind = kind; p->p_a1 = 0; return (p); } void trace(char a) { if ( --layout <= 0 ) { // printf("\n"); layout = 50; } // printf("%c", a); } void schedule() { while ( tcb != 0 ) { struct packet *pkt; struct task *newtcb; pkt=0; switch ( tcb->t_state ) { case S_WAITPKT: pkt = tcb->t_wkq; tcb->t_wkq = pkt->p_link; tcb->t_state = tcb->t_wkq == 0 ? S_RUN : S_RUNPKT; case S_RUN: case S_RUNPKT: taskid = tcb->t_id; v1 = tcb->t_v1; v2 = tcb->t_v2; if (tracing) { trace(taskid+'0'); } newtcb = (*(tcb->t_fn))(pkt); tcb->t_v1 = v1; tcb->t_v2 = v2; tcb = newtcb; break; case S_WAIT: case S_HOLD: case S_HOLDPKT: case S_HOLDWAIT: case S_HOLDWAITPKT: tcb = tcb->t_link; break; default: return; } } } struct task *wait_task(void) { tcb->t_state |= WAITBIT; return (tcb); } struct task *holdself(void) { ++holdcount; tcb->t_state |= HOLDBIT; return (tcb->t_link) ; } struct task *findtcb(int id) { struct task *t = 0; if (1<=id && id<=(long)tasktab[0]) t = tasktab[id]; // if (t==0) printf("\nBad task id %d\n", id); return(t); } struct task *release(int id) { struct task *t; t = findtcb(id); if ( t==0 ) return (0); t->t_state &= NOTHOLDBIT; if ( t->t_pri > tcb->t_pri ) return (t); return (tcb) ; } struct task *qpkt(struct packet *pkt) { struct task *t; t = findtcb(pkt->p_id); if (t==0) return (t); qpktcount++; pkt->p_link = 0; pkt->p_id = taskid; if (t->t_wkq==0) { t->t_wkq = pkt; t->t_state |= PKTBIT; if (t->t_pri > tcb->t_pri) return (t); } else { append(pkt, (struct packet *)&(t->t_wkq)); } return (tcb); } struct task *idlefn(struct packet *pkt) { if ( --v2==0 ) return ( holdself() ); if ( (v1&1) == 0 ) { v1 = ( v1>>1) & MAXINT; return ( release(I_DEVA) ); } else { v1 = ( (v1>>1) & MAXINT) ^ 0XD008; return ( release(I_DEVB) ); } } struct task *workfn(struct packet *pkt) { if ( pkt==0 ) return ( wait_task() ); else { int i; v1 = I_HANDLERA + I_HANDLERB - v1; pkt->p_id = v1; pkt->p_a1 = 0; for (i=0; i<=BUFSIZE; i++) { v2++; if ( v2 > 26 ) v2 = 1; (pkt->p_a2)[i] = alphabet[v2]; } return ( qpkt(pkt) ); } } struct task *handlerfn(struct packet *pkt) { if ( pkt!=0) { append(pkt, (struct packet *)(pkt->p_kind==K_WORK ? &v1 : &v2)); } if ( v1!=0 ) { int count; struct packet *workpkt = (struct packet *)v1; count = workpkt->p_a1; if ( count > BUFSIZE ) { v1 = (uintptr_t)(((struct packet *)v1)->p_link); return ( qpkt(workpkt) ); } if ( v2!=0 ) { struct packet *devpkt; devpkt = (struct packet *)v2; v2 = (uintptr_t)(((struct packet *)v2)->p_link); devpkt->p_a1 = workpkt->p_a2[count]; workpkt->p_a1 = count+1; return( qpkt(devpkt) ); } } return wait_task(); } struct task *devfn(struct packet *pkt) { if ( pkt==0 ) { if ( v1==0 ) return ( wait_task() ); pkt = (struct packet *)v1; v1 = 0; return ( qpkt(pkt) ); } else { v1 = (uintptr_t)pkt; if (tracing) trace(pkt->p_a1); return ( holdself() ); } } void append(struct packet *pkt, struct packet *ptr) { pkt->p_link = 0; while ( ptr->p_link ) ptr = ptr->p_link; ptr->p_link = pkt; } int bench() { struct packet *wkq = 0; // printf("Bench mark starting\n"); createtask(I_IDLE, 0, wkq, S_RUN, idlefn, 1, Count); wkq = pkt(0, 0, K_WORK); wkq = pkt(wkq, 0, K_WORK); createtask(I_WORK, 1000, wkq, S_WAITPKT, workfn, I_HANDLERA, 0); wkq = pkt(0, I_DEVA, K_DEV); wkq = pkt(wkq, I_DEVA, K_DEV); wkq = pkt(wkq, I_DEVA, K_DEV); // createtask(I_HANDLERA, 2000, wkq, S_WAITPKT, handlerfn, 0, 0); // wkq = pkt(0, I_DEVB, K_DEV); // wkq = pkt(wkq, I_DEVB, K_DEV); // wkq = pkt(wkq, I_DEVB, K_DEV); // createtask(I_HANDLERB, 3000, wkq, S_WAITPKT, handlerfn, 0, 0); // wkq = 0; // createtask(I_DEVA, 4000, wkq, S_WAIT, devfn, 0, 0); // createtask(I_DEVB, 5000, wkq, S_WAIT, devfn, 0, 0); // tcb = tasklist; // qpktcount = holdcount = 0; // // printf("Starting\n"); // tracing = FALSE; // layout = 0; schedule(); // printf("\nfinished\n"); // if (!(qpktcount == Qpktcountval && holdcount == Holdcountval)) { // printf("qpkt count = %d holdcount = %d\n", qpktcount, holdcount); // printf("These results are incorrect"); // exit(1); // } // printf("\nend of run\n"); return qpktcount; } int inner_loop(int inner) { int r = 0; while (inner > 0) { r += bench(); inner--; } return r; } int main(int argc, char* argv[]) { //INITREGULARALLOC(); int iterations = 1; int warmup = 0; int inner_iterations = 1; // parse_argv(argc, argv, &iterations, &warmup, &inner_iterations); int result = 0; while (iterations > 0) { // unsigned long start = microseconds(); result += inner_loop(inner_iterations); // unsigned long elapsed = microseconds() - start; // printf("Richards: iterations=1 runtime: %lu%s\n", elapsed, "us"); // print(elapsed); iterations--; } }