1 /* meas.c -- measure qt stuff. */
2 
3 #include "copyright.h"
4 
5 /* Need this to get assertions under Mach on the Sequent/i386: */
6 #ifdef __i386__
7 #define assert(ex) \
8   do { \
9     if (!(ex)) { \
10       fprintf (stderr, "[%s:%d] Assertion " #ex " failed\n", __FILE__, __LINE__); \
11       abort(); \
12     } \
13   } while (0)
14 #else
15 #include <assert.h>
16 #endif
17 
18 /* This really ought to be defined in some ANSI include file (*I*
19    think...), but it's defined here instead, which leads us to another
20    machine dependency.
21 
22    The `iaddr_t' type is an integer representation of a pointer,
23    suited for doing arithmetic on addresses, e.g. to round an address
24    to an alignment boundary. */
25 typedef unsigned long iaddr_t;
26 
27 #include <stdarg.h>	/* For varargs tryout. */
28 #include <stdio.h>
29 #include "b.h"
30 #include "qt.h"
31 #include "stp.h"
32 
33 extern void exit (int status);
34 extern int atoi (char const *s);
35 extern int fprintf (FILE *out, char const *fmt, ...);
36 extern int fputs (char const *s, FILE *fp);
37 extern void free (void *sto);
38 extern void *malloc (unsigned nbytes);
39 extern void perror (char const *s);
40 
41 void usage (void);
42 void tracer(void);
43 
44 /* Round `v' to be `a'-aligned, assuming `a' is a power of two. */
45 #define ROUND(v, a)	(((v) + (a) - 1) & ~((a)-1))
46 
47 typedef struct thread_t {
48   qt_t *qt;		/* Pointer to thread of function... */
49   void *stk;
50   void *top;		/* Set top of stack if reuse. */
51   struct thread_t *next;
52 } thread_t;
53 
54 
55   static thread_t *
t_alloc(void)56 t_alloc (void)
57 {
58   thread_t *t;
59   int ssz = 0x1000;
60 
61   t = malloc (sizeof(thread_t));
62   if (!t) {
63     perror ("malloc");
64     exit (1);
65   }
66   assert (ssz > QT_STKBASE);
67   t->stk = malloc (ssz);
68   t->stk = (void *)ROUND (((iaddr_t)t->stk), QT_STKALIGN);
69   if (!t->stk) {
70     perror ("malloc");
71     exit (1);
72   }
73   assert ((((iaddr_t)t->stk) & (QT_STKALIGN-1)) == 0);
74   t->top = QT_SP (t->stk, ssz - QT_STKBASE);
75 
76   return (t);
77 }
78 
79 
80   static thread_t *
t_create(qt_only_t * starter,void * p0,qt_userf_t * f)81 t_create (qt_only_t *starter, void *p0, qt_userf_t *f)
82 {
83   thread_t *t;
84 
85   t = t_alloc();
86   t->qt = QT_ARGS (t->top, p0, t, f, starter);
87   return (t);
88 }
89 
90 
91   static void
t_free(thread_t * t)92 t_free (thread_t *t)
93 {
94   free (t->stk);
95   free (t);
96 }
97 
98 
99   static void *
t_null(qt_t * old,void * p1,void * p2)100 t_null (qt_t *old, void *p1, void *p2)
101 {
102   /* return (garbage); */
103 }
104 
105 
106   static void *
t_splat(qt_t * old,void * oldp,void * null)107 t_splat (qt_t *old, void *oldp, void *null)
108 {
109   *(qt_t **)oldp = old;
110   /* return (garbage); */
111 }
112 
113 
114 static char const test01_msg[] =
115   "*QT_SP(sto,sz), QT_ARGS(top,p0,p1,userf,first)";
116 
117 static char const *test01_descr[] = {
118   "Performs 1 QT_SP and one QT_ARGS per iteration.",
119   NULL
120 };
121 
122 /* This test gives a guess on how long it takes to initalize
123    a thread. */
124 
125   static void
test01(int n)126 test01 (int n)
127 {
128   char stack[QT_STKBASE+QT_STKALIGN];
129   char *stk;
130   qt_t *top;
131 
132   stk = (char *)ROUND (((iaddr_t)stack), QT_STKALIGN);
133 
134   {
135     int i;
136 
137     for (i=0; i<QT_STKBASE; ++i) {
138       stk[i] = 0;
139     }
140   }
141 
142   while (n>0) {
143     /* RETVALUSED */
144     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
145 #ifdef NDEF
146     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
147     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
148     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
149     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
150 
151     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
152     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
153     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
154     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
155     top = QT_SP (stk, QT_STKBASE);	QT_ARGS (top, 0, 0, 0, 0);
156 
157     n -= 10;
158 #else
159     n -= 1;
160 #endif
161   }
162 }
163 
164 
165 static char const test02_msg[] = "QT_BLOCKI (0, 0, test02_aux, t->qt)";
166 static qt_t *rootthread;
167 
168   static void
test02_aux1(void * pu,void * pt,qt_userf_t * f)169 test02_aux1 (void *pu, void *pt, qt_userf_t *f)
170 {
171   QT_ABORT (t_null, 0, 0, rootthread);
172 }
173 
174   static void *
test02_aux2(qt_t * old,void * farg1,void * farg2)175 test02_aux2 (qt_t *old, void *farg1, void *farg2)
176 {
177   rootthread = old;
178   /* return (garbage); */
179 }
180 
181   static void
test02(int n)182 test02 (int n)
183 {
184   thread_t *t;
185 
186   while (n>0) {
187   t = t_create (test02_aux1, 0, 0);
188     QT_BLOCKI (test02_aux2, 0, 0, t->qt);
189   t_free (t);
190   t = t_create (test02_aux1, 0, 0);
191     QT_BLOCKI (test02_aux2, 0, 0, t->qt);
192   t_free (t);
193   t = t_create (test02_aux1, 0, 0);
194     QT_BLOCKI (test02_aux2, 0, 0, t->qt);
195   t_free (t);
196   t = t_create (test02_aux1, 0, 0);
197     QT_BLOCKI (test02_aux2, 0, 0, t->qt);
198   t_free (t);
199   t = t_create (test02_aux1, 0, 0);
200     QT_BLOCKI (test02_aux2, 0, 0, t->qt);
201   t_free (t);
202 
203     n -= 5;
204   }
205 }
206 
207 
208 static char const test03_msg[] = "QT_BLOCKI (...) test vals are right.";
209 
210 
211 /* Called by the thread function when it wants to shut down.
212    Return a value to the main thread. */
213 
214   static void *
test03_aux0(qt_t * old_is_garbage,void * farg1,void * farg2)215 test03_aux0 (qt_t *old_is_garbage, void *farg1, void *farg2)
216 {
217   assert (farg1 == (void *)5);
218   assert (farg2 == (void *)6);
219   return ((void *)15);		/* Some unlikely value. */
220 }
221 
222 
223 /* Called during new thread startup by main thread.  Since the new
224    thread has never run before, return value is ignored. */
225 
226   static void *
test03_aux1(qt_t * old,void * farg1,void * farg2)227 test03_aux1 (qt_t *old, void *farg1, void *farg2)
228 {
229   assert (old != NULL);
230   assert (farg1 == (void *)5);
231   assert (farg2 == (void *)6);
232   rootthread = old;
233   return ((void *)16);		/* Different than `15'. */
234 }
235 
236   static void
test03_aux2(void * pu,void * pt,qt_userf_t * f)237 test03_aux2 (void *pu, void *pt, qt_userf_t *f)
238 {
239   assert (pu == (void *)1);
240   assert (f == (qt_userf_t *)4);
241   QT_ABORT (test03_aux0, (void *)5, (void *)6, rootthread);
242 }
243 
244   static void
test03(int n)245 test03 (int n)
246 {
247   thread_t *t;
248   void *rv;
249 
250   while (n>0) {
251     t = t_create (test03_aux2, (void *)1, (qt_userf_t *)4);
252     rv = QT_BLOCKI (test03_aux1, (void *)5, (void *)6, t->qt);
253     assert (rv == (void *)15);
254     t_free (t);
255 
256     --n;
257   }
258 }
259 
260 
261 static char const test04_msg[] = "stp_start w/ no threads.";
262 
263   static void
test04(int n)264 test04 (int n)
265 {
266   while (n>0) {
267     stp_init();	stp_start();
268     stp_init();	stp_start();
269     stp_init();	stp_start();
270     stp_init();	stp_start();
271     stp_init();	stp_start();
272 
273     stp_init();	stp_start();
274     stp_init();	stp_start();
275     stp_init();	stp_start();
276     stp_init();	stp_start();
277     stp_init();	stp_start();
278 
279     n -= 10;
280   }
281 }
282 
283 
284 static char const test05_msg[] = "stp w/ 2 yielding thread.";
285 
286   static void
test05_aux(void * null)287 test05_aux (void *null)
288 {
289   stp_yield();
290   stp_yield();
291 }
292 
293   static void
test05(int n)294 test05 (int n)
295 {
296   while (n>0) {
297     stp_init();
298     stp_create (test05_aux, 0);
299     stp_create (test05_aux, 0);
300     stp_start();
301 
302     --n;
303   }
304 }
305 
306 
307 static char const test06_msg[] = "*QT_ARGS(...), QT_BLOCKI one thread";
308 
309 static char const *test06_descr[] = {
310   "Does a QT_ARGS, QT_BLOCKI to a helper function that saves the",
311   "stack pointer of the main thread, calls an `only' function that",
312   "saves aborts the thread, calling a null helper function.",
313   ":: start/stop = QT_ARGS + QT_BLOCKI + QT_ABORT + 3 procedure calls.",
314   NULL
315 };
316 
317 /* This test initializes a thread, runs it, then returns to the main
318    program, which reinitializes the thread, runs it again, etc.  Each
319    iteration corresponds to 1 init, 1 abort, 1 block. */
320 
321 static qt_t *test06_sp;
322 
323 
324   static void
test06_aux2(void * null0a,void * null1b,void * null2b,qt_userf_t * null)325 test06_aux2 (void *null0a, void *null1b, void *null2b, qt_userf_t *null)
326 {
327   QT_ABORT (t_null, 0, 0, test06_sp);
328 }
329 
330 
331   static void *
test06_aux3(qt_t * sp,void * null0c,void * null1c)332 test06_aux3 (qt_t *sp, void *null0c, void *null1c)
333 {
334   test06_sp = sp;
335   /* return (garbage); */
336 }
337 
338 
339   static void
test06(int n)340 test06 (int n)
341 {
342   thread_t *t;
343 
344   t = t_create (0, 0, 0);
345 
346   while (n>0) {
347     /* RETVALUSED */
348     QT_ARGS (t->top, 0, 0, 0, test06_aux2);
349     QT_BLOCKI (test06_aux3, 0, 0, t->qt);
350 #ifdef NDEF
351     /* RETVALUSED */
352     QT_ARGS (t->top, 0, 0, 0, test06_aux2);
353     QT_BLOCKI (test06_aux3, 0, 0, t->qt);
354 
355     /* RETVALUSED */
356     QT_ARGS (t->top, 0, 0, 0, test06_aux2);
357     QT_BLOCKI (test06_aux3, 0, 0, t->qt);
358 
359     /* RETVALUSED */
360     QT_ARGS (t->top, 0, 0, 0, test06_aux2);
361     QT_BLOCKI (test06_aux3, 0, 0, t->qt);
362 
363     /* RETVALUSED */
364     QT_ARGS (t->top, 0, 0, 0, test06_aux2);
365     QT_BLOCKI (test06_aux3, 0, 0, t->qt);
366 
367     n -= 5;
368 #else
369     --n;
370 #endif
371   }
372 }
373 
374 static char test07_msg[] = "*cswap between threads";
375 
376 static char const *test07_descr[] = {
377   "Build a chain of threads where each thread has a fixed successor.",
378   "There is no scheduling performed.  Each thread but one is a loop",
379   "that simply blocks with QT_BLOCKI, calling a helper that saves the",
380   "current stack pointer.  The last thread decrements a count, and,",
381   "if zero, aborts back to the main thread.  Else it continues with",
382   "the blocking chain.  The count is divided by the number of threads",
383   "in the chain, so `n' is the number of integer block operations.",
384   ":: integer cswap = QT_BLOCKI + a procedure call.",
385   NULL
386 };
387 
388 /* This test repeatedly blocks a bunch of threads.
389    Each iteration corresponds to one block operation.
390 
391    The threads are arranged so that there are TEST07_N-1 of them that
392    run `test07_aux2'.  Each one of those blocks saving it's sp to
393    storage owned by the preceding thread; a pointer to that storage is
394    passed in via `mep'.  Each thread has a handle on it's own storage
395    for the next thread, referenced by `nxtp', and it blocks by passing
396    control to `*nxtp', telling the helper function to save its state
397    in `*mep'.  The last thread in the chain decrements a count and, if
398    it's gone below zero, returns to `test07'; otherwise, it invokes
399    the first thread in the chain. */
400 
401 static qt_t *test07_heavy;
402 
403 #define TEST07_N (4)
404 
405 
406   static void
test07_aux2(void * null0,void * mep,void * nxtp,qt_userf_t * null)407 test07_aux2 (void *null0, void *mep, void *nxtp, qt_userf_t *null)
408 {
409   qt_t *nxt;
410 
411   while (1) {
412     nxt = *(qt_t **)nxtp;
413 #ifdef NDEF
414     printf ("Helper 0x%p\n", nxtp);
415 #endif
416     QT_BLOCKI (t_splat, mep, 0, nxt);
417   }
418 }
419 
420   static void
test07_aux3(void * np,void * mep,void * nxtp,qt_userf_t * null)421 test07_aux3 (void *np, void *mep, void *nxtp, qt_userf_t *null)
422 {
423   int n;
424 
425   n = *(int *)np;
426   while (1) {
427     n -= TEST07_N;
428     if (n<0) {
429       QT_ABORT (t_splat, mep, 0, test07_heavy);
430     }
431     QT_BLOCKI (t_splat, mep, 0, *(qt_t **)nxtp);
432   }
433 }
434 
435 
436   static void
test07(int n)437 test07 (int n)
438 {
439   int i;
440   thread_t *t[TEST07_N];
441 
442   for (i=0; i<TEST07_N; ++i) {
443     t[i] = t_create (0, 0, 0);
444   }
445   for (i=0; i<TEST07_N-1; ++i) {
446     /* RETVALUSED */
447     QT_ARGS (t[i]->top, 0, &t[i]->qt, &t[i+1]->qt, test07_aux2);
448   }
449   /* RETVALUSED */
450   QT_ARGS (t[i]->top, &n, &t[TEST07_N-1]->qt, &t[0]->qt, test07_aux3);
451   QT_BLOCKI (t_splat, &test07_heavy, 0, t[0]->qt);
452 }
453 
454 
455 static char test08_msg[] = "Floating-point cswap between threads";
456 
457 static char const *test08_descr[] = {
458   "Measure context switch times including floating-point, use QT_BLOCK.",
459   NULL
460 };
461 
462 static qt_t *test08_heavy;
463 
464 #define TEST08_N (4)
465 
466 
467   static void
test08_aux2(void * null0,void * mep,void * nxtp,qt_userf_t * null)468 test08_aux2 (void *null0, void *mep, void *nxtp, qt_userf_t *null)
469 {
470   qt_t *nxt;
471 
472   while (1) {
473     nxt = *(qt_t **)nxtp;
474     QT_BLOCK (t_splat, mep, 0, nxt);
475   }
476 }
477 
478   static void
test08_aux3(void * np,void * mep,void * nxtp,qt_userf_t * null)479 test08_aux3 (void *np, void *mep, void *nxtp, qt_userf_t *null)
480 {
481   int n;
482 
483   n = *(int *)np;
484   while (1) {
485     n -= TEST08_N;
486     if (n<0) {
487       QT_ABORT (t_splat, mep, 0, test08_heavy);
488     }
489     QT_BLOCK (t_splat, mep, 0, *(qt_t **)nxtp);
490   }
491 }
492 
493 
494   static void
test08(int n)495 test08 (int n)
496 {
497   int i;
498   thread_t *t[TEST08_N];
499 
500   for (i=0; i<TEST08_N; ++i) {
501     t[i] = t_create (0, 0, 0);
502   }
503   for (i=0; i<TEST08_N-1; ++i) {
504     /* RETVALUSED */
505     QT_ARGS (t[i]->top, 0, &t[i]->qt, &t[i+1]->qt, test08_aux2);
506   }
507   /* RETVALUSED */
508   QT_ARGS (t[i]->top, &n, &t[TEST08_N-1]->qt, &t[0]->qt, test08_aux3);
509   QT_BLOCK (t_splat, &test08_heavy, 0, t[0]->qt);
510 }
511 
512 
513 /* Test the varargs procedure calling. */
514 
515 char const test09_msg[] = { "Start and run threads using varargs." };
516 
517 thread_t *test09_t0, *test09_t1, *test09_t2, *test09_main;
518 
519   thread_t *
test09_create(qt_startup_t * start,qt_vuserf_t * f,qt_cleanup_t * cleanup,int nbytes,...)520 test09_create (qt_startup_t *start, qt_vuserf_t *f,
521 	       qt_cleanup_t *cleanup, int nbytes, ...)
522 {
523   va_list ap;
524   thread_t *t;
525 
526   t = t_alloc();
527   va_start (ap, nbytes);
528   t->qt = QT_VARGS (t->top, nbytes, ap, t, start, f, cleanup);
529   va_end (ap);
530   return (t);
531 }
532 
533 
534   static void
test09_cleanup(void * pt,void * vuserf_retval)535 test09_cleanup (void *pt, void *vuserf_retval)
536 {
537   assert (vuserf_retval == (void *)17);
538   QT_ABORT (t_splat, &((thread_t *)pt)->qt, 0,
539 	    ((thread_t *)pt)->next->qt);
540 }
541 
542 
543   static void
test09_start(void * pt)544 test09_start (void *pt)
545 {
546 }
547 
548 
549   static void *
test09_user0(void)550 test09_user0 (void)
551 {
552   QT_BLOCKI (t_splat, &test09_t0->qt, 0, test09_t1->qt);
553   return ((void *)17);
554 }
555 
556   static void *
test09_user2(int one,int two)557 test09_user2 (int one, int two)
558 {
559   assert (one == 1);
560   assert (two == 2);
561   QT_BLOCKI (t_splat, &test09_t1->qt, 0, test09_t2->qt);
562   assert (one == 1);
563   assert (two == 2);
564   return ((void *)17);
565 }
566 
567   static void *
test09_user10(int one,int two,int three,int four,int five,int six,int seven,int eight,int nine,int ten)568 test09_user10 (int one, int two, int three, int four, int five,
569 	      int six, int seven, int eight, int nine, int ten)
570 {
571   assert (one == 1);
572   assert (two == 2);
573   assert (three == 3);
574   assert (four == 4);
575   assert (five == 5);
576   assert (six == 6);
577   assert (seven == 7);
578   assert (eight == 8);
579   assert (nine == 9);
580   assert (ten == 10);
581   QT_BLOCKI (t_splat, &test09_t2->qt, 0, test09_main->qt);
582   assert (one == 1);
583   assert (two == 2);
584   assert (three == 3);
585   assert (four == 4);
586   assert (five == 5);
587   assert (six == 6);
588   assert (seven == 7);
589   assert (eight == 8);
590   assert (nine == 9);
591   assert (ten == 10);
592   return ((void *)17);
593 }
594 
595 
596   void
test09(int n)597 test09 (int n)
598 {
599   thread_t main;
600 
601   test09_main = &main;
602 
603   while (--n >= 0) {
604     test09_t0 = test09_create (test09_start, (qt_vuserf_t*)test09_user0,
605 			       test09_cleanup, 0);
606     test09_t1 = test09_create (test09_start, (qt_vuserf_t*)test09_user2,
607 			       test09_cleanup, 2 * sizeof(qt_word_t), 1, 2);
608     test09_t2 = test09_create (test09_start, (qt_vuserf_t*)test09_user10,
609 			       test09_cleanup, 10 * sizeof(qt_word_t),
610 			       1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
611 
612     /* Chaining used by `test09_cleanup' to determine who is next. */
613     test09_t0->next = test09_t1;
614     test09_t1->next = test09_t2;
615     test09_t2->next = test09_main;
616 
617     QT_BLOCKI (t_splat, &test09_main->qt, 0, test09_t0->qt);
618     QT_BLOCKI (t_splat, &test09_main->qt, 0, test09_t0->qt);
619 
620     t_free (test09_t0);
621     t_free (test09_t1);
622     t_free (test09_t2);
623   }
624 }
625 
626 
627 /* Test 10/11/12: time the cost of various number of args. */
628 
629 char const test10_msg[] = { "*Test varargs init & startup w/ 0 args." };
630 
631 char const *test10_descr[] = {
632   "Start and stop threads that use variant argument lists (varargs).",
633   "Each thread is initialized by calling a routine that calls",
634   "QT_VARARGS.  Then runs the thread by calling QT_BLOCKI to hald the",
635   "main thread, a helper that saves the main thread's stack pointer,",
636   "a null startup function, a null user function, a cleanup function",
637   "that calls QT_ABORT and restarts the main thread.  Copies no user",
638   "parameters.",
639   ":: varargs start/stop = QT_BLOCKI + QT_ABORT + 6 function calls.",
640   NULL
641 };
642 
643 /* Helper function to send control back to main.
644    Don't save anything. */
645 
646 
647 /* Helper function for starting the varargs thread.  Save the stack
648    pointer of the main thread so we can get back there eventually. */
649 
650 
651 /* Startup function for a varargs thread. */
652 
653   static void
test10_startup(void * pt)654 test10_startup (void *pt)
655 {
656 }
657 
658 
659 /* User function for a varargs thread. */
660 
661   static void *
test10_run(int arg0,...)662 test10_run (int arg0, ...)
663 {
664   /* return (garbage); */
665 }
666 
667 
668 /* Cleanup function for a varargs thread.  Send control
669    back to the main thread.  Don't save any state from the thread that
670    is halting. */
671 
672   void
test10_cleanup(void * pt,void * vuserf_retval)673 test10_cleanup (void *pt, void *vuserf_retval)
674 {
675   QT_ABORT (t_null, 0, 0, ((thread_t *)pt)->qt);
676 }
677 
678 
679   void
test10_init(thread_t * new,thread_t * next,int nbytes,...)680 test10_init (thread_t *new, thread_t *next, int nbytes, ...)
681 {
682   va_list ap;
683 
684   va_start (ap, nbytes);
685   new->qt = QT_VARGS (new->top, nbytes, ap, next, test10_startup,
686 		      test10_run, test10_cleanup);
687   va_end (ap);
688 }
689 
690 
691   void
test10(int n)692 test10 (int n)
693 {
694   thread_t main;
695   thread_t *t;
696 
697   t = t_alloc();
698   t->next = &main;
699 
700   while (--n >= 0) {
701     test10_init (t, &main, 0);
702     QT_BLOCKI (t_splat, &main.qt, 0, t->qt);
703   }
704   t_free (t);
705 }
706 
707 
708 char const test11_msg[] = { "*Test varargs init & startup w/ 2 args." };
709 
710 char const *test11_descr[] = {
711   "Varargs initialization/run.  Copies 2 user arguments.",
712   ":: varargs 2 start/stop = QT_VARGS(2 args), QT_BLOCKI, QT_ABORT, 6 f() calls.",
713   NULL
714 };
715 
716 
717   void
test11(int n)718 test11 (int n)
719 {
720   thread_t main;
721   thread_t *t;
722 
723   t = t_alloc();
724   t->next = &main;
725 
726   while (--n >= 0) {
727     test10_init (t, &main, 2 * sizeof(int), 2, 1);
728     QT_BLOCKI (t_splat, &main.qt, 0, t->qt);
729   }
730   t_free (t);
731 }
732 
733 char const test12_msg[] = { "*Test varargs init & startup w/ 4 args." };
734 
735 char const *test12_descr[] = {
736   "Varargs initialization/run.  Copies 4 user arguments.",
737   ":: varargs 4 start/stop = QT_VARGS(4 args), QT_BLOCKI, QT_ABORT, 6 f() calls.",
738   NULL
739 };
740 
741 
742   void
test12(int n)743 test12 (int n)
744 {
745   thread_t main;
746   thread_t *t;
747 
748   t = t_alloc();
749   t->next = &main;
750 
751   while (--n >= 0) {
752     test10_init (t, &main, 4 * sizeof(int), 4, 3, 2, 1);
753     QT_BLOCKI (t_splat, &main.qt, 0, t->qt);
754   }
755   t_free (t);
756 }
757 
758 
759 char const test13_msg[] = { "*Test varargs init & startup w/ 8 args." };
760 
761 char const *test13_descr[] = {
762   "Varargs initialization/run.  Copies 8 user arguments.",
763   ":: varargs 8 start/stop = QT_VARGS(8 args), QT_BLOCKI, QT_ABORT, 6 f() calls.",
764   NULL
765 };
766 
767   void
test13(int n)768 test13 (int n)
769 {
770   thread_t main;
771   thread_t *t;
772 
773   t = t_alloc();
774   t->next = &main;
775 
776   while (--n >= 0) {
777     test10_init (t, &main, 8 * sizeof(int), 8, 7, 6, 5, 4, 3, 2, 1);
778     QT_BLOCKI (t_splat, &main.qt, 0, t->qt);
779   }
780   t_free (t);
781 }
782 
783 
784 char const test14_msg[] = { "*Test varargs initialization w/ 0 args." };
785 
786 char const *test14_descr[] = {
787   "Varargs initialization without running the thread.  Just calls",
788   "QT_VARGS.",
789   ":: varargs 0 init = QT_VARGS()",
790   NULL
791 };
792 
793   void
test14(int n)794 test14 (int n)
795 {
796   thread_t main;
797   thread_t *t;
798 
799   t = t_alloc();
800   t->next = &main;
801 
802   while (--n >= 0) {
803     test10_init (t, &main, 0 * sizeof(int));
804   }
805   t_free (t);
806 }
807 
808 
809 char const test15_msg[] = { "*Test varargs initialization w/ 2 args." };
810 
811 char const *test15_descr[] = {
812   "Varargs initialization without running the thread.  Just calls",
813   "QT_VARGS.",
814   ":: varargs 2 init = QT_VARGS(2 args)",
815   NULL
816 };
817 
818   void
test15(int n)819 test15 (int n)
820 {
821   thread_t main;
822   thread_t *t;
823 
824   t = t_alloc();
825   t->next = &main;
826 
827   while (--n >= 0) {
828     test10_init (t, &main, 2 * sizeof(int), 2, 1);
829   }
830   t_free (t);
831 }
832 
833 char const test16_msg[] = { "*Test varargs initialization w/ 4 args." };
834 
835 char const *test16_descr[] = {
836   "Varargs initialization without running the thread.  Just calls",
837   "QT_VARGS.",
838   ":: varargs 4 init = QT_VARGS(4 args)",
839   NULL
840 };
841 
842 
843   void
test16(int n)844 test16 (int n)
845 {
846   thread_t main;
847   thread_t *t;
848 
849   t = t_alloc();
850   t->next = &main;
851 
852   while (--n >= 0) {
853     test10_init (t, &main, 4 * sizeof(int), 4, 3, 2, 1);
854   }
855   t_free (t);
856 }
857 
858 
859 char const test17_msg[] = { "*Test varargs initialization w/ 8 args." };
860 
861 char const *test17_descr[] = {
862   "Varargs initialization without running the thread.  Just calls",
863   "QT_VARGS.",
864   ":: varargs 8 init = QT_VARGS(8 args)",
865   NULL
866 };
867 
868 
869   void
test17(int n)870 test17 (int n)
871 {
872   thread_t main;
873   thread_t *t;
874 
875   t = t_alloc();
876   t->next = &main;
877 
878   while (--n >= 0) {
879     test10_init (t, &main, 8 * sizeof(int), 8, 7, 6, 5, 4, 3, 2, 1);
880   }
881   t_free (t);
882 }
883 
884 /* Test times for basic machine operations. */
885 
886 char const test18_msg[] = { "*Call register indirect." };
887 char const *test18_descr[] = { NULL };
888 
889   void
test18(int n)890 test18 (int n)
891 {
892   b_call_reg (n);
893 }
894 
895 
896 char const test19_msg[] = { "*Call immediate." };
897 char const *test19_descr[] = { NULL };
898 
899   void
test19(int n)900 test19 (int n)
901 {
902   b_call_imm (n);
903 }
904 
905 
906 char const test20_msg[] = { "*Add register-to-register." };
907 char const *test20_descr[] = { NULL };
908 
909   void
test20(int n)910 test20 (int n)
911 {
912   b_add (n);
913 }
914 
915 
916 char const test21_msg[] = { "*Load memory to a register." };
917 char const *test21_descr[] = { NULL };
918 
919   void
test21(int n)920 test21 (int n)
921 {
922   b_load (n);
923 }
924 
925 /* Driver. */
926 
927 typedef struct foo_t {
928     char const *msg;	/* Message to print for generic help. */
929     char const **descr;	/* A description of what is done by the test. */
930     void (*f)(int n);
931 } foo_t;
932 
933 
934 static foo_t foo[] = {
935   { "Usage:\n", NULL, (void(*)(int n))usage },
936   { test01_msg, test01_descr, test01 },
937   { test02_msg, NULL, test02 },
938   { test03_msg, NULL, test03 },
939   { test04_msg, NULL, test04 },
940   { test05_msg, NULL, test05 },
941   { test06_msg, test06_descr, test06 },
942   { test07_msg, test07_descr, test07 },
943   { test08_msg, test08_descr, test08 },
944   { test09_msg, NULL, test09 },
945   { test10_msg, test10_descr, test10 },
946   { test11_msg, test11_descr, test11 },
947   { test12_msg, test12_descr, test12 },
948   { test13_msg, test13_descr, test13 },
949   { test14_msg, test14_descr, test14 },
950   { test15_msg, test15_descr, test15 },
951   { test16_msg, test16_descr, test16 },
952   { test17_msg, test17_descr, test17 },
953   { test18_msg, test18_descr, test18 },
954   { test19_msg, test19_descr, test19 },
955   { test20_msg, test20_descr, test20 },
956   { test21_msg, test21_descr, test21 },
957   { 0, 0 }
958 };
959 
960 static int tv = 0;
961 
962   void
tracer()963 tracer ()
964 {
965 
966   fprintf (stderr, "tracer\t%d\n", tv++);
967   fflush (stderr);
968 }
969 
970   void
tracer2(void * val)971 tracer2 (void *val)
972 {
973   fprintf (stderr, "tracer2\t%d val=0x%p", tv++, val);
974   fflush (stderr);
975 }
976 
977 
978   void
describe()979 describe()
980 {
981   int i;
982   FILE *out = stdout;
983 
984   for (i=0; foo[i].msg; ++i) {
985     if (foo[i].descr) {
986       int j;
987 
988       putc ('\n', out);
989       fprintf (out, "[%d]\n", i);
990       for (j=0; foo[i].descr[j]; ++j) {
991 	fputs (foo[i].descr[j], out);
992 	putc ('\n', out);
993       }
994     }
995   }
996   exit (0);
997 }
998 
999 
1000   void
usage()1001 usage()
1002 {
1003   int i;
1004 
1005   fputs (foo[0].msg, stderr);
1006   for (i=1; foo[i].msg; ++i) {
1007     fprintf (stderr, "%2d\t%s\n", i, foo[i].msg);
1008   }
1009   exit (1);
1010 }
1011 
1012 
1013   void
args(int * which,int * n,int argc,char ** argv)1014 args (int *which, int *n, int argc, char **argv)
1015 {
1016   static int nfuncs = 0;
1017 
1018   if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'h') {
1019     describe();
1020   }
1021 
1022   if (nfuncs == 0) {
1023     for (nfuncs=0; foo[nfuncs].msg; ++nfuncs)
1024       ;
1025   }
1026 
1027   if (argc != 2 && argc != 3) {
1028     usage();
1029   }
1030 
1031   *which = atoi (argv[1]);
1032   if (*which < 0 || *which >= nfuncs) {
1033     usage();
1034   }
1035   *n = (argc == 3)
1036     ? atoi (argv[2])
1037     : 1;
1038 }
1039 
1040 
1041   int
main(int argc,char ** argv)1042 main (int argc, char **argv)
1043 {
1044   int which, n;
1045   args (&which, &n, argc, argv);
1046   (*(foo[which].f))(n);
1047   exit (0);
1048   return (0);
1049 }
1050