diff --git a/Project.toml b/Project.toml index 4559bca..658e2e6 100644 --- a/Project.toml +++ b/Project.toml @@ -3,6 +3,8 @@ uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" version = "0.5.6" [deps] +FlameGraphs = "08572546-2f56-4bcf-ba4e-bab62c3a3f89" +LeftChildRightSiblingTrees = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" [compat] diff --git a/src/TimerOutputs.jl b/src/TimerOutputs.jl index 744d953..b289909 100644 --- a/src/TimerOutputs.jl +++ b/src/TimerOutputs.jl @@ -21,5 +21,6 @@ using Printf include("TimerOutput.jl") include("show.jl") include("utilities.jl") +include("profile.jl") end # module diff --git a/src/profile.jl b/src/profile.jl new file mode 100644 index 0000000..ef50e59 --- /dev/null +++ b/src/profile.jl @@ -0,0 +1,42 @@ +import FlameGraphs + +using Base.StackTraces: StackFrame +using LeftChildRightSiblingTrees: Node, addchild + +function max_end_time(to::TimerOutput) + return maximum(child.start_data.time + child.accumulated_data.time for child in values(to.inner_timers)) +end + +# Make a flat frame for this TimerOutput +function _flamegraph_frame(to::TimerOutput, start_ns; toplevel = false) + # TODO: Use a better conversion to a StackFrame so this contains the right kind of data + tt = Symbol(to.name) + sf = StackFrame(tt, Symbol("none"), 0, nothing, false, false, UInt64(0x0)) + status = 0x0 # "default" status -- See FlameGraphs.jl + start = to.start_data.time - start_ns + # TODO: is this supposed to be inclusive or exclusive? + if toplevel + # The root frame covers the total time being measured, so start when the first node + # was created, and stop when the last node was finished. + range = Int(start) : Int(start + (max_end_time(to) - start_ns)) + else + #range = Int(start) : Int(start + TimerOutputs.tottime(to)) + range = Int(start) : Int(start + to.accumulated_data.time) + end + return FlameGraphs.NodeData(sf, status, range) +end + +function to_flamegraph(to::TimerOutput) + # Skip the very top-level node, which contains no useful data + node_data = _flamegraph_frame(to, to.start_data.time; toplevel=true) + root = Node(node_data) + return _to_flamegraph(to, root, to.start_data.time) +end +function _to_flamegraph(to::TimerOutput, root, start_ns) + for (k, child) in to.inner_timers + node_data = _flamegraph_frame(child, start_ns) + node = addchild(root, node_data) + _to_flamegraph(child, node, start_ns) + end + return root +end