diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 3c3b6cb65ad00..0fafa94a8cf1f 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -560,26 +560,33 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI return root end -# Print a "branch" starting at a particular level. This gets called recursively. +# Print the stack frame tree starting at a particular root. Uses a worklist to +# avoid stack overflows. function tree(io::IO, bt::StackFrameTree, level::Int, cols::Int, fmt::ProfileFormat, noisefloor::Int) - level > fmt.maxdepth && return - isempty(bt.down) && return - # Order the line information - nexts = collect(values(bt.down)) - lilist = collect(frame.frame for frame in nexts) - counts = collect(frame.count for frame in nexts) - # Generate the string for each line - strs = tree_format(lilist, counts, level, cols) - # Recurse to the next level - for i in liperm(lilist) - down = nexts[i] - count = down.count - count < fmt.mincount && continue - count < noisefloor && continue - str = strs[i] - println(io, isempty(str) ? "$count unknown stackframe" : str) - noisefloor_down = fmt.noisefloor > 0 ? floor(Int, fmt.noisefloor * sqrt(count)) : 0 - tree(io, down, level + 1, cols, fmt, noisefloor_down) + worklist = Tuple{StackFrameTree, Int, Int, Union{String, Nothing}}[ + (bt, level, noisefloor, nothing)] + while !isempty(worklist) + (bt, level, noisefloor, str) = popfirst!(worklist) + str !== nothing && println(io, str) + level > fmt.maxdepth && continue + isempty(bt.down) && continue + # Order the line information + nexts = collect(values(bt.down)) + lilist = collect(frame.frame for frame in nexts) + counts = collect(frame.count for frame in nexts) + # Generate the string for each line + strs = tree_format(lilist, counts, level, cols) + # Recurse to the next level + for i in liperm(lilist) + down = nexts[i] + count = down.count + count < fmt.mincount && continue + count < noisefloor && continue + str = strs[i] + isempty(str) && (str = "$count unknown stackframe") + noisefloor_down = fmt.noisefloor > 0 ? floor(Int, fmt.noisefloor * sqrt(count)) : 0 + push!(worklist, (down, level+1, noisefloor_down, str)) + end end nothing end