1implement Profile; 2 3include "sys.m"; 4 sys: Sys; 5include "draw.m"; 6include "bufio.m"; 7 bufio: Bufio; 8 Iobuf: import bufio; 9include "workdir.m"; 10 workdir: Workdir; 11include "debug.m"; 12 debug: Debug; 13 Sym: import debug; 14include "dis.m"; 15 dism: Dis; 16include "profile.m"; 17 18# merge common code 19 20PROF: con "/prof"; 21CTL: con "ctl"; 22NAME: con "name"; 23MPATH: con "path"; 24HISTOGRAM: con "histogram"; 25 26inited: int; 27modl: string; 28lasterr: string; 29 30bspath := array[] of 31{ 32 ("/dis/", "/appl/cmd/"), 33 ("/dis/", "/appl/"), 34}; 35 36error(s: string) 37{ 38 lasterr = sys->sprint("%s: %r", s); 39} 40 41error0(s: string) 42{ 43 lasterr = s; 44} 45 46cleare() 47{ 48 lasterr = nil; 49} 50 51lasterror(): string 52{ 53 return lasterr; 54} 55 56init(): int 57{ 58 cleare(); 59 sys = load Sys Sys->PATH; 60 bufio = load Bufio Bufio->PATH; 61 debug = load Debug Debug->PATH; 62 if(debug == nil){ 63 error("cannot load Debug module"); 64 return -1; 65 } 66 debug->init(); 67 (ok, nil) := sys->stat(PROF + "/ctl"); 68 if (ok == -1) { 69 if(sys->bind("#P", PROF, Sys->MREPL|Sys->MCREATE) < 0){ 70 error(sys->sprint("cannot bind prof device to /prof")); 71 return -1; 72 } 73 } 74 inited = 1; 75 return 0; 76} 77 78end(): int 79{ 80 cleare(); 81 inited = 0; 82 modl = nil; 83 if(write(mkpath(PROF, CTL), "end") < 0) 84 return -1; 85 return 0; 86} 87 88start(): int 89{ 90 cleare(); 91 if(!inited && init() < 0) 92 return -1; 93 if(write(mkpath(PROF, CTL), "module " + modl) < 0) 94 return -1; 95 if(write(mkpath(PROF, CTL), "start") < 0) 96 return -1; 97 return 0; 98} 99 100cpstart(pid: int): int 101{ 102 cleare(); 103 if(!inited && init() < 0) 104 return -1; 105 if(write(mkpath(PROF, CTL), "module " + modl) < 0) 106 return -1; 107 if(write(mkpath(PROF, CTL), "startcp " + string pid) < 0) 108 return -1; 109 return 0; 110} 111 112memstart(m: int): int 113{ 114 cleare(); 115 if(!inited && init() < 0) 116 return -1; 117 if(modl != nil && write(mkpath(PROF, CTL), "module " + modl) < 0) 118 return -1; 119 start := "startmp"; 120 if(m == 0) 121 m = MAIN|HEAP|IMAGE; 122 if(m&MAIN) 123 start += "1"; 124 if(m&HEAP) 125 start += "2"; 126 if(m&IMAGE) 127 start += "3"; 128 if(write(mkpath(PROF, CTL), start) < 0) 129 return -1; 130 return 0; 131} 132 133stop(): int 134{ 135 cleare(); 136 if(!inited && init() < 0) 137 return -1; 138 if(write(mkpath(PROF, CTL), "stop") < 0) 139 return -1; 140 return 0; 141} 142 143sample(i: int): int 144{ 145 cleare(); 146 if(i <= 0){ 147 error0(sys->sprint("bad sample rate %d", i)); 148 return -1; 149 } 150 if(write(mkpath(PROF, CTL), "interval " + string i) < 0) 151 return -1; 152 return 0; 153} 154 155profile(m: string): int 156{ 157 cleare(); 158 modl = m + " " + modl; 159 return 0; 160} 161 162stats(): Prof 163{ 164 mp: Modprof; 165 p: Prof; 166 mpl: list of Modprof; 167 168 cleare(); 169 fd := sys->open(PROF, Sys->OREAD); 170 if(fd == nil){ 171 error(sys->sprint("cannot open %s for reading", PROF)); 172 return (nil, 0, nil); 173 } 174 total := 0; 175 for(;;){ 176 (nr, d) := sys->dirread(fd); 177 if(nr <= 0) 178 break; 179 for(i := 0; i < nr; i++){ 180 if(d[i].name == CTL) 181 continue; 182 dn := mkpath(PROF, d[i].name); 183 mp.name = read(mkpath(dn, NAME)); 184 mp.path = read(mkpath(dn, MPATH)); 185 fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); 186 if(fdh == nil) 187 continue; 188 (mp.srcpath, mp.linetab, mp.funtab, mp.total) = tprofile(fdh, mp.path); 189 if((sp := getb(mp.path)) != nil) 190 mp.srcpath = sp; 191 if(mp.total != 0){ 192 mpl = mp :: mpl; 193 total += mp.total; 194 } 195 } 196 } 197 p.mods = mpl; 198 p.total = total; 199 return p; 200} 201 202cpstats(rec: int, v: int): Prof 203{ 204 m: string; 205 mp: Modprof; 206 p: Prof; 207 mpl: list of Modprof; 208 209 cleare(); 210 fd := sys->open(PROF, Sys->OREAD); 211 if(fd == nil){ 212 error(sys->sprint("cannot open %s for reading", PROF)); 213 return (nil, 0, nil); 214 } 215 total := 0; 216 for(;;){ 217 (nr, d) := sys->dirread(fd); 218 if(nr <= 0) 219 break; 220 for(i:=0; i<nr; i++){ 221 if(d[i].name == CTL) 222 continue; 223 dn := mkpath(PROF, d[i].name); 224 mp.name = read(mkpath(dn, NAME)); 225 mp.path = read(mkpath(dn, MPATH)); 226 fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); 227 if(fdh == nil) 228 continue; 229 (m, mp.srcpath, mp.rawtab, mp.linetab, mp.rngtab, mp.total, mp.coverage) = cprofile(fdh, mp.path, rec, v); 230 if(mp.name == nil) 231 mp.name = m; 232 if((sp := getb(mp.path)) != nil) 233 mp.srcpath = sp; 234 if(len mp.rawtab > 0){ 235 mpl = mp :: mpl; 236 total += mp.total; 237 } 238 } 239 } 240 p.mods = mpl; 241 p.total = total; 242 return p; 243} 244 245cpfstats(v: int): Prof 246{ 247 mp: Modprof; 248 p: Prof; 249 mpl: list of Modprof; 250 251 cleare(); 252 total := 0; 253 (nil, l) := sys->tokenize(modl, " "); 254 for( ; l != nil; l = tl l){ 255 s := hd l; 256 suf := suff(s); 257 if(suf == nil) 258 s += ".dis"; 259 else 260 s = repsuff(s, "."+suf, ".dis"); 261 if(!exists(s) && s[0] != '/' && s[0:2] != "./") 262 s = "/dis/"+s; 263 mp.path = s; 264 (mp.name, mp.srcpath, mp.rawtab, mp.linetab, mp.rngtab, mp.total, mp.coverage) = cprofile(nil, mp.path, 1, v); 265 if((sp := getb(mp.path)) != nil) 266 mp.srcpath = sp; 267 if(len mp.rawtab > 0){ 268 mpl = mp :: mpl; 269 total += mp.total; 270 } 271 } 272 p.mods = mpl; 273 p.total = total; 274 return p; 275} 276 277memstats(): Prof 278{ 279 mp: Modprof; 280 p: Prof; 281 mpl: list of Modprof; 282 283 cleare(); 284 fd := sys->open(PROF, Sys->OREAD); 285 if(fd == nil){ 286 error(sys->sprint("cannot open %s for reading", PROF)); 287 return (nil, 0, nil); 288 } 289 total := totale := 0; 290 for(;;){ 291 (nr, d) := sys->dirread(fd); 292 if(nr <= 0) 293 break; 294 for(i:=0; i<nr; i++){ 295 if(d[i].name == CTL) 296 continue; 297 dn := mkpath(PROF, d[i].name); 298 mp.name = read(mkpath(dn, NAME)); 299 mp.path = read(mkpath(dn, MPATH)); 300 fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); 301 if(fdh == nil) 302 continue; 303 mp.totals = array[1] of int; 304 (mp.srcpath, mp.linetab, mp.funtab, mp.total, mp.totals[0]) = mprofile(fdh, mp.path); 305 if((sp := getb(mp.path)) != nil) 306 mp.srcpath = sp; 307 if(mp.total != 0 || mp.totals[0] != 0){ 308 mpl = mp :: mpl; 309 total += mp.total; 310 totale += mp.totals[0]; 311 } 312 } 313 } 314 p.mods = mpl; 315 p.total = total; 316 p.totals = array[1] of int; 317 p.totals[0] = totale; 318 return p; 319} 320 321tprofile(fd: ref Sys->FD, dis: string): (string, array of int, array of Funprof, int) 322{ 323 sbl := findsbl(dis); 324 if(sbl == nil){ 325 error0(sys->sprint("cannot locate symbol table file for %s", dis)); 326 return (nil, nil, nil, 0); 327 } 328 (sym, err) := debug->sym(sbl); 329 if(sym == nil){ 330 error0(sys->sprint("bad symbol table file: %s", err)); 331 return (nil, nil, nil, 0); 332 } 333 nlines := 0; 334 nl := len sym.src; 335 for(i := 0; i < nl; i++){ 336 if((l := sym.src[i].stop.line) > nlines) 337 nlines = l; 338 } 339 name := sym.src[0].start.file; 340 line := array[nlines+1] of int; 341 for(i = 0; i <= nlines; i++) 342 line[i] = 0; 343 nf := len sym.fns; 344 fun := array[nf] of Funprof; 345 for(i = 0; i < nf; i++){ 346 fun[i].name = sym.fns[i].name; 347 # src seems to be always nil 348 # fun[i].file = sym.fns[i].src.start.file; 349 # fun[i].line = (sym.fns[i].src.start.line+sym.fns[i].src.stop.line)/2; 350 src := sym.pctosrc(sym.fns[i].offset); 351 if(src != nil) 352 fun[i].line = src.start.line; 353 else 354 fun[i].line = 0; 355 fun[i].count = 0; 356 } 357 buf := array[32] of byte; 358 # pc := 0; 359 tot := 0; 360 fi := 0; 361# for(i=0; i < nl; i++) sys->print("%d -> %d\n", i, sym.pctosrc(i).start.line); 362 while((m := sys->read(fd, buf, len buf)) > 0){ 363 (nw, lw) := sys->tokenize(string buf[0:m], " "); 364 if(nw != 2){ 365 error0("bad histogram data"); 366 return (nil, nil, nil, 0); 367 } 368 pc := int hd lw; 369 f := int hd tl lw; 370 rpc := pc-1; 371 src := sym.pctosrc(rpc); 372 if(src == nil) 373 continue; 374 l1 := src.start.line; 375 l2 := src.stop.line; 376 if(l1 == 0 || l2 == 0) 377 continue; 378 if((nl = l2-l1+1) == 1) 379 line[l1] += f; 380 else{ 381 q := f/nl; 382 r := f-q*nl; 383 for(i = l1; i <= l2; i++) 384 line[i] += q+(r-->0); 385 } 386 if(fi < nf){ 387 if(rpc >= sym.fns[fi].offset && rpc < sym.fns[fi].stoppc) 388 fun[fi].count += f; 389 else{ 390 while(fi < nf && rpc >= sym.fns[fi].stoppc) 391 fi++; 392 # fi++; 393 if(fi >= nf && f != 0) 394 error0(sys->sprint("bad fn index")); 395 if(fi < nf) 396 fun[fi].count += f; 397 } 398 } 399 tot += f; 400# sys->print("pc %d count %d l1 %d l2 %d\n", rpc, f, l1, l2); 401 } 402 return (name, line, fun, tot); 403} 404 405cprofile(fd: ref Sys->FD, dis: string, rec: int, v: int): (string, string, array of (int, int), array of int, array of ref Range, int, int) 406{ 407 freq := v&FREQUENCY; 408 sbl := findsbl(dis); 409 if(sbl == nil){ 410 error0(sys->sprint("cannot locate symbol table file for %s", dis)); 411 return (nil, nil, nil, nil, nil, 0, 0); 412 } 413 (sym, err) := debug->sym(sbl); 414 if(sym == nil){ 415 error0(sys->sprint("bad symbol table file: %s", err)); 416 return (nil, nil, nil, nil, nil, 0, 0); 417 } 418 nlines := 0; 419 nl := len sym.src; 420 for(i := 0; i < nl; i++){ 421 if((l := sym.src[i].start.line) > nlines) 422 nlines = l; 423 if((l = sym.src[i].stop.line) > nlines) 424 nlines = l; 425 } 426 name := sym.src[0].start.file; 427 line := array[nlines+1] of int; 428 for(i = 0; i <= nlines; i++){ 429 if(freq) 430 line[i] = -1; 431 else 432 line[i] = 0; 433 } 434 rng := array[nlines+1] of ref Range; 435 for(i = 0; i < nl; i++) 436 cover(i, -1, sym, line, rng, freq); 437 buf := array[32] of byte; 438 nr := 0; 439 r := array[1024] of (int, int); 440 while((m := sys->read(fd, buf, len buf)) > 0){ 441 (nw, lw) := sys->tokenize(string buf[0:m], " "); 442 if(nw != 2){ 443 error0("bad histogram data"); 444 return (nil, nil, nil, nil, nil, 0, 0); 445 } 446 (r, nr) = add(r, nr, int hd lw, int hd tl lw); 447 } 448 r = clip(r, nr); 449 if(rec){ 450 wt := nr > 0; 451 prf := repsuff(sbl, ".sbl", ".prf"); 452 if(exists(prf)){ 453 if(stamp(sbl) > stamp(prf)){ 454 error0(sys->sprint("%s later than %s", sbl, prf)); 455 return (nil, nil, nil, nil, nil, 0, 0); 456 } 457 r = mergeprof(r, readprof(prf)); 458 nr = len r; 459 } 460 if(wt && writeprof(prf, r) < 0){ 461 error0(sys->sprint("cannot write profile file %s", prf)); 462 return (nil, nil, nil, nil, nil, 0, 0); 463 } 464 } 465 tot := 0; 466 lpc := 0; 467 dise := dist := 0; 468 for(i = 0; i < nr; i++){ 469 (pc, f) := r[i]; 470 for( ; lpc < pc; lpc++){ 471 cover(lpc, 0, sym, line, rng, freq); 472 dist++; 473 } 474 cover(pc, f, sym, line, rng, freq); 475 dist++; 476 if(f != 0) 477 dise++; 478 tot += f; 479 lpc = pc+1; 480 } 481 for( ; lpc < nl; lpc++){ 482 cover(lpc, 0, sym, line, rng, freq); 483 dist++; 484 } 485 if(dist == 0) 486 dist = 1; 487 return (sym.name, name, r, line, rng, tot, (100*dise)/dist); 488} 489 490show(p: Prof, v: int): int 491{ 492 i: int; 493 494 cleare(); 495 tot := p.total; 496 if(tot == 0) 497 return 0; 498 verbose := v&VERBOSE; 499 fullhdr := v&FULLHDR; 500 for(ml := p.mods; ml != nil; ml = tl ml){ 501 mp := hd ml; 502 if(mp.total == 0) 503 continue; 504 if((b := getb(mp.path)) == nil) 505 continue; 506 sys->print("\nModule: %s(%s)\n\n", mp.name, mp.path); 507 line := mp.linetab; 508 if(v&FUNCTION){ 509 fun := mp.funtab; 510 nf := len fun; 511 for(i = 0; i < nf; i++) 512 if(verbose || fun[i].count != 0){ 513 if(fullhdr) 514 sys->print("%s:", b); 515 sys->print("%d\t%.2f\t%s()\n", fun[i].line, 100.0*(real fun[i].count)/(real tot), fun[i].name); 516 } 517 sys->print("\n**** module sampling points %d ****\n\n", mp.total); 518 if(v&LINE) 519 sys->print("\n"); 520 } 521 if(v&LINE){ 522 bio := bufio->open(b, Bufio->OREAD); 523 if(bio == nil){ 524 error(sys->sprint("cannot open %s for reading", b)); 525 continue; 526 } 527 i = 1; 528 ll := len line; 529 while((s := bio.gets('\n')) != nil){ 530 f := 0; 531 if(i < ll) 532 f = line[i]; 533 if(verbose || f != 0){ 534 if(fullhdr) 535 sys->print("%s:", b); 536 sys->print("%d\t%.2f\t%s", i, 100.0*(real f)/(real tot), s); 537 } 538 i++; 539 } 540 sys->print("\n**** module sampling points %d ****\n\n", mp.total); 541 } 542 } 543 if(p.mods != nil && tl p.mods != nil) 544 sys->print("\n**** total sampling points %d ****\n\n", p.total); 545 return 0; 546} 547 548cpshow(p: Prof, v: int): int 549{ 550 i: int; 551 552 cleare(); 553 tot := p.total; 554 fullhdr := v&FULLHDR; 555 freq := v&FREQUENCY; 556 for(ml := p.mods; ml != nil; ml = tl ml){ 557 mp := hd ml; 558 if((b := getb(mp.path)) == nil) 559 continue; 560 sys->print("\nModule: %s(%s)", mp.name, mp.path); 561 sys->print("\t%d%% coverage\n\n", mp.coverage); 562 if(mp.coverage == 100 && !freq) 563 continue; 564 line := mp.linetab; 565 rng := mp.rngtab; 566 bio := bufio->open(b, Bufio->OREAD); 567 if(bio == nil){ 568 error(sys->sprint("cannot open %s for reading", b)); 569 continue; 570 } 571 i = 1; 572 ll := len line; 573 while((s := bio.gets('\n')) != nil){ 574 f := 0; 575 if(i < ll) 576 f = line[i]; 577 if(fullhdr) 578 sys->print("%s:", b); 579 sys->print("%d\t", i); 580 if(rng != nil && i < ll && (r := rng[i]) != nil && multirng(r)){ 581 for( ; r != nil; r = r.n){ 582 sys->print("%s", trans(r.f, freq)); 583 if(r.n != nil) 584 sys->print("|"); 585 } 586 } 587 else 588 sys->print("%s", trans(f, freq)); 589 sys->print("\t%s", s); 590 i++; 591 } 592 sys->print("\n**** module dis instructions %d ****\n\n", mp.total); 593 } 594 if(p.mods != nil && tl p.mods != nil) 595 sys->print("\n**** total number dis instructions %d ****\n\n", p.total); 596 return 0; 597} 598 599coverage(p: Prof, v: int): Coverage 600{ 601 i: int; 602 clist: Coverage; 603 604 cleare(); 605 freq := v&FREQUENCY; 606 for(ml := p.mods; ml != nil; ml = tl ml){ 607 mp := hd ml; 608 if((b := getb(mp.path)) == nil) 609 continue; 610 line := mp.linetab; 611 rng := mp.rngtab; 612 bio := bufio->open(b, Bufio->OREAD); 613 if(bio == nil){ 614 error(sys->sprint("cannot open %s for reading", b)); 615 continue; 616 } 617 i = 1; 618 ll := len line; 619 llist: list of (list of (int, int, int), string); 620 while((s := bio.gets('\n')) != nil){ 621 f := 0; 622 if(i < ll) 623 f = line[i]; 624 rlist: list of (int, int, int); 625 if(rng != nil && i < ll && (r := rng[i]) != nil){ 626 for( ; r != nil; r = r.n){ 627 if(r.u == ∞) 628 r.u = len s - 1; 629 if(freq){ 630 if(r.f > 0) 631 rlist = (r.l, r.u, r.f) :: rlist; 632 } 633 else{ 634 if(r.f&NEX) 635 rlist = (r.l, r.u, (r.f&EXE)==EXE) :: rlist; 636 } 637 } 638 } 639 else{ 640 if(freq){ 641 if(f > 0) 642 rlist = (0, len s - 1, f) :: rlist; 643 } 644 else{ 645 if(f&NEX) 646 rlist = (0, len s - 1, (f&EXE)==EXE) :: nil; 647 } 648 } 649 llist = (rlist, s) :: llist; 650 i++; 651 } 652 if(freq) 653 n := mp.total; 654 else 655 n = mp.coverage; 656 clist = (b, n, rev(llist)) :: clist; 657 } 658 return clist; 659} 660 661∞: con 1<<30; 662 663DIS: con 1; 664EXE: con 2; 665NEX: con 4; 666 667cover(pc: int, f: int, sym: ref Debug->Sym, line: array of int, rng: array of ref Range, freq: int) 668{ 669 v: int; 670 671 src := sym.pctosrc(pc); 672 if(src == nil) 673 return; 674 l1 := src.start.line; 675 l2 := src.stop.line; 676 if(l1 == 0 || l2 == 0) 677 return; 678 c1 := src.start.pos; 679 c2 := src.stop.pos; 680 if(freq){ 681 v = 0; 682 if(f > 0) 683 v = f; 684 } 685 else{ 686 v = DIS; 687 if(f > 0) 688 v = EXE; 689 else if(f == 0) 690 v = NEX; 691 } 692 for(i := l1; i <= l2; i++){ 693 r1 := 0; 694 r2 := ∞; 695 if(i == l1) 696 r1 = c1; 697 if(i == l2) 698 r2 = c2; 699 if(rng != nil) 700 rng[i] = mrgrng(addrng(rng[i], r1, r2, v, freq)); 701 if(freq){ 702 if(v > line[i]) 703 line[i] = v; 704 } 705 else 706 line[i] |= v; 707 # if(i==123) sys->print("%d %d-%d %d %d\n", i, r1, r2, v, pc); 708 } 709} 710 711arng(c1: int, c2: int, f: int, tr: ref Range, lr: ref Range, r: ref Range): ref Range 712{ 713 nr := ref Range(c1, c2, f, tr); 714 if(lr == nil) 715 r = nr; 716 else 717 lr.n = nr; 718 return r; 719} 720 721addrng(r: ref Range, c1: int, c2: int, f: int, freq: int): ref Range 722{ 723 lr: ref Range; 724 725 if(c1 > c2) 726 return r; 727 for(tr := r; tr != nil; tr = tr.n){ 728 r1 := tr.l; 729 r2 := tr.u; 730 if(c1 < r1){ 731 if(c2 < r1) 732 return arng(c1, c2, f, tr, lr, r); 733 else if(c2 <= r2){ 734 r = addrng(r, c1, r1-1, f, freq); 735 return addrng(r, r1, c2, f, freq); 736 } 737 else{ 738 r = addrng(r, c1, r1-1, f, freq); 739 r = addrng(r, r1, r2, f, freq); 740 return addrng(r, r2+1, c2, f, freq); 741 } 742 } 743 else if(c1 <= r2){ 744 if(c2 <= r2){ 745 v := tr.f; 746 tr.l = c1; 747 tr.u = c2; 748 if(freq){ 749 if(f > tr.f) 750 tr.f = f; 751 } 752 else 753 tr.f |= f; 754 r = addrng(r, r1, c1-1, v, freq); 755 return addrng(r, c2+1, r2, v, freq); 756 } 757 else{ 758 r = addrng(r, c1, r2, f, freq); 759 return addrng(r, r2+1, c2, f, freq); 760 } 761 } 762 lr = tr; 763 } 764 return arng(c1, c2, f, nil, lr, r); 765} 766 767mrgrng(r: ref Range): ref Range 768{ 769 lr: ref Range; 770 771 for(tr := r; tr != nil; tr = tr.n){ 772 if(lr != nil && lr.u >= tr.l) 773 sys->print("ERROR %d %d\n", lr.u, tr.l); 774 if(lr != nil && lr.f == tr.f && lr.u+1 == tr.l){ 775 lr.u = tr.u; 776 lr.n = tr.n; 777 } 778 else 779 lr = tr; 780 } 781 return r; 782} 783 784multirng(r: ref Range): int 785{ 786 f := r.f; 787 for(tr := r; tr != nil; tr = tr.n) 788 if(tr.f != f) 789 return 1; 790 return 0; 791} 792 793add(r: array of (int, int), nr: int, pc: int, f: int): (array of (int, int), int) 794{ 795 l := len r; 796 if(nr == l){ 797 s := array[2*l] of (int, int); 798 s[0:] = r[0: nr]; 799 r = s; 800 } 801 r[nr++] = (pc, f); 802 return (r, nr); 803} 804 805clip(r: array of (int, int), nr: int): array of (int, int) 806{ 807 l := len r; 808 if(nr < l){ 809 s := array[nr] of (int, int); 810 s[0:] = r[0: nr]; 811 r = s; 812 } 813 return r; 814} 815 816readprof(f: string): array of (int, int) 817{ 818 b := bufio->open(f, Bufio->OREAD); 819 if(b == nil) 820 return nil; 821 nr := 0; 822 r := array[1024] of (int, int); 823 while((buf := b.gets('\n')) != nil){ 824 (nw, lw) := sys->tokenize(buf, " "); 825 if(nw != 2){ 826 error0("bad raw data"); 827 return nil; 828 } 829 (r, nr) = add(r, nr, int hd lw, int hd tl lw); 830 } 831 r = clip(r, nr); 832 return r; 833} 834 835mergeprof(r1, r2: array of (int, int)): array of (int, int) 836{ 837 nr := 0; 838 r := array[1024] of (int, int); 839 l1 := len r1; 840 l2 := len r2; 841 for((i, j) := (0, 0); i < l1 || j < l2; ){ 842 if(i < l1) 843 (pc1, f1) := r1[i]; 844 else 845 pc1 = ∞; 846 if(j < l2) 847 (pc2, f2) := r2[j]; 848 else 849 pc2 = ∞; 850 if(pc1 < pc2){ 851 (r, nr) = add(r, nr, pc1, f1); 852 i++; 853 } 854 else if(pc1 > pc2){ 855 (r, nr) = add(r, nr, pc2, f2); 856 j++; 857 } 858 else{ 859 (r, nr) = add(r, nr, pc1, f1+f2); 860 i++; 861 j++; 862 } 863 } 864 r = clip(r, nr); 865 return r; 866} 867 868writeprof(f: string, r: array of (int, int)): int 869{ 870 fd := sys->create(f, Sys->OWRITE, 8r664); 871 if(fd == nil) 872 return -1; 873 l := len r; 874 for(i := 0; i < l; i++){ 875 (pc, fr) := r[i]; 876 sys->fprint(fd, "%d %d\n", pc, fr); 877 } 878 return 0; 879} 880 881trans(f: int, freq: int): string 882{ 883 if(freq) 884 return transf(f); 885 else 886 return transc(f); 887} 888 889transf(f: int): string 890{ 891 if(f < 0) 892 return " "; 893 return string f; 894} 895 896transc(f: int): string 897{ 898 c := ""; 899 case(f){ 900 0 => c = " "; 901 DIS|EXE => c = "+"; 902 DIS|NEX => c = "-"; 903 DIS|EXE|NEX => c = "?"; 904 * => 905 error(sys->sprint("bad code %d\n", f)); 906 } 907 return c; 908} 909 910getb(dis: string): string 911{ 912 b := findb(dis); 913 if(b == nil){ 914 error0(sys->sprint("cannot locate source file for %s\n", dis)); 915 return nil; 916 } 917 if(stamp(b) > stamp(dis)){ 918 error0(sys->sprint("%s later than %s", b, dis)); 919 return nil; 920 } 921 return b; 922} 923 924mkpath(d: string, f: string): string 925{ 926 return d+"/"+f; 927} 928 929suff(s: string): string 930{ 931 (n, l) := sys->tokenize(s, "."); 932 if(n > 1){ 933 while(tl l != nil) 934 l = tl l; 935 return hd l; 936 } 937 return nil; 938} 939 940repsuff(s: string, old: string, new: string): string 941{ 942 lo := len old; 943 ls := len s; 944 if(lo <= ls && s[ls-lo:ls] == old) 945 return s[0:ls-lo]+new; 946 return s; 947} 948 949read(f: string): string 950{ 951 if((fd := sys->open(f, Sys->OREAD)) == nil){ 952 error(sys->sprint("cannot open %s for reading", f)); 953 return nil; 954 } 955 buf := array[128] of byte; 956 n := sys->read(fd, buf, len buf); 957 return string buf[0:n]; 958} 959 960write(f: string, s: string): int 961{ 962 if((fd := sys->open(f, Sys->OWRITE)) == nil){ 963 error(sys->sprint("cannot open %s for writing", f)); 964 return -1; 965 } 966 b := array of byte s; 967 if((n := sys->write(fd, b, len b)) != len b){ 968 error(sys->sprint("cannot write %s to file %s", s, f)); 969 return -1; 970 } 971 return 0; 972} 973 974exists(f: string): int 975{ 976 return sys->open(f, Sys->OREAD) != nil; 977} 978 979stamp(f: string): int 980{ 981 (ok, d) := sys->stat(f); 982 if(ok < 0) 983 return 0; 984 return d.mtime; 985} 986 987findb(dis: string): string 988{ 989 if(dism == nil){ 990 dism = load Dis Dis->PATH; 991 if(dism != nil) 992 dism->init(); 993 } 994 if(dism != nil && (b := dism->src(dis)) != nil && exists(b)) 995 return b; 996 return findfile(repsuff(dis, ".dis", ".b")); 997} 998 999findsbl(dis: string): string 1000{ 1001 b := findb(dis); 1002 if(b != nil){ 1003 sbl := repsuff(b, ".b", ".sbl"); 1004 if(exists(sbl)) 1005 return sbl; 1006 return findfile(sbl); 1007 } 1008 return findfile(repsuff(dis, ".dis", ".sbl")); 1009} 1010 1011findfile(s: string): string 1012{ 1013 if(exists(s)) 1014 return s; 1015 if(s != nil && s[0] != '/'){ 1016 if(workdir == nil) 1017 workdir = load Workdir Workdir->PATH; 1018 if(workdir == nil){ 1019 error("cannot load Workdir module"); 1020 return nil; 1021 } 1022 s = workdir->init() + "/" + s; 1023 } 1024 (d, f) := split(s, '/'); 1025 (fp, nil) := split(f, '.'); 1026 if(fp != nil) 1027 fp = fp[0: len fp - 1]; 1028 for(k := 0; k < 2; k++){ 1029 if(k == 0) 1030 str := s; 1031 else 1032 str = d; 1033 ls := len str; 1034 for(i := 0; i < len bspath; i++){ 1035 (dis, src) := bspath[i]; 1036 ld := len dis; 1037 if(ls >= ld && str[:ld] == dis){ 1038 if(k == 0) 1039 ns := src + str[ld:]; 1040 else 1041 ns = src + str[ld:] + fp + "/" + f; 1042 if(exists(ns)) 1043 return ns; 1044 } 1045 } 1046 } 1047 return nil; 1048} 1049 1050split(s: string, c: int): (string, string) 1051{ 1052 for(i := len s - 1; i >= 0; --i) 1053 if(s[i] == c) 1054 break; 1055 return (s[0:i+1], s[i+1:]); 1056} 1057 1058rev(llist: list of (list of (int, int, int), string)): list of (list of (int, int, int), string) 1059{ 1060 r: list of (list of (int, int, int), string); 1061 1062 for(l := llist; l != nil; l = tl l) 1063 r = hd l :: r; 1064 return r; 1065} 1066 1067mprofile(fd: ref Sys->FD, dis: string): (string, array of int, array of Funprof, int, int) 1068{ 1069 sbl := findsbl(dis); 1070 if(sbl == nil){ 1071 error0(sys->sprint("cannot locate symbol table file for %s", dis)); 1072 return (nil, nil, nil, 0, 0); 1073 } 1074 (sym, err) := debug->sym(sbl); 1075 if(sym == nil){ 1076 error0(sys->sprint("bad symbol table file: %s", err)); 1077 return (nil, nil, nil, 0, 0); 1078 } 1079 nlines := 0; 1080 nl := len sym.src; 1081 for(i := 0; i < nl; i++){ 1082 if((l := sym.src[i].stop.line) > nlines) 1083 nlines = l; 1084 } 1085 name := sym.src[0].start.file; 1086 nl0 := 2*(nlines+1); 1087 line := array[nl0] of int; 1088 for(i = 0; i < nl0; i++) 1089 line[i] = 0; 1090 nf := len sym.fns; 1091 fun := array[nf] of Funprof; 1092 for(i = 0; i < nf; i++){ 1093 fun[i].name = sym.fns[i].name; 1094 # src seems to be always nil 1095 # fun[i].file = sym.fns[i].src.start.file; 1096 # fun[i].line = (sym.fns[i].src.start.line+sym.fns[i].src.stop.line)/2; 1097 src := sym.pctosrc(sym.fns[i].offset); 1098 if(src != nil) 1099 fun[i].line = src.start.line; 1100 else 1101 fun[i].line = 0; 1102 fun[i].count = fun[i].counte = 0; 1103 } 1104 buf := array[32] of byte; 1105 # pc := 0; 1106 ktot := ktot1 := 0; 1107 fi := 0; 1108# for(i=0; i < nl; i++) sys->print("%d -> %d\n", i, sym.pctosrc(i).start.line); 1109 while((m := sys->read(fd, buf, len buf)) > 0){ 1110 (nw, lw) := sys->tokenize(string buf[0:m], " "); 1111 if(nw != 2){ 1112 error0("bad histogram data"); 1113 return (nil, nil, nil, 0, 0); 1114 } 1115 pc := int hd lw; 1116 f := int hd tl lw; 1117 if(pc == 0){ 1118 ktot = f; 1119 continue; 1120 } 1121 if(pc == 1){ 1122 ktot1 = f; 1123 continue; 1124 } 1125 pc -= 2; 1126 t := pc&1; 1127 pc /= 2; 1128 rpc := pc-1; 1129 src := sym.pctosrc(rpc); 1130 if(src == nil) 1131 continue; 1132 l1 := src.start.line; 1133 l2 := src.stop.line; 1134 if(l1 == 0 || l2 == 0) 1135 continue; 1136 if((nl = l2-l1+1) == 1) 1137 line[2*l1+t] += f; 1138 else{ 1139 q := f/nl; 1140 r := f-q*nl; 1141 for(i = l1; i <= l2; i++) 1142 line[2*i+t] += q+(r-->0); 1143 } 1144 if(fi < nf){ 1145 if(rpc >= sym.fns[fi].offset && rpc < sym.fns[fi].stoppc){ 1146 if(t) 1147 fun[fi].counte += f; 1148 else 1149 fun[fi].count += f; 1150 } 1151 else{ 1152 while(fi < nf && rpc >= sym.fns[fi].stoppc) 1153 fi++; 1154 # fi++; 1155 if(fi >= nf && f != 0) 1156 error0(sys->sprint("bad fn index")); 1157 if(fi < nf){ 1158 if(t) 1159 fun[fi].counte += f; 1160 else 1161 fun[fi].count += f; 1162 } 1163 } 1164 } 1165# sys->print("pc %d count %d l1 %d l2 %d\n", rpc, f, l1, l2); 1166 } 1167 return (name, line, fun, ktot, ktot1); 1168} 1169 1170memshow(p: Prof, v: int): int 1171{ 1172 i: int; 1173 1174 cleare(); 1175 tot := p.total; 1176 if(p.total == 0 && p.totals[0] == 0) 1177 return 0; 1178 verbose := v&VERBOSE; 1179 fullhdr := v&FULLHDR; 1180 for(ml := p.mods; ml != nil; ml = tl ml){ 1181 mp := hd ml; 1182 if(mp.total == 0 && mp.totals[0] == 0) 1183 continue; 1184 if((b := getb(mp.path)) == nil) 1185 continue; 1186 sys->print("\nModule: %s(%s)\n\n", mp.name, mp.path); 1187 line := mp.linetab; 1188 if(v&LINE){ 1189 bio := bufio->open(b, Bufio->OREAD); 1190 if(bio == nil){ 1191 error(sys->sprint("cannot open %s for reading", b)); 1192 continue; 1193 } 1194 i = 1; 1195 ll := len line/2; 1196 while((s := bio.gets('\n')) != nil){ 1197 f := g := 0; 1198 if(i < ll){ 1199 f = line[2*i]; 1200 g = line[2*i+1]; 1201 } 1202 if(verbose || f != 0 || g != 0){ 1203 if(fullhdr) 1204 sys->print("%s:", b); 1205 sys->print("%d\t%d\t%d\t%s", i, f, g, s); 1206 } 1207 i++; 1208 } 1209 if(v&(FUNCTION|MODULE)) 1210 sys->print("\n"); 1211 } 1212 if(v&FUNCTION){ 1213 fun := mp.funtab; 1214 nf := len fun; 1215 for(i = 0; i < nf; i++) 1216 if(verbose || fun[i].count != 0 || fun[i].counte != 0){ 1217 if(fullhdr) 1218 sys->print("%s:", b); 1219 sys->print("%d\t%d\t%d\t%s()\n", fun[i].line, fun[i].count, fun[i].counte, fun[i].name); 1220 } 1221 if(v&MODULE) 1222 sys->print("\n"); 1223 } 1224 if(v&MODULE) 1225 sys->print("Module totals\t%d\t%d\n\n", mp.total, mp.totals[0]); 1226 } 1227 if(p.mods != nil && tl p.mods != nil) 1228 sys->print("Grand totals\t%d\t%d\n\n", p.total, p.totals[0]); 1229 return 0; 1230} 1231