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