-
Notifications
You must be signed in to change notification settings - Fork 4
/
tree_base.jl
139 lines (127 loc) · 4.7 KB
/
tree_base.jl
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# `tree_base(pd)` returns the same results as Profile.print().
# It's equivalent to `tree`, but ~3X faster, so I'm keeping it here.
function tree_base(bt::Vector{Vector{UInt64}}, counts::Vector{Int},
lidict::LineInfoFlatDict, level::Int, fmt::ProfileFormat, noisefloor::Int)
if level > fmt.maxdepth
return []::Any
end
# Organize backtraces into groups that are identical up to this level
if fmt.combine
# Combine based on the line information
d = Dict{StackFrame,Vector{Int}}()
for i = 1:length(bt)
ip = bt[i][level + 1]
key = lidict[ip]
indx = Base.ht_keyindex(d, key)
if haskey(d, key)
push!(d[key], i)
else
d[key] = [i]
end
end
# Generate counts
dlen = length(d)
lilist = Vector{StackFrame}(dlen)
group = Vector{Vector{Int}}(dlen)
n = Vector{Int}(dlen)
i = 1
for (key, v) in d
lilist[i] = key
group[i] = v
n[i] = sum(counts[v])
i += 1
end
else
# Combine based on the instruction pointer
d = Dict{UInt64,Vector{Int}}()
for i = 1:length(bt)
key = bt[i][level+1]
if haskey(d, key)
push!(d[key], i)
else
d[key] = [i]
end
end
# Generate counts, and do the code lookup
dlen = length(d)
lilist = Vector{StackFrame}(dlen)
group = Vector{Vector{Int}}(dlen)
n = Vector{Int}(dlen)
i = 1
for (key, v) in d
lilist[i] = lidict[key]
group[i] = v
n[i] = sum(counts[v])
i += 1
end
end
# Order the line information
if length(lilist) > 1
p = Profile.liperm(lilist)
lilist = lilist[p]
group = group[p]
n = n[p]
end
# Recurse to the next level
len = Int[length(x) for x in bt]
out = Node[]
for i = 1:length(lilist)
n[i] < fmt.mincount && continue
n[i] < noisefloor && continue
idx = group[i]
keep = len[idx] .> level+1
if any(keep)
idx = idx[keep]
children = tree_base(bt[idx], counts[idx], lidict, level + 1, fmt,
fmt.noisefloor > 0 ?
floor(Int, fmt.noisefloor * sqrt(n[i])) : 0)
else
children = []
end
push!(out, Node(lilist[i], n[i], children))
end
return out
end
function tree_base(data::Vector{UInt64}, lidict::LineInfoFlatDict, fmt::ProfileFormat)
if !fmt.C
data = purgeC(data, lidict)
end
bt, counts = tree_aggregate(data)
level = 0
len = Int[length(x) for x in bt]
keep = len .> 0
# Using UNKNOWN as the root works, but it should ideally be a different flag value...
# Or use a Nullable. - @cstjean
return Node(UNKNOWN, -1, tree_base(bt[keep], counts[keep], lidict, level, fmt, 0))
end
function tree_base(data::Vector, lidict::LineInfoDict, fmt::ProfileFormat)
newdata, newdict = flatten(data, lidict)
return tree_base(newdata, newdict, fmt)
end
"""
tree(pd::ProfileData; C = false, combine = true, maxdepth::Int = typemax(Int),
mincount::Int = 0, noisefloor = 0)
Returns a tree view of the profiling data `pd`
The keyword arguments can be any combination of:
- `C` -- If `true`, backtraces from C and Fortran code are shown (normally they are excluded).
- `combine` -- If `true` (default), instruction pointers are merged that correspond to the same line of code.
- `maxdepth` -- Limits the depth higher than `maxdepth` in the `:tree` format.
- `sortedby` -- Controls the order in `:flat` format. `:filefuncline` (default) sorts by the source
line, whereas `:count` sorts in order of number of collected samples.
- `noisefloor` -- Limits frames that exceed the heuristic noise floor of the sample (only applies to format `:tree`).
A suggested value to try for this is 2.0 (the default is 0). This parameter hides samples for which `n <= noisefloor * √N`,
where `n` is the number of samples on this line, and `N` is the number of samples for the callee.
- `mincount` -- Limits the printout to only those lines with at least `mincount` occurrences.
"""
function tree_base(pd::ProfileData;
C = false,
combine = true,
maxdepth::Int = typemax(Int),
mincount::Int = 0,
noisefloor = 0)
tree_base(pd.data, pd.lidict, ProfileFormat(C = C,
combine = combine,
maxdepth = maxdepth,
mincount = mincount,
noisefloor = noisefloor))
end