ref: ff88594df5c5df6fb8f227ab8e5df3529ba6e72f
dir: /support/dumpleak.myr/
use std use bio var stackaggr = 10 var summary var allocstats type memstats = struct allocs : std.size allocsz : std.size frees : std.size freesz : std.size tab : std.htab(std.size, (std.size, std.size[:]))# ;; const main = {args var cmd var stats : memstats cmd = std.optparse(args, &[ .argdesc="dumps...", .opts=[ [.opt='a', .arg="", .desc="show all allocations, regardless of frees"], [.opt='d', .arg="depth", .desc="aggregate by at most `depth` stack elements"], [.opt='s', .arg="", .desc="only show a summary of memory activity"], ][:] ]) for opt : cmd.opts match opt | ('a',""): allocstats = true | ('d', depth): match std.intparse(depth) | `std.Some d: stackaggr = d | `std.None: std.fatal("could not parse stack depth {}\n", depth) ;; | ('s', ""): summary = true | _: std.die("unreachable") ;; ;; std.clear(&stats) stats.tab = std.mkht() for d : cmd.args match bio.open(d, bio.Rd) | `std.Ok f: dump(d, f, &stats) | `std.Err e: std.fatal("could not open {}: {}\n", d, e) ;; ;; } const dump = {path, f, stats while true match bio.getle64(f) | `std.Err `bio.Eof: break | `std.Ok 0: tracealloc(path, f, stats) | `std.Ok 1: tracefree(path, f, stats) | `std.Ok wat: std.fatal("unknown action type {x}\n", wat) | `std.Err e: std.fatal("failed to read {}: {}\n", path, e) ;; ;; if !summary dumptrace(stats.tab) ;; dumpsummary(stats) } const dumpsummary = {stats std.put("allocs:\t{}\n", stats.allocs) std.put("allocsz:\t{}\n", stats.allocsz) std.put("frees:\t{}\n", stats.frees) std.put("freesz:\t{}\n", stats.freesz) std.put("livesz:\t{}\n", stats.allocsz - stats.freesz) } const tracealloc = {path, f, stats var ptr, sz, stk ptr = get64(path, f) sz = get64(path, f) stk = [][:] for var i = 0; i < 20; i++ std.slpush(&stk, get64(path, f)) ;; stats.allocs++ stats.allocsz += sz std.htput(stats.tab, ptr, (sz, stk)) } const tracefree = {path, f, stats var ptr, sz ptr = get64(path, f) sz = get64(path, f) stats.frees++ stats.freesz += sz std.htdel(stats.tab, ptr) } const dumptrace = {tab var aggr aggr = std.mkht() for (k, (sz, stk)) : std.byhtkeyvals(tab) match std.htget(aggr, stk[:stackaggr]) | `std.Some (count, total): std.htput(aggr, stk[:stackaggr], (count + 1, sz + total)) | `std.None: std.htput(aggr, stk[:stackaggr], (1, sz)) ;; ;; for (stk, (n, sz)) : std.byhtkeyvals(aggr) std.put("unfreed: {} (size: {}): {}\n", n, sz, stk) ;; } const get64 = {path, f match bio.getle64(f) | `std.Ok v: -> v | res: std.fatal("failed to read {}: {}\n", path, res) ;; }