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