summaryrefslogtreecommitdiff
path: root/support/dumpleak.myr
blob: 06a4953f448b192b08402e91622a1d46024848bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std
use bio

var stackaggr = 10

const main = {args
	var tab : std.htab(int64, (int64, int64[:]))#
	var cmd

	cmd = std.optparse(args, &[
		.argdesc="dumps...",
		.opts=[
			[.opt='d', .arg="depth", .desc="aggregate by at most `depth` stack elements"],
		][:]
	])

	for opt in cmd.opts
		match opt
		| ('d', depth):
			match std.intparse(depth)
			| `std.Some d:	stackaggr = d
			| `std.None:	std.fatal("could not parse stack depth {}\n", depth)
			;;
		| _:	std.die("unreachable")
		;;
	;;

	tab = std.mkht(std.inthash, std.inteq)
	for d in cmd.args
		match bio.open(d, bio.Rd)
		| `std.Ok f:	dump(d, f, tab)
		| `std.Err e:	std.fatal("could not open {}: {}\n", d, e)
		;;
	;;
}

const dump = {path, f, tab
	while true
		match bio.getle64(f)
		| `bio.Ok 0:	tracealloc(path, f, tab)
		| `bio.Ok 1:	tracefree(path, f, tab)
		| `bio.Eof:	break
		| `bio.Ok wat:	std.fatal("unknown action type {x}\n", wat)
		| `bio.Err e:	std.fatal("failed to read {}: {}\n", path, e)
		;;
	;;
	dumptrace(tab)
}

const tracealloc = {path, f, tab
	var ptr, sz, stk

	ptr = get64(path, f)
	sz = get64(path, f)
	stk = [][:]
	for var i = 0; i < 10; i++
		std.slpush(&stk, get64(path, f))
	;;
	std.htput(tab, ptr, (sz, stk))
}

const tracefree = {path, f, tab
	var ptr, sz

	ptr = get64(path, f)
	sz = get64(path, f)
	std.htdel(tab, ptr)
}

const dumptrace = {tab
	var aggr

	aggr = std.mkht(hashintsl, std.sleq)
	for (k, (sz, stk)) in std.htbykeyvals(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)) in std.htbykeyvals(aggr)
		std.put("unfreed: {} (size: {}): {}\n", n, sz, stk)
	;;
}

const get64 = {path, f
	match bio.getle64(f)
	| `bio.Ok v:	-> v
	| res:	std.fatal("failed to read {}: {}\n", path, res)
	;;
}

const hashintsl = {sl
	var h

	h = 0
	for i in sl
		h ^= std.inthash(i)
	;;
	-> h
}