| |
| /* 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) |
| ** |
| ** 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 <stdio.h> |
| #include <stdlib.h> |
| |
| #ifdef SMALL_PROBLEM_SIZE |
| #define Count 1000*1000 |
| #define Qpktcountval 2326389 |
| #define Holdcountval 930555 |
| #else |
| #define Count 10000*1000 |
| #define Qpktcountval 23263894 |
| #define Holdcountval 9305557 |
| #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[4]; |
| }; |
| |
| 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 *); |
| long t_v1; |
| long t_v2; |
| }; |
| |
| char alphabet[28] = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| struct task *tasktab[11] = {0,0,0,0,0,0,0,0,0,0,0}; |
| struct task *tasklist = 0; |
| struct task *tcb; |
| long taskid; |
| long v1; |
| long v2; |
| int qpktcount = 0; |
| int holdcount = 0; |
| int tracing = 1; |
| 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 *), |
| long v1, |
| long v2) |
| { |
| struct task *t = (struct task *)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 *)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==TRUE) 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(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)10) |
| 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) |
| { |
| --v2; |
| 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() ); |
| 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 = (long)(((struct packet *)v1)->p_link); |
| return ( qpkt(workpkt) ); |
| } |
| |
| if ( v2!=0 ) |
| { |
| struct packet *devpkt; |
| |
| devpkt = (struct packet *)v2; |
| v2 = (long)(((struct packet *)v2)->p_link); |
| devpkt->p_a1 = workpkt->p_a2[count]; |
| workpkt->p_a1 = count+1; |
| return( qpkt(devpkt) ); |
| } |
| } |
| return ( Wait() ); |
| } |
| |
| struct task *devfn(struct packet *pkt) |
| { |
| if ( pkt==0 ) |
| { |
| if ( v1==0 ) return ( Wait() ); |
| pkt = (struct packet *)v1; |
| v1 = 0; |
| return ( qpkt(pkt) ); |
| } |
| else |
| { |
| v1 = (long)pkt; |
| if (tracing==TRUE) 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 main() |
| { |
| struct packet *wkq = 0; |
| int retval; |
| |
| 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("finished\n"); |
| |
| printf("qpkt count = %d holdcount = %d\n", |
| qpktcount, holdcount); |
| |
| printf("These results are "); |
| if (qpktcount == Qpktcountval && holdcount == Holdcountval) { |
| printf("correct"); |
| retval = 0; |
| } else { |
| printf("incorrect"); |
| retval = 1; |
| } |
| |
| printf("\nend of run\n"); |
| return retval; |
| } |
| |