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. */
25typedef 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
33extern void exit (int status);
34extern int atoi (char const *s);
35extern int fprintf (FILE *out, char const *fmt, ...);
36extern int fputs (char const *s, FILE *fp);
37extern void free (void *sto);
38extern void *malloc (unsigned nbytes);
39extern void perror (char const *s);
40
41void usage (void);
42void 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
47typedef 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 *
56t_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 *
81t_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
92t_free (thread_t *t)
93{
94  free (t->stk);
95  free (t);
96}
97
98
99  static void *
100t_null (qt_t *old, void *p1, void *p2)
101{
102  /* return (garbage); */
103}
104
105
106  static void *
107t_splat (qt_t *old, void *oldp, void *null)
108{
109  *(qt_t **)oldp = old;
110  /* return (garbage); */
111}
112
113
114static char const test01_msg[] =
115  "*QT_SP(sto,sz), QT_ARGS(top,p0,p1,userf,first)";
116
117static 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
126test01 (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
165static char const test02_msg[] = "QT_BLOCKI (0, 0, test02_aux, t->qt)";
166static qt_t *rootthread;
167
168  static void
169test02_aux1 (void *pu, void *pt, qt_userf_t *f)
170{
171  QT_ABORT (t_null, 0, 0, rootthread);
172}
173
174  static void *
175test02_aux2 (qt_t *old, void *farg1, void *farg2)
176{
177  rootthread = old;
178  /* return (garbage); */
179}
180
181  static void
182test02 (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
208static 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 *
215test03_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 *
227test03_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
237test03_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
245test03 (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
261static char const test04_msg[] = "stp_start w/ no threads.";
262
263  static void
264test04 (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
284static char const test05_msg[] = "stp w/ 2 yielding thread.";
285
286  static void
287test05_aux (void *null)
288{
289  stp_yield();
290  stp_yield();
291}
292
293  static void
294test05 (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
307static char const test06_msg[] = "*QT_ARGS(...), QT_BLOCKI one thread";
308
309static 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
321static qt_t *test06_sp;
322
323
324  static void
325test06_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 *
332test06_aux3 (qt_t *sp, void *null0c, void *null1c)
333{
334  test06_sp = sp;
335  /* return (garbage); */
336}
337
338
339  static void
340test06 (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
374static char test07_msg[] = "*cswap between threads";
375
376static 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
401static qt_t *test07_heavy;
402
403#define TEST07_N (4)
404
405
406  static void
407test07_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
421test07_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
437test07 (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
455static char test08_msg[] = "Floating-point cswap between threads";
456
457static char const *test08_descr[] = {
458  "Measure context switch times including floating-point, use QT_BLOCK.",
459  NULL
460};
461
462static qt_t *test08_heavy;
463
464#define TEST08_N (4)
465
466
467  static void
468test08_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
479test08_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
495test08 (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
515char const test09_msg[] = { "Start and run threads using varargs." };
516
517thread_t *test09_t0, *test09_t1, *test09_t2, *test09_main;
518
519  thread_t *
520test09_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
535test09_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
544test09_start (void *pt)
545{
546}
547
548
549  static void *
550test09_user0 (void)
551{
552  QT_BLOCKI (t_splat, &test09_t0->qt, 0, test09_t1->qt);
553  return ((void *)17);
554}
555
556  static void *
557test09_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 *
568test09_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
597test09 (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
629char const test10_msg[] = { "*Test varargs init & startup w/ 0 args." };
630
631char 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
654test10_startup (void *pt)
655{
656}
657
658
659/* User function for a varargs thread. */
660
661  static void *
662test10_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
673test10_cleanup (void *pt, void *vuserf_retval)
674{
675  QT_ABORT (t_null, 0, 0, ((thread_t *)pt)->qt);
676}
677
678
679  void
680test10_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
692test10 (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
708char const test11_msg[] = { "*Test varargs init & startup w/ 2 args." };
709
710char 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
718test11 (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
733char const test12_msg[] = { "*Test varargs init & startup w/ 4 args." };
734
735char 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
743test12 (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
759char const test13_msg[] = { "*Test varargs init & startup w/ 8 args." };
760
761char 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
768test13 (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
784char const test14_msg[] = { "*Test varargs initialization w/ 0 args." };
785
786char 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
794test14 (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
809char const test15_msg[] = { "*Test varargs initialization w/ 2 args." };
810
811char 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
819test15 (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
833char const test16_msg[] = { "*Test varargs initialization w/ 4 args." };
834
835char 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
844test16 (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
859char const test17_msg[] = { "*Test varargs initialization w/ 8 args." };
860
861char 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
870test17 (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
886char const test18_msg[] = { "*Call register indirect." };
887char const *test18_descr[] = { NULL };
888
889  void
890test18 (int n)
891{
892  b_call_reg (n);
893}
894
895
896char const test19_msg[] = { "*Call immediate." };
897char const *test19_descr[] = { NULL };
898
899  void
900test19 (int n)
901{
902  b_call_imm (n);
903}
904
905
906char const test20_msg[] = { "*Add register-to-register." };
907char const *test20_descr[] = { NULL };
908
909  void
910test20 (int n)
911{
912  b_add (n);
913}
914
915
916char const test21_msg[] = { "*Load memory to a register." };
917char const *test21_descr[] = { NULL };
918
919  void
920test21 (int n)
921{
922  b_load (n);
923}
924
925/* Driver. */
926
927typedef 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
934static 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
960static int tv = 0;
961
962  void
963tracer ()
964{
965
966  fprintf (stderr, "tracer\t%d\n", tv++);
967  fflush (stderr);
968}
969
970  void
971tracer2 (void *val)
972{
973  fprintf (stderr, "tracer2\t%d val=0x%p", tv++, val);
974  fflush (stderr);
975}
976
977
978  void
979describe()
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
1001usage()
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
1014args (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
1042main (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