📄 meas.c
字号:
/* meas.c -- measure qt stuff. */#include "copyright.h"/* Need this to get assertions under Mach on the Sequent/i386: */#ifdef __i386__#define assert(ex) \ do { \ if (!(ex)) { \ fprintf (stderr, "[%s:%d] Assertion " #ex " failed\n", __FILE__, __LINE__); \ abort(); \ } \ } while (0)#else#include <assert.h>#endif/* This really ought to be defined in some ANSI include file (*I* think...), but it's defined here instead, which leads us to another machine dependency. The `iaddr_t' type is an integer representation of a pointer, suited for doing arithmetic on addresses, e.g. to round an address to an alignment boundary. */typedef unsigned long iaddr_t;#include <stdarg.h> /* For varargs tryout. */#include <stdio.h>#include "b.h"#include "qt.h"#include "stp.h"extern void exit (int status);extern int atoi (char const *s);extern int fprintf (FILE *out, char const *fmt, ...);extern int fputs (char const *s, FILE *fp);extern void free (void *sto);extern void *malloc (unsigned nbytes);extern void perror (char const *s);void usage (void);void tracer(void);/* Round `v' to be `a'-aligned, assuming `a' is a power of two. */#define ROUND(v, a) (((v) + (a) - 1) & ~((a)-1))typedef struct thread_t { qt_t *qt; /* Pointer to thread of function... */ void *stk; void *top; /* Set top of stack if reuse. */ struct thread_t *next;} thread_t; static thread_t *t_alloc (void){ thread_t *t; int ssz = 0x1000; t = malloc (sizeof(thread_t)); if (!t) { perror ("malloc"); exit (1); } assert (ssz > QT_STKBASE); t->stk = malloc (ssz); t->stk = (void *)ROUND (((iaddr_t)t->stk), QT_STKALIGN); if (!t->stk) { perror ("malloc"); exit (1); } assert ((((iaddr_t)t->stk) & (QT_STKALIGN-1)) == 0); t->top = QT_SP (t->stk, ssz - QT_STKBASE); return (t);} static thread_t *t_create (qt_only_t *starter, void *p0, qt_userf_t *f){ thread_t *t; t = t_alloc(); t->qt = QT_ARGS (t->top, p0, t, f, starter); return (t);} static voidt_free (thread_t *t){ free (t->stk); free (t);} static void *t_null (qt_t *old, void *p1, void *p2){ /* return (garbage); */} static void *t_splat (qt_t *old, void *oldp, void *null){ *(qt_t **)oldp = old; /* return (garbage); */}static char const test01_msg[] = "*QT_SP(sto,sz), QT_ARGS(top,p0,p1,userf,first)";static char const *test01_descr[] = { "Performs 1 QT_SP and one QT_ARGS per iteration.", NULL};/* This test gives a guess on how long it takes to initalize a thread. */ static voidtest01 (int n){ char stack[QT_STKBASE+QT_STKALIGN]; char *stk; qt_t *top; stk = (char *)ROUND (((iaddr_t)stack), QT_STKALIGN); { int i; for (i=0; i<QT_STKBASE; ++i) { stk[i] = 0; } } while (n>0) { /* RETVALUSED */ top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0);#ifdef NDEF top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); top = QT_SP (stk, QT_STKBASE); QT_ARGS (top, 0, 0, 0, 0); n -= 10;#else n -= 1;#endif }}static char const test02_msg[] = "QT_BLOCKI (0, 0, test02_aux, t->qt)";static qt_t *rootthread; static voidtest02_aux1 (void *pu, void *pt, qt_userf_t *f){ QT_ABORT (t_null, 0, 0, rootthread);} static void *test02_aux2 (qt_t *old, void *farg1, void *farg2){ rootthread = old; /* return (garbage); */} static voidtest02 (int n){ thread_t *t; while (n>0) { t = t_create (test02_aux1, 0, 0); QT_BLOCKI (test02_aux2, 0, 0, t->qt); t_free (t); t = t_create (test02_aux1, 0, 0); QT_BLOCKI (test02_aux2, 0, 0, t->qt); t_free (t); t = t_create (test02_aux1, 0, 0); QT_BLOCKI (test02_aux2, 0, 0, t->qt); t_free (t); t = t_create (test02_aux1, 0, 0); QT_BLOCKI (test02_aux2, 0, 0, t->qt); t_free (t); t = t_create (test02_aux1, 0, 0); QT_BLOCKI (test02_aux2, 0, 0, t->qt); t_free (t); n -= 5; }}static char const test03_msg[] = "QT_BLOCKI (...) test vals are right.";/* Called by the thread function when it wants to shut down. Return a value to the main thread. */ static void *test03_aux0 (qt_t *old_is_garbage, void *farg1, void *farg2){ assert (farg1 == (void *)5); assert (farg2 == (void *)6); return ((void *)15); /* Some unlikely value. */}/* Called during new thread startup by main thread. Since the new thread has never run before, return value is ignored. */ static void *test03_aux1 (qt_t *old, void *farg1, void *farg2){ assert (old != NULL); assert (farg1 == (void *)5); assert (farg2 == (void *)6); rootthread = old; return ((void *)16); /* Different than `15'. */} static voidtest03_aux2 (void *pu, void *pt, qt_userf_t *f){ assert (pu == (void *)1); assert (f == (qt_userf_t *)4); QT_ABORT (test03_aux0, (void *)5, (void *)6, rootthread);} static voidtest03 (int n){ thread_t *t; void *rv; while (n>0) { t = t_create (test03_aux2, (void *)1, (qt_userf_t *)4); rv = QT_BLOCKI (test03_aux1, (void *)5, (void *)6, t->qt); assert (rv == (void *)15); t_free (t); --n; }}static char const test04_msg[] = "stp_start w/ no threads."; static voidtest04 (int n){ while (n>0) { stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); stp_init(); stp_start(); n -= 10; }}static char const test05_msg[] = "stp w/ 2 yielding thread."; static voidtest05_aux (void *null){ stp_yield(); stp_yield();} static voidtest05 (int n){ while (n>0) { stp_init(); stp_create (test05_aux, 0); stp_create (test05_aux, 0); stp_start(); --n; }}static char const test06_msg[] = "*QT_ARGS(...), QT_BLOCKI one thread";static char const *test06_descr[] = { "Does a QT_ARGS, QT_BLOCKI to a helper function that saves the", "stack pointer of the main thread, calls an `only' function that", "saves aborts the thread, calling a null helper function.", ":: start/stop = QT_ARGS + QT_BLOCKI + QT_ABORT + 3 procedure calls.", NULL};/* This test initializes a thread, runs it, then returns to the main program, which reinitializes the thread, runs it again, etc. Each iteration corresponds to 1 init, 1 abort, 1 block. */static qt_t *test06_sp; static voidtest06_aux2 (void *null0a, void *null1b, void *null2b, qt_userf_t *null){ QT_ABORT (t_null, 0, 0, test06_sp);} static void *test06_aux3 (qt_t *sp, void *null0c, void *null1c){ test06_sp = sp; /* return (garbage); */} static voidtest06 (int n){ thread_t *t; t = t_create (0, 0, 0); while (n>0) { /* RETVALUSED */ QT_ARGS (t->top, 0, 0, 0, test06_aux2); QT_BLOCKI (test06_aux3, 0, 0, t->qt);#ifdef NDEF /* RETVALUSED */ QT_ARGS (t->top, 0, 0, 0, test06_aux2); QT_BLOCKI (test06_aux3, 0, 0, t->qt); /* RETVALUSED */ QT_ARGS (t->top, 0, 0, 0, test06_aux2); QT_BLOCKI (test06_aux3, 0, 0, t->qt); /* RETVALUSED */ QT_ARGS (t->top, 0, 0, 0, test06_aux2); QT_BLOCKI (test06_aux3, 0, 0, t->qt); /* RETVALUSED */ QT_ARGS (t->top, 0, 0, 0, test06_aux2); QT_BLOCKI (test06_aux3, 0, 0, t->qt); n -= 5;#else --n;#endif }}static char test07_msg[] = "*cswap between threads";static char const *test07_descr[] = { "Build a chain of threads where each thread has a fixed successor.", "There is no scheduling performed. Each thread but one is a loop", "that simply blocks with QT_BLOCKI, calling a helper that saves the", "current stack pointer. The last thread decrements a count, and,", "if zero, aborts back to the main thread. Else it continues with", "the blocking chain. The count is divided by the number of threads", "in the chain, so `n' is the number of integer block operations.", ":: integer cswap = QT_BLOCKI + a procedure call.", NULL};/* This test repeatedly blocks a bunch of threads. Each iteration corresponds to one block operation. The threads are arranged so that there are TEST07_N-1 of them that run `test07_aux2'. Each one of those blocks saving it's sp to storage owned by the preceding thread; a pointer to that storage is passed in via `mep'. Each thread has a handle on it's own storage for the next thread, referenced by `nxtp', and it blocks by passing control to `*nxtp', telling the helper function to save its state in `*mep'. The last thread in the chain decrements a count and, if it's gone below zero, returns to `test07'; otherwise, it invokes the first thread in the chain. */static qt_t *test07_heavy;#define TEST07_N (4) static voidtest07_aux2 (void *null0, void *mep, void *nxtp, qt_userf_t *null){ qt_t *nxt; while (1) { nxt = *(qt_t **)nxtp;#ifdef NDEF printf ("Helper 0x%p\n", nxtp);#endif QT_BLOCKI (t_splat, mep, 0, nxt); }} static voidtest07_aux3 (void *np, void *mep, void *nxtp, qt_userf_t *null){ int n; n = *(int *)np; while (1) { n -= TEST07_N; if (n<0) { QT_ABORT (t_splat, mep, 0, test07_heavy); } QT_BLOCKI (t_splat, mep, 0, *(qt_t **)nxtp); }} static voidtest07 (int n){ int i; thread_t *t[TEST07_N]; for (i=0; i<TEST07_N; ++i) { t[i] = t_create (0, 0, 0); } for (i=0; i<TEST07_N-1; ++i) { /* RETVALUSED */ QT_ARGS (t[i]->top, 0, &t[i]->qt, &t[i+1]->qt, test07_aux2); } /* RETVALUSED */ QT_ARGS (t[i]->top, &n, &t[TEST07_N-1]->qt, &t[0]->qt, test07_aux3); QT_BLOCKI (t_splat, &test07_heavy, 0, t[0]->qt);}static char test08_msg[] = "Floating-point cswap between threads";static char const *test08_descr[] = { "Measure context switch times including floating-point, use QT_BLOCK.", NULL};static qt_t *test08_heavy;#define TEST08_N (4) static voidtest08_aux2 (void *null0, void *mep, void *nxtp, qt_userf_t *null){ qt_t *nxt; while (1) { nxt = *(qt_t **)nxtp; QT_BLOCK (t_splat, mep, 0, nxt); }} static voidtest08_aux3 (void *np, void *mep, void *nxtp, qt_userf_t *null){ int n; n = *(int *)np; while (1) { n -= TEST08_N; if (n<0) { QT_ABORT (t_splat, mep, 0, test08_heavy); } QT_BLOCK (t_splat, mep, 0, *(qt_t **)nxtp); }} static voidtest08 (int n){ int i; thread_t *t[TEST08_N]; for (i=0; i<TEST08_N; ++i) { t[i] = t_create (0, 0, 0); } for (i=0; i<TEST08_N-1; ++i) { /* RETVALUSED */ QT_ARGS (t[i]->top, 0, &t[i]->qt, &t[i+1]->qt, test08_aux2); } /* RETVALUSED */ QT_ARGS (t[i]->top, &n, &t[TEST08_N-1]->qt, &t[0]->qt, test08_aux3); QT_BLOCK (t_splat, &test08_heavy, 0, t[0]->qt);}/* Test the varargs procedure calling. */char const test09_msg[] = { "Start and run threads using varargs." };thread_t *test09_t0, *test09_t1, *test09_t2, *test09_main; thread_t *test09_create (qt_startup_t *start, qt_vuserf_t *f, qt_cleanup_t *cleanup, int nbytes, ...){ va_list ap; thread_t *t;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -