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