using Calculus, TraceCalls @traceable f(x) = sin(x) + sqrt(x) trace_derivative = @trace Calculus second_derivative(f, 1.0) trace_derivative[1][1] # get the first call of the first call. trace_derivative[1][1].args[2] # get its second argument @trace Calculus second_derivative(f, 0.0) greenred(map(:@allocated, trace_derivative)) # compute how many bytes were allocated in each function call using LightGraphs, TraceCalls graph = Graph(3) # build an undirected graph with three connected vertices add_edge!(graph, 1, 2); add_edge!(graph, 2, 3) trace_walk = @trace LightGraphs randomwalk(graph, 2, 5) trace_walk[1][3] # can also be written trace_walk[1,3] trace_walk[1][3][:v] # get the second argument by name. To get it by position, use trace_walk[1][3].args[2] trace_walk[1,3]() # call `LightGraphs.out_neighbors(...)` pruned_trace = prune(trace_walk, 2, # maximum depth 4) # maximum length of each trace (eg. if foo() calls bar() 100 times, keep the first 4 times) @trace LightGraphs pruned_trace[1, 2]() # don't forget the (); it triggers the computation for that call TraceCalls.show_val(io::IO, ::MIME"text/html", v::Vector{Int}) = write(io, string("[", join([x==2 ? "2" : x for x in v], ","), "]")) TraceCalls.show_val(io::IO, ::MIME"text/html", ::Graph) = # could also be done with `@show_val_only_type Graph` write(io, "AnyOldGraph") trace_walk # Get rid of the `fadj` calls filter(trace->trace.func != LightGraphs.SimpleGraphs.fadj, trace_walk) # Focus on the callers and callees of `LightGraphs.out_neighbors(AnyOldGraph, 2)` filter_lineage(trace -> trace.func==out_neighbors && trace[:v]==2, trace_walk; highlight=true) # Take the second argument of every call to LightGraphs.out_neighbors map(trace->trace.func == LightGraphs.out_neighbors ? trace.args[2] : nothing, filter(trace->trace.func == LightGraphs.out_neighbors, trace_walk)) @traceable push5!(vec::Vector) = push!(vec, 5) @traceable function many_5s(n) vec = Int[] for i in 1:n push5!(vec) end return vec end @trace many_5s(3) TraceCalls.store(x::Vector) = copy(x) # the default is `store(x) = x` @trace many_5s(3) tr = @trace many_5s(3) filter(!is_mutating, tr) # filter out every function that ends with a ! (see https://docs.julialang.org/en/stable/manual/style-guide/#Append-!-to-names-of-functions-that-modify-their-arguments-1) using Optim, TraceCalls @traceable logplus10(x) = log(x[1]+10) TraceCalls.store(v::Vector) = copy(v) # Minimize the function x -> log(x[1]+10) starting at x = 0 strace = @stacktrace (Optim, Calculus) optimize(logplus10, [0.0], BFGS()) strace[1,1,1,1] # could also use `strace[bottom-2]`, or `strace[top+4]` --- bottom/top are special values like `end` linesearch_trace = @trace (Optim, Calculus) strace[1,1,1,1]() filter(tr->tr.func==Calculus.finite_difference!, linesearch_trace) ?compare_past_trace using TraceCalls @traceable function hypothenuse_length(a, b) a2 = a * a b2 = b * b trace_log(a2=a2, b2=FontColor(:blue, b2)) # FontColor is also useful in Base.show_val or Base.map return sqrt(a2+b2) end @trace hypothenuse_length(3, 4) ## Profile the PyCall code for accessing Python's `math.pi` using PyCall, TraceCalls math = pyimport(:math) trace_pycall = @trace PyCall math[:pi]; using BenchmarkTools: @belapsed m_trace = measure(:@belapsed, trace_pycall; normalize=true, threshold=0.005) # only show/explore calls that take >0.5% of total runtime redgreen(map(is_inferred, trace_pycall)) # ignore the top-most call - it will always be `false` using BenchmarkTools # necessary for trace_benchmark bench = trace_benchmark(trace_pycall) bench_new = run(bench); judge(bench_new, bench; sort=true) @compilation_times PyCall math[:pi]