1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include <interp.h> 7 #include "io.h" 8 #include "../port/error.h" 9 #include <isa.h> 10 #include "kernel.h" 11 12 /* Builtin module support */ 13 #include "bench.h" 14 #include "benchmod.h" 15 16 typedef enum { None, Calibrate, Base, Op, Intr, Dis, Gc, MS2T, xTest}; 17 static struct { 18 int inuse; /* reference count */ 19 int test; 20 void* scratch; 21 char* buf; 22 int bufsz; 23 char* wpos; 24 void (*op)(void); 25 vlong tickstart; 26 } bench; 27 28 static void 29 log(char *msg, ...) 30 { 31 va_list ap; 32 33 va_start(ap, msg); 34 bench.wpos = vseprint(bench.wpos, bench.buf+bench.bufsz, msg, ap); 35 va_end(ap); 36 } 37 38 void 39 elog(char *msg, ...) 40 { 41 va_list ap; 42 43 if(bench.buf == 0) 44 return; 45 va_start(ap, msg); 46 bench.wpos = vseprint(bench.wpos, bench.buf+bench.bufsz, msg, ap); 47 va_end(ap); 48 } 49 50 static void 51 clear(void) 52 { 53 bench.wpos = bench.buf; 54 } 55 56 static long 57 rep(void *to, long n, ulong offset) 58 { 59 long left = bench.wpos - bench.buf - offset; 60 if(left < 0) 61 left = 0; 62 if(n > left) 63 n = left; 64 memmove(to, bench.buf+offset, n); 65 return n; 66 } 67 68 static long 69 notest(int report, void *va, long n, ulong offset) 70 { 71 USED(report, va, n, offset); 72 if(report) 73 return rep(va, n, offset); 74 return 0; 75 } 76 77 // Calibration 78 static long MS2TS = 0; // time stamps per millisec 79 static long US2TS = 0; // time stamps per microsecond 80 81 static long 82 cal(int report, void *va, long n, ulong offset) 83 { 84 int tot, i, lim, low, max, pl, mdelay; 85 ulong t; 86 if(report) 87 return rep(va, n, offset); 88 clear(); 89 setpri(PriRealtime); 90 lim = 1000; 91 low = 64000000; 92 max = 0; 93 tot = 0; 94 mdelay = 1000; 95 for(i=0; i<lim; i++){ 96 do{ 97 pl = splhi(); 98 t = archrdtsc32(); 99 microdelay(mdelay); 100 t = archrdtsc32() - t; 101 splx(pl); 102 } while(t < 0); 103 if(t < low) 104 low = t; 105 if(t > max) 106 max = t; 107 tot += t; 108 } 109 MS2TS = tot/lim; 110 US2TS = MS2TS/1000; 111 if(va) 112 log("mdelay=%lud lim=%lud tot=%lud low=%lud max=%lud\n", mdelay, lim, tot, low, max); 113 setpri(PriNormal); 114 return n; 115 } 116 117 /* 118 * ticks to format string 119 */ 120 /*static*/ char * 121 ts2str(vlong ticks) 122 { 123 #define Nbuf 5 124 static char b[Nbuf][40]; 125 static int n=Nbuf-1; 126 char *fmt, *unit; 127 double d; 128 129 if(0){ 130 print("ticks=%lld MS2TS=%ld\n", ticks, MS2TS); 131 d = (double)ticks; 132 print("1:%f\n", d); 133 d = (double)ticks*1000; 134 //print("2:%f\n", d); 135 d = ((double)ticks)/MS2TS; 136 //print("3:%f\n", d); 137 } 138 n = (n+1)%Nbuf; 139 if(ticks > MS2TS*1000) { 140 fmt = "%.2f %s"; 141 unit = "s"; 142 d = ((double)ticks/MS2TS) * 1000.0; 143 } else if(ticks > MS2TS) { 144 fmt = "%.2f %s"; 145 unit = "ms"; 146 d = (double)ticks/MS2TS; 147 } else if(ticks > MS2TS/1000) { 148 fmt = "%.2f %s"; 149 unit = "us"; 150 d = ((double)ticks*1000)/MS2TS; 151 } else { 152 fmt = "%.2f %s"; 153 unit = "ns"; 154 d = ((double)ticks*1000*1000)/MS2TS; 155 } 156 sprint(b[n], fmt, d, unit); 157 return b[n]; 158 } 159 160 /* 161 * ticks to microseconds 162 */ 163 static double 164 ts2us(vlong ticks) 165 { 166 return ((double)ticks*1000)/MS2TS; 167 } 168 169 /* 170 * microseconds timestamp 171 */ 172 static vlong 173 bus(int reset) 174 { 175 vlong now; 176 if(US2TS == 0) 177 return 0; 178 if(reset) { 179 bench.tickstart = archrdtsc(); 180 return 0; 181 } 182 now = archrdtsc(); 183 return ((now-bench.tickstart))/US2TS; 184 } 185 186 // Base 187 static long 188 base(int report, void *va, long n, ulong offset) 189 { 190 int tot, i, lim, low, max, pl; 191 ulong t; 192 char *bm; 193 194 if(report) 195 return rep(va, n, offset); 196 clear(); 197 setpri(PriRealtime); 198 lim = 1000; 199 low = 64000000; 200 max = 0; 201 tot = 0; 202 for(i=0; i<lim; i++){ 203 do { 204 pl = splhi(); 205 t = archrdtsc32(); 206 // do nothing 207 t = archrdtsc32() - t; 208 splx(pl); 209 } while(t < 0); 210 if(t < low) 211 low = t; 212 if(t > max) 213 max = t; 214 tot += t; 215 } 216 bm = ts2str(tot/lim); 217 log("%d %lud %lud %lud %lud (%s)\n", up->pid, lim, tot, low, max, bm); 218 setpri(PriNormal); 219 return n; 220 } 221 222 // Timeop 223 224 typedef struct Psync Psync; 225 226 enum { 227 Maxprocs=3, 228 }; 229 230 struct Psync { 231 Rendez r; 232 int flag; 233 int id; 234 int awaken; 235 }; 236 static Psync timesync[Maxprocs]; 237 static Ref nactive; 238 static Ref nbusy; 239 static RWlock sync; 240 241 static void 242 nilop(void) 243 { 244 } 245 246 static int 247 timev(void *a) 248 { 249 return *(int*)a; 250 } 251 252 static void 253 timeop0(void *ap) 254 { 255 int tot, i, lim, low, max; 256 ulong t; 257 Psync *ps; 258 char *bm; 259 260 ps = ap; 261 setpri(PriRealtime); 262 incref(&nactive); 263 sleep(&ps->r, timev, &ps->flag); 264 rlock(&sync); 265 lim = 1000; 266 low = 64000000; 267 max = 0; 268 tot = 0; 269 for(i=0; i<lim; i++){ 270 do{ 271 t = archrdtsc32(); 272 (*bench.op)(); 273 t = archrdtsc32() - t; 274 }while(t < 0); 275 if(t < low) 276 low = t; 277 if(t > max) 278 max = t; 279 tot += t; 280 } 281 bm = ts2str(tot/lim); 282 log("%d %lud %lud %lud %lud (%s)\n", up->pid, lim, tot, low, max, bm); 283 runlock(&sync); 284 pexit("", 0); 285 } 286 287 static long 288 timeop(int report, void *va, long n, ulong offset) 289 { 290 int i, np, pl; 291 292 if(report) 293 return rep(va, n, offset); 294 clear(); 295 bench.op = 0; 296 if(strncmp(va, "nil", 3) == 0) 297 bench.op = nilop; 298 else if(strncmp(va, "sched", 5) == 0) 299 bench.op = sched; 300 else 301 return 0; 302 for(np=1; np<=Maxprocs; np++) { 303 nactive.ref = 0; 304 wlock(&sync); 305 log("%d procs\n", np); 306 setpri(PriRealtime); 307 for(i=0; i<np; i++) { 308 timesync[i].id = i; 309 kproc("timeop", timeop0, ×ync[i], 0); 310 } 311 while(nactive.ref < np) 312 tsleep(&up->sleep, return0, 0, 20); 313 for(i=0; i<np; i++){ 314 timesync[i].flag = 1; 315 wakeup(×ync[i].r); 316 } 317 sched(); 318 pl = splhi(); 319 setpri(PriNormal); 320 wunlock(&sync); 321 // now they run 322 wlock(&sync); // wait for last reader 323 wunlock(&sync); 324 splx(pl); 325 } 326 return n; 327 } 328 329 typedef struct Ictr Ictr; 330 struct Ictr { 331 ulong base; 332 ulong sleep; 333 ulong spllo; 334 ulong intr; 335 ulong isave; 336 ulong arrive; 337 ulong wakeup; 338 ulong awake; 339 }; 340 static Ictr counters[5/*100*/], *curct; 341 static int intrwant; 342 static Rendez vous; 343 int spltbl; /* set by spllo */ 344 int intrtbl; /* set by intrvec() */ 345 int isavetbl; /* set by intrvec() */ 346 347 static int ienable; 348 349 350 static void 351 intrwake(void) 352 { 353 if(ienable == 0) 354 return; 355 ienable = 0; 356 if(spltbl == 0) // not used here 357 curct->spllo = curct->intr = curct->isave = archrdtsc32(); 358 else { 359 curct->spllo = spltbl; 360 curct->intr = intrtbl; 361 curct->isave = isavetbl; 362 } 363 curct->arrive = archrdtsc32(); 364 intrwant = 0; 365 wakeup(&vous); 366 curct->wakeup = archrdtsc32(); 367 } 368 369 /* 370 * sleep calls intrtest with splhi (under lock): 371 * provoke the interrupt now, so that it is guaranteed 372 * not to happen until sleep has queued the process, 373 * forcing wakeup to do something. 374 */ 375 static int 376 intrtest(void*) 377 { 378 ienable = 1; /* enable recording on interrupt */ 379 curct->sleep = archrdtsc32(); 380 return intrwant==0; 381 } 382 383 static long 384 intrtime(int report, void *va, long n, ulong offset) 385 { 386 Ictr *ic; 387 long t; 388 int i; 389 char *bm; 390 if(report) 391 return rep(va, n, offset); 392 clear(); 393 394 setpri(PriRealtime); 395 sched(); 396 curct = counters; 397 ienable = 0; 398 addclock0link(intrwake, MS2HZ); 399 for(i=0; i<nelem(counters); i++){ 400 curct = &counters[i]; 401 intrwant = 1; 402 curct->base = archrdtsc32(); 403 sleep(&vous, intrtest, nil); 404 curct->awake = archrdtsc32(); 405 sched(); /* just to slow it down between trials */ 406 } 407 log("interrupt\n"); 408 for(i=0; i<nelem(counters); i++){ 409 ic = &counters[i]; 410 t = ic->awake - ic->base; 411 bm = ts2str(ic->awake - ic->arrive); 412 ic->awake -= ic->wakeup; 413 ic->wakeup -= ic->arrive; 414 ic->arrive -= ic->isave; 415 ic->isave -= ic->intr; 416 ic->intr -= ic->spllo; 417 ic->spllo -= ic->sleep; 418 ic->sleep -= ic->base; 419 log("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld (%s)\n", ic->sleep, ic->spllo, ic->intr, ic->isave, ic->arrive, ic->wakeup, ic->awake, t, bm); 420 } 421 setpri(PriNormal); 422 return n; 423 } 424 425 426 /* DIS operation timing */ 427 428 typedef struct { 429 vlong n; /* count */ 430 vlong min; 431 vlong max; 432 vlong sum; 433 vlong sumsq; /* sum of squares */ 434 } Stat; 435 436 static void 437 stat(enum { Reset, Inc } op, Stat *c, vlong val) 438 { 439 switch(op) { 440 case Reset: 441 c->n = 0; 442 c->sum = 0; 443 c->sumsq = 0; 444 c->min = 0; 445 c->max = 0; 446 break; 447 case Inc: 448 c->n++; 449 c->sum += val; 450 c->sumsq += val*val; 451 break; 452 } 453 if(val < c->min || c->n == 1) 454 c->min = val; 455 if(val > c->max || c->n == 1) 456 c->max = val; 457 } 458 459 static void 460 statinc(Stat *d, Stat *s) 461 { 462 d->n += s->n; 463 d->sum += s->sum; 464 d->sumsq += s->sumsq; 465 if(s->min < d->min || d->n == s->n) 466 d->min = s->min; 467 if(s->max > d->max || d->n == s->n) 468 d->max = s->max; 469 } 470 471 enum 472 { 473 HSIZE = 31, 474 MAXCOUNT = 100000000L, 475 }; 476 477 typedef struct { 478 int op; 479 int pc; 480 long count; 481 Stat t; /* combined dec and execution time */ 482 } Istat; 483 484 typedef struct Mstat Mstat; 485 struct Mstat { 486 char* name; 487 char* path; 488 int ninst; 489 Istat* inst; 490 Inst* base; 491 Mstat* hash; 492 Mstat* link; 493 }; 494 495 struct 496 { 497 Mstat* hash[HSIZE]; 498 Mstat* list; 499 } vmstat; 500 501 extern struct /* see ../../interp/tab.h:/keywds/ */ 502 { 503 char* name; 504 int op; 505 int terminal; 506 }keywds[]; 507 508 static char * 509 opname(int op) 510 { 511 char *name; 512 513 if(op < 0 || op >= MAXDIS) 514 return "Unknown"; 515 return keywds[op].name; 516 if(name == 0) 517 name = "<Noname>"; 518 return name; 519 } 520 521 static void 522 mreset(void) 523 { 524 Mstat *mp, *link; 525 526 for(mp=vmstat.list; mp; mp=link) { 527 link = mp->link; 528 free(mp->inst); 529 free(mp); 530 } 531 vmstat.list = 0; 532 memset(vmstat.hash, 0, HSIZE*sizeof(Mstat*)); 533 } 534 535 static ulong 536 hash(void *s) 537 { 538 ulong sum = 0; 539 uchar *a = s; 540 541 while(*a) 542 sum = (sum << 1) + *a++; 543 return sum%HSIZE; 544 } 545 546 static Mstat * 547 mlookup(Module *mod) 548 { 549 Mstat *m; 550 ulong h; 551 552 for(m=vmstat.hash[hash(mod->name)]; m; m=m->hash) 553 if(strcmp(m->name, mod->name) == 0 554 && strcmp(m->path, mod->path) == 0) { 555 return m; 556 } 557 558 559 m = malloc(sizeof(Mstat)); 560 if(m == 0) 561 return 0; 562 kstrdup(&m->name, mod->name); 563 kstrdup(&m->path, mod->path); 564 m->ninst = mod->nprog; 565 m->inst = malloc(m->ninst*sizeof(Istat)); 566 if(m->path == 0 || m->inst == 0) 567 return 0; 568 m->base = mod->prog; 569 m->link = vmstat.list; 570 vmstat.list = m; 571 h = hash(m->name); 572 m->hash = vmstat.hash[h]; 573 vmstat.hash[h] = m; 574 return m; 575 } 576 577 /* interpreted code Dis timing */ 578 void 579 bxec(Prog *p) 580 { 581 int op, pc; 582 vlong t0, t; 583 Mstat* ms; 584 Istat* is; 585 Module *om; 586 587 R = p->R; 588 R.MP = R.M->MP; 589 R.IC = p->quanta; 590 591 if(p->kill != nil) { 592 char *m; 593 m = p->kill; 594 p->kill = nil; 595 error(m); 596 } 597 598 if(R.M->compiled) 599 comvec(); 600 else { 601 om = 0; 602 ms = mlookup(R.M->m); 603 do { 604 op = R.PC->op; 605 pc = R.PC-R.M->prog; 606 if(om != R.M->m) { 607 om = R.M->m; 608 ms = mlookup(R.M->m); 609 } 610 611 t0 = archrdtsc(); 612 dec[R.PC->add](); 613 R.PC++; 614 optab[op](); 615 t = archrdtsc(); 616 if(ms) { 617 is = &ms->inst[pc]; 618 if(is->count < MAXCOUNT) { 619 if(is->count++ == 0) { 620 is->op = op; 621 is->pc = pc; 622 } 623 stat(Inc, &is->t, t-t0); 624 } 625 } 626 if(op==ISPAWN || op==IMSPAWN) { 627 Prog *new = delruntail(Pdebug); 628 new->xec = bxec; 629 addrun(new); 630 } 631 } while(--R.IC != 0); 632 } 633 634 p->R = R; 635 } 636 637 /* compiled code Dis timing */ 638 639 static struct { /* compiled code timing */ 640 int set; 641 int op, pc; /* Dis opcode and program counter */ 642 vlong t0, t; /* time-in and time-out */ 643 vlong base; /* cost of doing the timing */ 644 Mstat *ms; 645 Module *om; 646 int timing; /* between "dis timer start" and stop */ 647 } C; 648 649 enum { Nop = 0 }; /* opcode value for Dis NOP instruction */ 650 void 651 dopostcomp(vlong t) 652 { 653 Istat* is; 654 655 C.t = t; 656 C.set = 0; 657 if(C.ms != 0) { 658 is = &C.ms->inst[C.pc]; 659 if(C.op == Nop) { /* NOP calibration */ 660 vlong newbase = C.t - C.t0; 661 if(C.base == 0 || newbase < C.base) 662 C.base = newbase; 663 } 664 if(is->count < MAXCOUNT) { 665 if(is->count++ == 0) { 666 is->op = C.op; 667 is->pc = C.pc; 668 } 669 stat(Inc, &is->t, C.t-C.t0/*-C.base*/); 670 } 671 } 672 } 673 674 void 675 postcomp(void) 676 { 677 vlong t; 678 679 t = archrdtsc(); 680 if(C.timing == 0 || C.set == 0) 681 return; 682 dopostcomp(t); 683 } 684 685 void 686 precomp(void) 687 { 688 vlong t; 689 690 t = archrdtsc(); 691 if(C.timing == 0) 692 return; 693 if(C.set) 694 dopostcomp(t); 695 C.pc = *(ulong *)R.m; 696 C.op = *(ulong *)R.s; 697 if(C.om != R.M->m) { 698 C.om = R.M->m; 699 C.ms = mlookup(R.M->m); 700 } 701 C.set = 1; 702 C.t0 = archrdtsc(); 703 } 704 705 /* standard deviation */ 706 static vlong 707 sdev(Stat *s) 708 { 709 extern double sqrt(double); 710 vlong var; 711 var = s->sum; 712 var *= var/s->n; 713 var = (s->sumsq - var)/s->n; 714 return (vlong)sqrt(var); 715 } 716 717 /* 718 * Use the sequence: 719 * 1. "timer startclr" or "timer start", then, 720 * 2. Any DIS operations, and, 721 * 3. "timer stop", to stop timing. 722 * 4. Read the results from the data file after: 723 * a) "timer report" to get module/pc level results, or 724 * b) "timer summary" to get opcode level results 725 */ 726 static long 727 distime(int report, void *va, long n, ulong offset) 728 { 729 Prog *p; 730 Mstat *mp; 731 Istat *ip, *ep; 732 733 if(report) 734 return rep(va, n, offset); 735 clear(); 736 acquire(); 737 p = currun(); 738 if(strncmp(va, "timer startclr", 14) == 0) { 739 mreset(); 740 memset(&C, 0, sizeof(C)); 741 C.timing = 1; 742 p->xec = bxec; 743 } else if(strncmp(va, "timer start", 11) == 0) { 744 p->xec = bxec; 745 C.timing = 1; 746 } else if(strncmp(va, "timer stop", 10) == 0) { 747 p->xec = xec; /* bug: stop all xec threads */ 748 C.timing = 0; 749 } else if(strncmp(va, "timer nilop", 11) == 0) { 750 } else if(strncmp(va, "timer report", 12) == 0) /* by address */ 751 for(mp=vmstat.list; mp; mp=mp->link) { 752 ep = mp->inst + mp->ninst; 753 for(ip=mp->inst; ip<ep; ip++) 754 if(ip->count > 0) { 755 char *mean = ts2str(ip->t.sum/ip->count); 756 char *min = ts2str(ip->t.min); 757 char *max = ts2str(ip->t.max); 758 char *std = ts2str(sdev(&ip->t)); 759 log("%s %d %s %ld %s %s %s %s\n", mp->path, ip->pc, opname(ip->op), ip->count, mean, min, max, std); 760 } 761 } 762 else if(strncmp(va, "timer summary", 13) == 0) { /* by opcode */ 763 static Stat T[MAXDIS]; 764 int i; 765 766 for(i=0; i<MAXDIS; i++) 767 stat(Reset, &T[i], 0); 768 for(mp=vmstat.list; mp; mp=mp->link) { 769 ep = mp->inst + mp->ninst; 770 for(ip=mp->inst; ip<ep; ip++) 771 if(ip->count > 0) 772 statinc(&T[ip->op], &ip->t); 773 } 774 for(i=0; i<MAXDIS; i++) { 775 Stat *t = &T[i]; 776 char *mean = "0.00 ms"; 777 char *min = "0.00 ms"; 778 char *max = "0.00 ms"; 779 char *std = "0.00 ms"; 780 if(t->n > 0) { 781 mean = ts2str(t->sum/t->n); 782 min = ts2str(t->min); 783 max = ts2str(t->max); 784 std = ts2str(sdev(t)); 785 } 786 log("%d %s %lld %s %s %s %s\n", i, opname(i), t->n, mean, min, max, std); 787 } 788 } else 789 n = 0; 790 R.IC = 1; 791 release(); 792 793 return n; 794 } 795 796 /* 797 * Garbage collection 798 */ 799 static int nidle; 800 801 int 802 idlegc(void *p) 803 { 804 int done; 805 Prog *head; 806 vlong t0, t1, tot; 807 USED(p); 808 809 head = progn(0); /* isched.head */ 810 done = gccolor + 3; 811 tot = 0; 812 while(gccolor < done && gcruns()) { 813 if(tready(nil)) 814 break; 815 t0 = archrdtsc(); 816 rungc(head); 817 t1 = archrdtsc(); 818 t1 -= t0; 819 tot += t1; 820 // log(" %.2f", ts2us(t1)); 821 } 822 log(" %.2f", ts2us(tot)); 823 nidle--; 824 if(nidle == 0) { 825 log("\n"); 826 return 1; 827 } 828 return 0; 829 } 830 831 static long 832 gctime(int report, void *va, long n, ulong offset) 833 { 834 int i; 835 vlong t0, t1; 836 Prog *head; 837 838 if(report) 839 return rep(va, n, offset); 840 clear(); 841 acquire(); 842 head = progn(0); /* isched.head */ 843 /* 844 if(strncmp(va, "idle", 4) == 0) { 845 nidle = 100; 846 log("GCIDLE:1l:Observation:n:Time:us"); 847 atidle(idlegc, 0); 848 } else if(strncmp(va, "stop", 4) == 0) { 849 atidledont(idlegc, 0); 850 } else 851 */ 852 if(strncmp(va, "sched", 5) == 0) { 853 log("GCSCHED:1l:Observation:n:Time:us"); 854 for(i=0; i<1000; i++) { 855 t0 = archrdtsc(); 856 rungc(head); 857 t1 = archrdtsc(); 858 log(" %.2f", ts2us(t1-t0)); 859 release(); 860 acquire(); 861 } 862 log("\n"); 863 } else if(strncmp(va, "acquire", 7) == 0) { 864 log("GCACQUIRE:1l:Observation:n:Time:us"); 865 for(i=0; i<1000; i++) { 866 t0 = archrdtsc(); 867 release(); 868 acquire(); 869 head = progn(0); /* isched.head */ 870 rungc(head); 871 release(); 872 acquire(); 873 t1 = archrdtsc(); 874 log(" %.2f", ts2us(t1-t0)); 875 } 876 log("\n"); 877 } 878 879 release(); 880 881 return n; 882 } 883 884 885 /* 886 * Request the number of time stamp ticks per millisecond 887 */ 888 static long 889 ms2ts(int report, void *va, long n, ulong offset) 890 { 891 if(report) 892 return rep(va, n, offset); 893 log("%.ld\n", MS2TS); 894 return n; 895 } 896 897 /* 898 * test 899 */ 900 901 static long 902 test(int report, void *va, long n, ulong offset) 903 { 904 // vlong v; 905 double d; 906 if(report) 907 return rep(va, n, offset); 908 // v = 5; 909 // print("vlong %lld\n", v); 910 // print("before cast\n"); 911 // d = (double)v; 912 // print("after cast\n"); 913 // print("before assign\n"); 914 d=100.0; 915 print("after assign\n"); 916 print("double %f\n", d); 917 // log("%lld %f\n", v, d); 918 return n; 919 } 920 921 /* 922 * $Bench builtin support 923 */ 924 void 925 Bench_reset(void *) 926 { 927 bus(1); 928 } 929 930 void 931 Bench_microsec(void *fp) 932 { 933 F_Bench_microsec *f; 934 935 f = fp; 936 *f->ret = bus(0); 937 } 938 939 void 940 Bench_disablegc(void *) 941 { 942 gclock(); 943 } 944 945 void 946 Bench_enablegc(void *) 947 { 948 gcunlock(); 949 } 950 951 952 #define fdchk(x) ((x) == (Bench_FD*)H ? -1 : (x)->fd) 953 void 954 Bench_read(void *fp) 955 { 956 int n; 957 F_Bench_read *f; 958 vlong usrelease, uskread, usacquire, ussched; 959 960 f = fp; 961 n = f->n; 962 if(f->buf == (Array*)H) { 963 *f->ret = 0; 964 return; 965 } 966 if(n > f->buf->len) 967 n = f->buf->len; 968 969 bus(1); 970 release(); 971 usrelease = bus(0); 972 *f->ret = kread(fdchk(f->fd), f->buf->data, n); 973 uskread = bus(0); 974 acquire(); 975 usacquire = bus(0); 976 sched(); 977 ussched = bus(0); 978 log("%lld %lld %lld %lud %lld\n", usrelease, uskread, usacquire, m->ticks, ussched); 979 } 980 981 982 /* 983 * driver support 984 */ 985 long (*Test[])(int report, void *va, long n, ulong offset) = { 986 [None] notest, 987 [Calibrate] cal, 988 [Base] base, 989 [Op] timeop, 990 [Intr] intrtime, 991 [Dis] distime, 992 [Gc] gctime, 993 [MS2T] ms2ts, 994 [xTest] test, 995 }; 996 997 enum { 998 Benchdirqid, 999 Benchdataqid, 1000 Benchctlqid, 1001 Benchusqid, 1002 }; 1003 #define Data 0 1004 static Dirtab benchtab[]={ 1005 ".", {Benchdirqid,0,QTDIR}, 0, 0555, 1006 "bdata", {Benchdataqid}, 0, 0444, 1007 "bctl", {Benchctlqid}, 0, 0660, 1008 "busec", {Benchusqid}, 0, 0660, 1009 }; 1010 1011 static void 1012 benchreset(void) 1013 { 1014 builtinmod("$Bench", Benchmodtab); 1015 } 1016 1017 static Chan* 1018 benchattach(char *spec) 1019 { 1020 bench.inuse++; 1021 if(bench.inuse == 1) { 1022 bench.bufsz = 100*READSTR; 1023 bench.buf = xalloc(bench.bufsz); 1024 bench.wpos = bench.buf; 1025 if(bench.buf == 0) 1026 error(Enomem); 1027 bench.test = None; 1028 cal(0, 0, 0, 0); 1029 } 1030 return devattach('x', spec); 1031 } 1032 1033 void 1034 benchshutdown(void) 1035 { 1036 bench.inuse--; 1037 if(bench.inuse == 0) 1038 xfree(bench.buf); 1039 } 1040 1041 static Walkqid* 1042 benchwalk(Chan *c, Chan *nc, char **name, int nname) 1043 { 1044 return devwalk(c, nc, name, nname, benchtab, nelem(benchtab), devgen); 1045 } 1046 1047 static Chan* 1048 benchopen(Chan *c, int omode) 1049 { 1050 if(c->qid.path == Benchdirqid){ 1051 if(omode != OREAD) 1052 error(Eperm); 1053 } 1054 c->mode = openmode(omode); 1055 c->flag |= COPEN; 1056 c->offset = 0; 1057 return c; 1058 } 1059 1060 static int 1061 benchstat(Chan *c, uchar *dp, int n) 1062 { 1063 switch((ulong)c->qid.path){ 1064 case Benchdataqid: 1065 benchtab[Data].length = bench.wpos - bench.buf; 1066 } 1067 return devstat(c, dp, n, benchtab, nelem(benchtab), devgen); 1068 } 1069 1070 static void 1071 benchclose(Chan*) 1072 { 1073 } 1074 1075 static long 1076 benchread(Chan *c, void *buf, long n, vlong offset) 1077 { 1078 vlong us; 1079 char tmp[64]; 1080 1081 switch((ulong)c->qid.path){ 1082 case Benchdirqid: 1083 return devdirread(c, buf, n, benchtab, nelem(benchtab), devgen); 1084 1085 case Benchdataqid: 1086 return Test[bench.test](1, buf, n, offset); 1087 1088 case Benchusqid: 1089 us = archrdtsc(); 1090 us /= US2TS; 1091 snprint(tmp, sizeof(tmp), "%.lld", us); 1092 return readstr(0, buf, n, tmp); 1093 default: 1094 n = 0; 1095 break; 1096 } 1097 return n; 1098 } 1099 1100 static long 1101 benchwrite(Chan *c, void *buf, long n, vlong offset) 1102 { 1103 int argn = n; 1104 1105 switch((ulong)c->qid.path){ 1106 case Benchctlqid: 1107 bench.test = None; 1108 memset((char *)bench.buf, 0, bench.bufsz); 1109 bench.wpos = bench.buf; 1110 if(strncmp(buf, "test", 4) == 0) 1111 bench.test = xTest; 1112 else if(strncmp(buf, "calibrate", 9) == 0) 1113 bench.test = Calibrate; 1114 else if(strncmp(buf, "base", 4) == 0) 1115 bench.test = Base; 1116 else if(strncmp(buf, "intr", 4) == 0) 1117 bench.test = Intr; 1118 else if(strncmp(buf, "op ", 3) == 0) { 1119 bench.test = Op; 1120 buf = (char *)buf + 3; 1121 argn -= 3; 1122 } else if(strncmp(buf, "dis ", 4) == 0) { 1123 bench.test = Dis; 1124 buf = (char *)buf + 4; 1125 argn -= 4; 1126 } else if(strncmp(buf, "gc ", 3) == 0) { 1127 bench.test = Gc; 1128 buf = (char *)buf + 3; 1129 argn -= 3; 1130 } else if(strncmp(buf, "ms2ts", 5) == 0) 1131 bench.test = MS2T; 1132 else 1133 error(Ebadctl); 1134 Test[bench.test](0, buf, argn, offset); 1135 break; 1136 case Benchusqid: 1137 bench.tickstart = archrdtsc(); 1138 break; 1139 default: 1140 error(Ebadusefd); 1141 } 1142 return n; 1143 } 1144 1145 Dev benchdevtab = { 1146 'x', 1147 "bench", 1148 1149 benchreset, 1150 devinit, 1151 benchshutdown, 1152 benchattach, 1153 benchwalk, 1154 benchstat, 1155 benchopen, 1156 devcreate, 1157 benchclose, 1158 benchread, 1159 devbread, 1160 benchwrite, 1161 devbwrite, 1162 devremove, 1163 devwstat, 1164 1165 }; 1166