Accessing profiling data programmatically

I did not find an example of querying Julia profiling data for e.g. the number of samples that hit a given function. I want to post what I’m using in case it’s useful to anyone searching:

using Profile
using FlameGraphs
using FlameGraphs.AbstractTrees: PreOrderDFS

# ----------------
function foo(n)
    acc = 0.0
    for i = 1:n
        if i % 2 == 0
            acc += bar1(i)
        else
            acc += bar2(i)
        end
    end
    return acc
end

baz(x) = sqrt(sin((cos(sin(tan(cos(sin(x))))))^2))

function bar1(n)
    acc = 0.0
    for i=1:n
        acc += baz(i)
    end
    return acc
end

function bar2(n)
    acc = 0.0
    for i=1:(2n)
        acc += baz(i)
    end
    return acc
end
# ----------------

function groupby_sf(fg)
    d = Dict()
    for node in PreOrderDFS(fg)
        push!(get!(d, node.data.sf, []), node)
    end
    return d
end

function find_sf_keys_by_func(gsf, func::Symbol)
    filter(sf -> func == sf.func, collect(keys(gsf)))
end

function time_in_function(gsf, f::Symbol)
    ks = find_sf_keys_by_func(gsf, f)
    ns = reduce(vcat, getindex.(Ref(gsf), ks))
    spans = map(n -> n.data.span, ns)
    return sum(length.(spans))
end

profile_fill_ratio() = Profile.len_data() / Profile.maxlen_data()

Profile.init(;delay=0.001)
@profile foo(5000)
@show profile_fill_ratio()
# VSCodeServer.view_profile() # use visualization in VS Code
fg = FlameGraphs.flamegraph() # retreieves current profiling data

gsf = groupby_sf(fg)
@show time_in_function(gsf, :foo)
@show time_in_function(gsf, :bar1)
@show time_in_function(gsf, :bar2)
@show time_in_function(gsf, :baz)
profile_fill_ratio() = 0.0086456
time_in_function(gsf, :foo) = 1551
time_in_function(gsf, :bar1) = 539
time_in_function(gsf, :bar2) = 1010
time_in_function(gsf, :baz) = 1532
2 Likes