Skip to content

Instantly share code, notes, and snippets.

@mkborregaard
Last active March 1, 2022 12:29
Show Gist options
  • Save mkborregaard/81825c3d370bb4d8dbfe59c3b2ae4b33 to your computer and use it in GitHub Desktop.
Save mkborregaard/81825c3d370bb4d8dbfe59c3b2ae4b33 to your computer and use it in GitHub Desktop.
Create call trace graphs for julia calls. Based mostly on code and input by Tim Holy (https://github.com/cstjean/TraceCalls.jl/issues/61)
module TraceCalls2
using JuliaInterpreter, OrderedCollections, LightGraphs
const callchains = OrderedSet{Vector{Method}}()
const modules = Set{Module}()
function callchain(frame::JuliaInterpreter.Frame)
chain = Method[]
sc = JuliaInterpreter.scopeof(frame)
while sc isa Method
push!(chain, sc)
frame = frame.caller
frame === nothing && break
sc = JuliaInterpreter.scopeof(frame)
end
return chain
end
function log_far!(@nospecialize(recurse), frame, istoplevel::Bool=false)
chain = callchain(frame)
chain[1].module ∈ modules && push!(callchains, chain)
return JuliaInterpreter.finish_and_return!(recurse, frame, istoplevel)
end
function encode_vertices(callchains)
i = 0
vertices = Dict{Array{Method}, Int}()
for chain in callchains
for ind in length(chain):-1:1
vert = chain[ind:end]
haskey(vertices, vert) || (vertices[vert] = (i += 1))
end
end
vertices
end
function getnames(vertices)
names = Vector{String}(undef, length(vertices))
for (k,v) in vertices
names[v] = "$(k[1].module).$(k[1].name)"
end
names
end
function construct_graph(callchains)
vertices = encode_vertices(callchains)
g = SimpleDiGraph(length(vertices))
i = 0
for chain in callchains
for ind in length(chain)-1:-1:1
add_edge!(g, vertices[chain[ind+1:end]], vertices[chain[ind:end]])
end
end
g, vertices
end
function tracecall(mods::Tuple, call, arg)
empty!(callchains)
empty!(modules)
for m in mods
push!(modules, m)
end
frame = JuliaInterpreter.enter_call(call, arg);
log_far!(log_far!, frame, false)
construct_graph(callchains) #, callchains
end
export tracecall, getnames
end
@mkborregaard
Copy link
Author

I'm just in general having issues getting the information out of the Cassette context metadata. See this example

# this is - unedited - the tracer from the docs
using Cassette

Cassette.@context TraceCtx

function Cassette.overdub(ctx::TraceCtx, args...)
    subtrace = Any[]
    push!(ctx.metadata, args => subtrace)
    if Cassette.canrecurse(ctx, args...)
        newctx = Cassette.similarcontext(ctx, metadata = subtrace)
        return Cassette.recurse(newctx, args...)
    else
        return Cassette.fallback(ctx, args...)
    end
end

trace = Any[]

Running it on Plots.scatter

Cassette.overdub(TraceCtx(metadata = trace), scatter, 1:10)

gives

 (Plots.scatter, 1:10) => Any[
    (NamedTuple,) => Any[
        (Core.apply_type, Tuple) => Any[],
        (Core.apply_type, NamedTuple, (), Tuple{}) => Any[],
        (NamedTuple{(),Tuple{}}, ()) => Any[
            (Core.apply_type, NamedTuple, (), Tuple{}) => Any[]
        ]
     ],
     (pairs, NamedTuple()) => Any[
        (keys, NamedTuple()) => Any[],
        (Base.Iterators.Pairs, NamedTuple(), ()) => Any[
            (Core.apply_type, Base.Iterators.Pairs, Union{}, Union{}, Tuple{}, NamedTuple{(),Tuple{}}) => Any[],
            (fieldtype, Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, 1) => Any[],
            (convert, NamedTuple{(),Tuple{}}, NamedTuple()) => Any[],
            (fieldtype, Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, 2) => Any[]
        ]
      ],
      (tuple, Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}(), Plots.scatter) => Any[]
  ]

Almost no actual information on the call trace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment