JuliaLang / AllocCheck.jl

AllocCheck
Other
221 stars 8 forks source link

`multiple call sites` obscures allocation origin #81

Open danielwe opened 2 months ago

danielwe commented 2 months ago

Allocations reported by AllocCheck often have stack traces that only contain stack frames from Julia core/Base (array/dict/set constructors, locks, gc code, etc.) before terminating with multiple call sites. This is unhelpful for debugging and makes it hard to filter out allocations that a developer might consider benign.

Could these cases instead be split into multiple allocations, one for each origin, each with a stack trace going back to the top-level call?

As an example, see the code below, where a simple log statement results in 95 reported allocations, and an attempt to filter out the logging-related ones only removes 30 of them.

julia> using AllocCheck

julia> f() = @warn "Watch out!"
f (generic function with 1 method)

julia> allocs = check_allocs(f, ());

julia> length(allocs)
95

julia> allocs_not_from_loggingJL = filter(allocs) do alloc
           for frame in alloc.backtrace
               (frame.file == Symbol("./logging.jl")) && return false
           end
           return true
       end;

julia> length(allocs_not_from_loggingJL)
65

julia> allocs_not_from_loggingJL[1]  # example of stack trace terminating with "multiple call sites"
Allocation of String in ./strings/string.jl:90
  | @eval _string_n(n::Integer) = $(Expr(:foreigncall, QuoteNode(:jl_alloc_string), Ref{String}, Expr(:call, Expr(:core, :svec), :Csize_t), 1, QuoteNode((:ccall,0xe)), :(convert(Csize_t, n))))

Stacktrace:
 [1] _string_n
   @ ./strings/string.jl:90 [inlined]
 [2] StringVector
   @ ./iobuffer.jl:32 [inlined]
 [3] _similar_data
   @ ./iobuffer.jl:142 [inlined]
 [4] ensureroom
   @ ./iobuffer.jl:337 [inlined]
 [5] unsafe_write(to::IOBuffer, p::Ptr{UInt8}, nb::UInt64)
   @ Base ./iobuffer.jl:458
 [6] multiple call sites
   @ unknown:0
topolarity commented 3 weeks ago

It may not be necessary to show all of the paths at once - We should probably try following at least one of the paths back to the entry-point