diff options
Diffstat (limited to 'appl/lib/profile.b')
| -rw-r--r-- | appl/lib/profile.b | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/appl/lib/profile.b b/appl/lib/profile.b new file mode 100644 index 00000000..20ad94b3 --- /dev/null +++ b/appl/lib/profile.b @@ -0,0 +1,1230 @@ +implement Profile; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "bufio.m"; + bufio: Bufio; + Iobuf: import bufio; +include "workdir.m"; + workdir: Workdir; +include "debug.m"; + debug: Debug; + Sym: import debug; +include "dis.m"; + dism: Dis; +include "profile.m"; + +# merge common code + +PROF: con "/prof"; +CTL: con "ctl"; +NAME: con "name"; +MPATH: con "path"; +HISTOGRAM: con "histogram"; + +inited: int; +modl: string; +lasterr: string; + +bspath := array[] of +{ + ("/dis/", "/appl/cmd/"), + ("/dis/", "/appl/"), +}; + +error(s: string) +{ + lasterr = sys->sprint("%s: %r", s); +} + +error0(s: string) +{ + lasterr = s; +} + +cleare() +{ + lasterr = nil; +} + +lasterror(): string +{ + return lasterr; +} + +init(): int +{ + cleare(); + sys = load Sys Sys->PATH; + bufio = load Bufio Bufio->PATH; + debug = load Debug Debug->PATH; + if(debug == nil){ + error("cannot load Debug module"); + return -1; + } + debug->init(); + (ok, nil) := sys->stat(PROF + "/ctl"); + if (ok == -1) { + if(sys->bind("#P", PROF, Sys->MREPL|Sys->MCREATE) < 0){ + error(sys->sprint("cannot bind prof device to /prof")); + return -1; + } + } + inited = 1; + return 0; +} + +end(): int +{ + cleare(); + inited = 0; + modl = nil; + if(write(mkpath(PROF, CTL), "end") < 0) + return -1; + return 0; +} + +start(): int +{ + cleare(); + if(!inited && init() < 0) + return -1; + if(write(mkpath(PROF, CTL), "module " + modl) < 0) + return -1; + if(write(mkpath(PROF, CTL), "start") < 0) + return -1; + return 0; +} + +cpstart(pid: int): int +{ + cleare(); + if(!inited && init() < 0) + return -1; + if(write(mkpath(PROF, CTL), "module " + modl) < 0) + return -1; + if(write(mkpath(PROF, CTL), "startcp " + string pid) < 0) + return -1; + return 0; +} + +memstart(m: int): int +{ + cleare(); + if(!inited && init() < 0) + return -1; + if(modl != nil && write(mkpath(PROF, CTL), "module " + modl) < 0) + return -1; + start := "startmp"; + if(m == 0) + m = MAIN|HEAP|IMAGE; + if(m&MAIN) + start += "1"; + if(m&HEAP) + start += "2"; + if(m&IMAGE) + start += "3"; + if(write(mkpath(PROF, CTL), start) < 0) + return -1; + return 0; +} + +stop(): int +{ + cleare(); + if(!inited && init() < 0) + return -1; + if(write(mkpath(PROF, CTL), "stop") < 0) + return -1; + return 0; +} + +sample(i: int): int +{ + cleare(); + if(i <= 0){ + error0(sys->sprint("bad sample rate %d", i)); + return -1; + } + if(write(mkpath(PROF, CTL), "interval " + string i) < 0) + return -1; + return 0; +} + +profile(m: string): int +{ + cleare(); + modl = m + " " + modl; + return 0; +} + +stats(): Prof +{ + mp: Modprof; + p: Prof; + mpl: list of Modprof; + + cleare(); + fd := sys->open(PROF, Sys->OREAD); + if(fd == nil){ + error(sys->sprint("cannot open %s for reading", PROF)); + return (nil, 0, nil); + } + total := 0; + for(;;){ + (nr, d) := sys->dirread(fd); + if(nr <= 0) + break; + for(i := 0; i < nr; i++){ + if(d[i].name == CTL) + continue; + dn := mkpath(PROF, d[i].name); + mp.name = read(mkpath(dn, NAME)); + mp.path = read(mkpath(dn, MPATH)); + fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); + if(fdh == nil) + continue; + (mp.srcpath, mp.linetab, mp.funtab, mp.total) = tprofile(fdh, mp.path); + if((sp := getb(mp.path)) != nil) + mp.srcpath = sp; + if(mp.total != 0){ + mpl = mp :: mpl; + total += mp.total; + } + } + } + p.mods = mpl; + p.total = total; + return p; +} + +cpstats(rec: int, v: int): Prof +{ + m: string; + mp: Modprof; + p: Prof; + mpl: list of Modprof; + + cleare(); + fd := sys->open(PROF, Sys->OREAD); + if(fd == nil){ + error(sys->sprint("cannot open %s for reading", PROF)); + return (nil, 0, nil); + } + total := 0; + for(;;){ + (nr, d) := sys->dirread(fd); + if(nr <= 0) + break; + for(i:=0; i<nr; i++){ + if(d[i].name == CTL) + continue; + dn := mkpath(PROF, d[i].name); + mp.name = read(mkpath(dn, NAME)); + mp.path = read(mkpath(dn, MPATH)); + fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); + if(fdh == nil) + continue; + (m, mp.srcpath, mp.rawtab, mp.linetab, mp.rngtab, mp.total, mp.coverage) = cprofile(fdh, mp.path, rec, v); + if(mp.name == nil) + mp.name = m; + if((sp := getb(mp.path)) != nil) + mp.srcpath = sp; + if(len mp.rawtab > 0){ + mpl = mp :: mpl; + total += mp.total; + } + } + } + p.mods = mpl; + p.total = total; + return p; +} + +cpfstats(v: int): Prof +{ + mp: Modprof; + p: Prof; + mpl: list of Modprof; + + cleare(); + total := 0; + (nil, l) := sys->tokenize(modl, " "); + for( ; l != nil; l = tl l){ + s := hd l; + suf := suff(s); + if(suf == nil) + s += ".dis"; + else + s = repsuff(s, "."+suf, ".dis"); + if(!exists(s) && s[0] != '/' && s[0:2] != "./") + s = "/dis/"+s; + mp.path = s; + (mp.name, mp.srcpath, mp.rawtab, mp.linetab, mp.rngtab, mp.total, mp.coverage) = cprofile(nil, mp.path, 1, v); + if((sp := getb(mp.path)) != nil) + mp.srcpath = sp; + if(len mp.rawtab > 0){ + mpl = mp :: mpl; + total += mp.total; + } + } + p.mods = mpl; + p.total = total; + return p; +} + +memstats(): Prof +{ + mp: Modprof; + p: Prof; + mpl: list of Modprof; + + cleare(); + fd := sys->open(PROF, Sys->OREAD); + if(fd == nil){ + error(sys->sprint("cannot open %s for reading", PROF)); + return (nil, 0, nil); + } + total := totale := 0; + for(;;){ + (nr, d) := sys->dirread(fd); + if(nr <= 0) + break; + for(i:=0; i<nr; i++){ + if(d[i].name == CTL) + continue; + dn := mkpath(PROF, d[i].name); + mp.name = read(mkpath(dn, NAME)); + mp.path = read(mkpath(dn, MPATH)); + fdh := sys->open(mkpath(dn, HISTOGRAM), Sys->OREAD); + if(fdh == nil) + continue; + mp.totals = array[1] of int; + (mp.srcpath, mp.linetab, mp.funtab, mp.total, mp.totals[0]) = mprofile(fdh, mp.path); + if((sp := getb(mp.path)) != nil) + mp.srcpath = sp; + if(mp.total != 0 || mp.totals[0] != 0){ + mpl = mp :: mpl; + total += mp.total; + totale += mp.totals[0]; + } + } + } + p.mods = mpl; + p.total = total; + p.totals = array[1] of int; + p.totals[0] = totale; + return p; +} + +tprofile(fd: ref Sys->FD, dis: string): (string, array of int, array of Funprof, int) +{ + sbl := findsbl(dis); + if(sbl == nil){ + error0(sys->sprint("cannot locate symbol table file for %s", dis)); + return (nil, nil, nil, 0); + } + (sym, err) := debug->sym(sbl); + if(sym == nil){ + error0(sys->sprint("bad symbol table file: %s", err)); + return (nil, nil, nil, 0); + } + nlines := 0; + nl := len sym.src; + for(i := 0; i < nl; i++){ + if((l := sym.src[i].stop.line) > nlines) + nlines = l; + } + name := sym.src[0].start.file; + line := array[nlines+1] of int; + for(i = 0; i <= nlines; i++) + line[i] = 0; + nf := len sym.fns; + fun := array[nf] of Funprof; + for(i = 0; i < nf; i++){ + fun[i].name = sym.fns[i].name; + # src seems to be always nil + # fun[i].file = sym.fns[i].src.start.file; + # fun[i].line = (sym.fns[i].src.start.line+sym.fns[i].src.stop.line)/2; + src := sym.pctosrc(sym.fns[i].offset); + if(src != nil) + fun[i].line = src.start.line; + else + fun[i].line = 0; + fun[i].count = 0; + } + buf := array[32] of byte; + # pc := 0; + tot := 0; + fi := 0; +# for(i=0; i < nl; i++) sys->print("%d -> %d\n", i, sym.pctosrc(i).start.line); + while((m := sys->read(fd, buf, len buf)) > 0){ + (nw, lw) := sys->tokenize(string buf[0:m], " "); + if(nw != 2){ + error0("bad histogram data"); + return (nil, nil, nil, 0); + } + pc := int hd lw; + f := int hd tl lw; + rpc := pc-1; + src := sym.pctosrc(rpc); + if(src == nil) + continue; + l1 := src.start.line; + l2 := src.stop.line; + if(l1 == 0 || l2 == 0) + continue; + if((nl = l2-l1+1) == 1) + line[l1] += f; + else{ + q := f/nl; + r := f-q*nl; + for(i = l1; i <= l2; i++) + line[i] += q+(r-->0); + } + if(fi < nf){ + if(rpc >= sym.fns[fi].offset && rpc < sym.fns[fi].stoppc) + fun[fi].count += f; + else{ + while(fi < nf && rpc >= sym.fns[fi].stoppc) + fi++; + # fi++; + if(fi >= nf && f != 0) + error0(sys->sprint("bad fn index")); + if(fi < nf) + fun[fi].count += f; + } + } + tot += f; +# sys->print("pc %d count %d l1 %d l2 %d\n", rpc, f, l1, l2); + } + return (name, line, fun, tot); +} + +cprofile(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) +{ + freq := v&FREQUENCY; + sbl := findsbl(dis); + if(sbl == nil){ + error0(sys->sprint("cannot locate symbol table file for %s", dis)); + return (nil, nil, nil, nil, nil, 0, 0); + } + (sym, err) := debug->sym(sbl); + if(sym == nil){ + error0(sys->sprint("bad symbol table file: %s", err)); + return (nil, nil, nil, nil, nil, 0, 0); + } + nlines := 0; + nl := len sym.src; + for(i := 0; i < nl; i++){ + if((l := sym.src[i].start.line) > nlines) + nlines = l; + if((l = sym.src[i].stop.line) > nlines) + nlines = l; + } + name := sym.src[0].start.file; + line := array[nlines+1] of int; + for(i = 0; i <= nlines; i++){ + if(freq) + line[i] = -1; + else + line[i] = 0; + } + rng := array[nlines+1] of ref Range; + for(i = 0; i < nl; i++) + cover(i, -1, sym, line, rng, freq); + buf := array[32] of byte; + nr := 0; + r := array[1024] of (int, int); + while((m := sys->read(fd, buf, len buf)) > 0){ + (nw, lw) := sys->tokenize(string buf[0:m], " "); + if(nw != 2){ + error0("bad histogram data"); + return (nil, nil, nil, nil, nil, 0, 0); + } + (r, nr) = add(r, nr, int hd lw, int hd tl lw); + } + r = clip(r, nr); + if(rec){ + wt := nr > 0; + prf := repsuff(sbl, ".sbl", ".prf"); + if(exists(prf)){ + if(stamp(sbl) > stamp(prf)){ + error0(sys->sprint("%s later than %s", sbl, prf)); + return (nil, nil, nil, nil, nil, 0, 0); + } + r = mergeprof(r, readprof(prf)); + nr = len r; + } + if(wt && writeprof(prf, r) < 0){ + error0(sys->sprint("cannot write profile file %s", prf)); + return (nil, nil, nil, nil, nil, 0, 0); + } + } + tot := 0; + lpc := 0; + dise := dist := 0; + for(i = 0; i < nr; i++){ + (pc, f) := r[i]; + for( ; lpc < pc; lpc++){ + cover(lpc, 0, sym, line, rng, freq); + dist++; + } + cover(pc, f, sym, line, rng, freq); + dist++; + if(f != 0) + dise++; + tot += f; + lpc = pc+1; + } + for( ; lpc < nl; lpc++){ + cover(lpc, 0, sym, line, rng, freq); + dist++; + } + if(dist == 0) + dist = 1; + return (sym.name, name, r, line, rng, tot, (100*dise)/dist); +} + +show(p: Prof, v: int): int +{ + i: int; + + cleare(); + tot := p.total; + if(tot == 0) + return 0; + verbose := v&VERBOSE; + fullhdr := v&FULLHDR; + for(ml := p.mods; ml != nil; ml = tl ml){ + mp := hd ml; + if(mp.total == 0) + continue; + if((b := getb(mp.path)) == nil) + continue; + sys->print("\nModule: %s(%s)\n\n", mp.name, mp.path); + line := mp.linetab; + if(v&FUNCTION){ + fun := mp.funtab; + nf := len fun; + for(i = 0; i < nf; i++) + if(verbose || fun[i].count != 0){ + if(fullhdr) + sys->print("%s:", b); + sys->print("%d\t%.2f\t%s()\n", fun[i].line, 100.0*(real fun[i].count)/(real tot), fun[i].name); + } + sys->print("\n**** module sampling points %d ****\n\n", mp.total); + if(v&LINE) + sys->print("\n"); + } + if(v&LINE){ + bio := bufio->open(b, Bufio->OREAD); + if(bio == nil){ + error(sys->sprint("cannot open %s for reading", b)); + continue; + } + i = 1; + ll := len line; + while((s := bio.gets('\n')) != nil){ + f := 0; + if(i < ll) + f = line[i]; + if(verbose || f != 0){ + if(fullhdr) + sys->print("%s:", b); + sys->print("%d\t%.2f\t%s", i, 100.0*(real f)/(real tot), s); + } + i++; + } + sys->print("\n**** module sampling points %d ****\n\n", mp.total); + } + } + if(p.mods != nil && tl p.mods != nil) + sys->print("\n**** total sampling points %d ****\n\n", p.total); + return 0; +} + +cpshow(p: Prof, v: int): int +{ + i: int; + + cleare(); + tot := p.total; + fullhdr := v&FULLHDR; + freq := v&FREQUENCY; + for(ml := p.mods; ml != nil; ml = tl ml){ + mp := hd ml; + if((b := getb(mp.path)) == nil) + continue; + sys->print("\nModule: %s(%s)", mp.name, mp.path); + sys->print("\t%d%% coverage\n\n", mp.coverage); + if(mp.coverage == 100 && !freq) + continue; + line := mp.linetab; + rng := mp.rngtab; + bio := bufio->open(b, Bufio->OREAD); + if(bio == nil){ + error(sys->sprint("cannot open %s for reading", b)); + continue; + } + i = 1; + ll := len line; + while((s := bio.gets('\n')) != nil){ + f := 0; + if(i < ll) + f = line[i]; + if(fullhdr) + sys->print("%s:", b); + sys->print("%d\t", i); + if(rng != nil && i < ll && (r := rng[i]) != nil && multirng(r)){ + for( ; r != nil; r = r.n){ + sys->print("%s", trans(r.f, freq)); + if(r.n != nil) + sys->print("|"); + } + } + else + sys->print("%s", trans(f, freq)); + sys->print("\t%s", s); + i++; + } + sys->print("\n**** module dis instructions %d ****\n\n", mp.total); + } + if(p.mods != nil && tl p.mods != nil) + sys->print("\n**** total number dis instructions %d ****\n\n", p.total); + return 0; +} + +coverage(p: Prof, v: int): Coverage +{ + i: int; + clist: Coverage; + + cleare(); + freq := v&FREQUENCY; + for(ml := p.mods; ml != nil; ml = tl ml){ + mp := hd ml; + if((b := getb(mp.path)) == nil) + continue; + line := mp.linetab; + rng := mp.rngtab; + bio := bufio->open(b, Bufio->OREAD); + if(bio == nil){ + error(sys->sprint("cannot open %s for reading", b)); + continue; + } + i = 1; + ll := len line; + llist: list of (list of (int, int, int), string); + while((s := bio.gets('\n')) != nil){ + f := 0; + if(i < ll) + f = line[i]; + rlist: list of (int, int, int); + if(rng != nil && i < ll && (r := rng[i]) != nil){ + for( ; r != nil; r = r.n){ + if(r.u == ∞) + r.u = len s - 1; + if(freq){ + if(r.f > 0) + rlist = (r.l, r.u, r.f) :: rlist; + } + else{ + if(r.f&NEX) + rlist = (r.l, r.u, (r.f&EXE)==EXE) :: rlist; + } + } + } + else{ + if(freq){ + if(f > 0) + rlist = (0, len s - 1, f) :: rlist; + } + else{ + if(f&NEX) + rlist = (0, len s - 1, (f&EXE)==EXE) :: nil; + } + } + llist = (rlist, s) :: llist; + i++; + } + if(freq) + n := mp.total; + else + n = mp.coverage; + clist = (b, n, rev(llist)) :: clist; + } + return clist; +} + +∞: con 1<<30; + +DIS: con 1; +EXE: con 2; +NEX: con 4; + +cover(pc: int, f: int, sym: ref Debug->Sym, line: array of int, rng: array of ref Range, freq: int) +{ + v: int; + + src := sym.pctosrc(pc); + if(src == nil) + return; + l1 := src.start.line; + l2 := src.stop.line; + if(l1 == 0 || l2 == 0) + return; + c1 := src.start.pos; + c2 := src.stop.pos; + if(freq){ + v = 0; + if(f > 0) + v = f; + } + else{ + v = DIS; + if(f > 0) + v = EXE; + else if(f == 0) + v = NEX; + } + for(i := l1; i <= l2; i++){ + r1 := 0; + r2 := ∞; + if(i == l1) + r1 = c1; + if(i == l2) + r2 = c2; + if(rng != nil) + rng[i] = mrgrng(addrng(rng[i], r1, r2, v, freq)); + if(freq){ + if(v > line[i]) + line[i] = v; + } + else + line[i] |= v; + # if(i==123) sys->print("%d %d-%d %d %d\n", i, r1, r2, v, pc); + } +} + +arng(c1: int, c2: int, f: int, tr: ref Range, lr: ref Range, r: ref Range): ref Range +{ + nr := ref Range(c1, c2, f, tr); + if(lr == nil) + r = nr; + else + lr.n = nr; + return r; +} + +addrng(r: ref Range, c1: int, c2: int, f: int, freq: int): ref Range +{ + lr: ref Range; + + if(c1 > c2) + return r; + for(tr := r; tr != nil; tr = tr.n){ + r1 := tr.l; + r2 := tr.u; + if(c1 < r1){ + if(c2 < r1) + return arng(c1, c2, f, tr, lr, r); + else if(c2 <= r2){ + r = addrng(r, c1, r1-1, f, freq); + return addrng(r, r1, c2, f, freq); + } + else{ + r = addrng(r, c1, r1-1, f, freq); + r = addrng(r, r1, r2, f, freq); + return addrng(r, r2+1, c2, f, freq); + } + } + else if(c1 <= r2){ + if(c2 <= r2){ + v := tr.f; + tr.l = c1; + tr.u = c2; + if(freq){ + if(f > tr.f) + tr.f = f; + } + else + tr.f |= f; + r = addrng(r, r1, c1-1, v, freq); + return addrng(r, c2+1, r2, v, freq); + } + else{ + r = addrng(r, c1, r2, f, freq); + return addrng(r, r2+1, c2, f, freq); + } + } + lr = tr; + } + return arng(c1, c2, f, nil, lr, r); +} + +mrgrng(r: ref Range): ref Range +{ + lr: ref Range; + + for(tr := r; tr != nil; tr = tr.n){ + if(lr != nil && lr.u >= tr.l) + sys->print("ERROR %d %d\n", lr.u, tr.l); + if(lr != nil && lr.f == tr.f && lr.u+1 == tr.l){ + lr.u = tr.u; + lr.n = tr.n; + } + else + lr = tr; + } + return r; +} + +multirng(r: ref Range): int +{ + f := r.f; + for(tr := r; tr != nil; tr = tr.n) + if(tr.f != f) + return 1; + return 0; +} + +add(r: array of (int, int), nr: int, pc: int, f: int): (array of (int, int), int) +{ + l := len r; + if(nr == l){ + s := array[2*l] of (int, int); + s[0:] = r[0: nr]; + r = s; + } + r[nr++] = (pc, f); + return (r, nr); +} + +clip(r: array of (int, int), nr: int): array of (int, int) +{ + l := len r; + if(nr < l){ + s := array[nr] of (int, int); + s[0:] = r[0: nr]; + r = s; + } + return r; +} + +readprof(f: string): array of (int, int) +{ + b := bufio->open(f, Bufio->OREAD); + if(b == nil) + return nil; + nr := 0; + r := array[1024] of (int, int); + while((buf := b.gets('\n')) != nil){ + (nw, lw) := sys->tokenize(buf, " "); + if(nw != 2){ + error0("bad raw data"); + return nil; + } + (r, nr) = add(r, nr, int hd lw, int hd tl lw); + } + r = clip(r, nr); + return r; +} + +mergeprof(r1, r2: array of (int, int)): array of (int, int) +{ + nr := 0; + r := array[1024] of (int, int); + l1 := len r1; + l2 := len r2; + for((i, j) := (0, 0); i < l1 || j < l2; ){ + if(i < l1) + (pc1, f1) := r1[i]; + else + pc1 = ∞; + if(j < l2) + (pc2, f2) := r2[j]; + else + pc2 = ∞; + if(pc1 < pc2){ + (r, nr) = add(r, nr, pc1, f1); + i++; + } + else if(pc1 > pc2){ + (r, nr) = add(r, nr, pc2, f2); + j++; + } + else{ + (r, nr) = add(r, nr, pc1, f1+f2); + i++; + j++; + } + } + r = clip(r, nr); + return r; +} + +writeprof(f: string, r: array of (int, int)): int +{ + fd := sys->create(f, Sys->OWRITE, 8r664); + if(fd == nil) + return -1; + l := len r; + for(i := 0; i < l; i++){ + (pc, fr) := r[i]; + sys->fprint(fd, "%d %d\n", pc, fr); + } + return 0; +} + +trans(f: int, freq: int): string +{ + if(freq) + return transf(f); + else + return transc(f); +} + +transf(f: int): string +{ + if(f < 0) + return " "; + return string f; +} + +transc(f: int): string +{ + c := ""; + case(f){ + 0 => c = " "; + DIS|EXE => c = "+"; + DIS|NEX => c = "-"; + DIS|EXE|NEX => c = "?"; + * => + error(sys->sprint("bad code %d\n", f)); + } + return c; +} + +getb(dis: string): string +{ + b := findb(dis); + if(b == nil){ + error0(sys->sprint("cannot locate source file for %s\n", dis)); + return nil; + } + if(stamp(b) > stamp(dis)){ + error0(sys->sprint("%s later than %s", b, dis)); + return nil; + } + return b; +} + +mkpath(d: string, f: string): string +{ + return d+"/"+f; +} + +suff(s: string): string +{ + (n, l) := sys->tokenize(s, "."); + if(n > 1){ + while(tl l != nil) + l = tl l; + return hd l; + } + return nil; +} + +repsuff(s: string, old: string, new: string): string +{ + lo := len old; + ls := len s; + if(lo <= ls && s[ls-lo:ls] == old) + return s[0:ls-lo]+new; + return s; +} + +read(f: string): string +{ + if((fd := sys->open(f, Sys->OREAD)) == nil){ + error(sys->sprint("cannot open %s for reading", f)); + return nil; + } + buf := array[128] of byte; + n := sys->read(fd, buf, len buf); + return string buf[0:n]; +} + +write(f: string, s: string): int +{ + if((fd := sys->open(f, Sys->OWRITE)) == nil){ + error(sys->sprint("cannot open %s for writing", f)); + return -1; + } + b := array of byte s; + if((n := sys->write(fd, b, len b)) != len b){ + error(sys->sprint("cannot write %s to file %s", s, f)); + return -1; + } + return 0; +} + +exists(f: string): int +{ + return sys->open(f, Sys->OREAD) != nil; +} + +stamp(f: string): int +{ + (ok, d) := sys->stat(f); + if(ok < 0) + return 0; + return d.mtime; +} + +findb(dis: string): string +{ + if(dism == nil){ + dism = load Dis Dis->PATH; + if(dism != nil) + dism->init(); + } + if(dism != nil && (b := dism->src(dis)) != nil && exists(b)) + return b; + return findfile(repsuff(dis, ".dis", ".b")); +} + +findsbl(dis: string): string +{ + b := findb(dis); + if(b != nil){ + sbl := repsuff(b, ".b", ".sbl"); + if(exists(sbl)) + return sbl; + return findfile(sbl); + } + return findfile(repsuff(dis, ".dis", ".sbl")); +} + +findfile(s: string): string +{ + if(exists(s)) + return s; + if(s != nil && s[0] != '/'){ + if(workdir == nil) + workdir = load Workdir Workdir->PATH; + if(workdir == nil){ + error("cannot load Workdir module"); + return nil; + } + s = workdir->init() + "/" + s; + } + (d, f) := split(s, '/'); + (fp, nil) := split(f, '.'); + if(fp != nil) + fp = fp[0: len fp - 1]; + for(k := 0; k < 2; k++){ + if(k == 0) + str := s; + else + str = d; + ls := len str; + for(i := 0; i < len bspath; i++){ + (dis, src) := bspath[i]; + ld := len dis; + if(ls >= ld && str[:ld] == dis){ + if(k == 0) + ns := src + str[ld:]; + else + ns = src + str[ld:] + fp + "/" + f; + if(exists(ns)) + return ns; + } + } + } + return nil; +} + +split(s: string, c: int): (string, string) +{ + for(i := len s - 1; i >= 0; --i) + if(s[i] == c) + break; + return (s[0:i+1], s[i+1:]); +} + +rev(llist: list of (list of (int, int, int), string)): list of (list of (int, int, int), string) +{ + r: list of (list of (int, int, int), string); + + for(l := llist; l != nil; l = tl l) + r = hd l :: r; + return r; +} + +mprofile(fd: ref Sys->FD, dis: string): (string, array of int, array of Funprof, int, int) +{ + sbl := findsbl(dis); + if(sbl == nil){ + error0(sys->sprint("cannot locate symbol table file for %s", dis)); + return (nil, nil, nil, 0, 0); + } + (sym, err) := debug->sym(sbl); + if(sym == nil){ + error0(sys->sprint("bad symbol table file: %s", err)); + return (nil, nil, nil, 0, 0); + } + nlines := 0; + nl := len sym.src; + for(i := 0; i < nl; i++){ + if((l := sym.src[i].stop.line) > nlines) + nlines = l; + } + name := sym.src[0].start.file; + nl0 := 2*(nlines+1); + line := array[nl0] of int; + for(i = 0; i < nl0; i++) + line[i] = 0; + nf := len sym.fns; + fun := array[nf] of Funprof; + for(i = 0; i < nf; i++){ + fun[i].name = sym.fns[i].name; + # src seems to be always nil + # fun[i].file = sym.fns[i].src.start.file; + # fun[i].line = (sym.fns[i].src.start.line+sym.fns[i].src.stop.line)/2; + src := sym.pctosrc(sym.fns[i].offset); + if(src != nil) + fun[i].line = src.start.line; + else + fun[i].line = 0; + fun[i].count = fun[i].counte = 0; + } + buf := array[32] of byte; + # pc := 0; + ktot := ktot1 := 0; + fi := 0; +# for(i=0; i < nl; i++) sys->print("%d -> %d\n", i, sym.pctosrc(i).start.line); + while((m := sys->read(fd, buf, len buf)) > 0){ + (nw, lw) := sys->tokenize(string buf[0:m], " "); + if(nw != 2){ + error0("bad histogram data"); + return (nil, nil, nil, 0, 0); + } + pc := int hd lw; + f := int hd tl lw; + if(pc == 0){ + ktot = f; + continue; + } + if(pc == 1){ + ktot1 = f; + continue; + } + pc -= 2; + t := pc&1; + pc /= 2; + rpc := pc-1; + src := sym.pctosrc(rpc); + if(src == nil) + continue; + l1 := src.start.line; + l2 := src.stop.line; + if(l1 == 0 || l2 == 0) + continue; + if((nl = l2-l1+1) == 1) + line[2*l1+t] += f; + else{ + q := f/nl; + r := f-q*nl; + for(i = l1; i <= l2; i++) + line[2*i+t] += q+(r-->0); + } + if(fi < nf){ + if(rpc >= sym.fns[fi].offset && rpc < sym.fns[fi].stoppc){ + if(t) + fun[fi].counte += f; + else + fun[fi].count += f; + } + else{ + while(fi < nf && rpc >= sym.fns[fi].stoppc) + fi++; + # fi++; + if(fi >= nf && f != 0) + error0(sys->sprint("bad fn index")); + if(fi < nf){ + if(t) + fun[fi].counte += f; + else + fun[fi].count += f; + } + } + } +# sys->print("pc %d count %d l1 %d l2 %d\n", rpc, f, l1, l2); + } + return (name, line, fun, ktot, ktot1); +} + +memshow(p: Prof, v: int): int +{ + i: int; + + cleare(); + tot := p.total; + if(p.total == 0 && p.totals[0] == 0) + return 0; + verbose := v&VERBOSE; + fullhdr := v&FULLHDR; + for(ml := p.mods; ml != nil; ml = tl ml){ + mp := hd ml; + if(mp.total == 0 && mp.totals[0] == 0) + continue; + if((b := getb(mp.path)) == nil) + continue; + sys->print("\nModule: %s(%s)\n\n", mp.name, mp.path); + line := mp.linetab; + if(v&LINE){ + bio := bufio->open(b, Bufio->OREAD); + if(bio == nil){ + error(sys->sprint("cannot open %s for reading", b)); + continue; + } + i = 1; + ll := len line/2; + while((s := bio.gets('\n')) != nil){ + f := g := 0; + if(i < ll){ + f = line[2*i]; + g = line[2*i+1]; + } + if(verbose || f != 0 || g != 0){ + if(fullhdr) + sys->print("%s:", b); + sys->print("%d\t%d\t%d\t%s", i, f, g, s); + } + i++; + } + if(v&(FUNCTION|MODULE)) + sys->print("\n"); + } + if(v&FUNCTION){ + fun := mp.funtab; + nf := len fun; + for(i = 0; i < nf; i++) + if(verbose || fun[i].count != 0 || fun[i].counte != 0){ + if(fullhdr) + sys->print("%s:", b); + sys->print("%d\t%d\t%d\t%s()\n", fun[i].line, fun[i].count, fun[i].counte, fun[i].name); + } + if(v&MODULE) + sys->print("\n"); + } + if(v&MODULE) + sys->print("Module totals\t%d\t%d\n\n", mp.total, mp.totals[0]); + } + if(p.mods != nil && tl p.mods != nil) + sys->print("Grand totals\t%d\t%d\n\n", p.total, p.totals[0]); + return 0; +} |
