JuliaLang / AllocCheck.jl

AllocCheck
Other
209 stars 8 forks source link

Support @check_allocs at callsites #54

Open tecosaur opened 8 months ago

tecosaur commented 8 months ago

This is an alternative to #46 that resolves #45 by creating an anonymous function for a given call, allowing @check_allocs to be applied to callsites.

julia> @check_allocs 1 + 1
2

is equivalent to

julia> @check_allocs f(a, b) = a + b
f (generic function with 1 method)

julia> f(1, 1)
2

This mechanism is different to #46, as that is based on calling check_allocs with the argument types.

fredrikekre commented 8 months ago

What is the advantage of this version? I find this one a bit confusing -- why is the extra anonymous function layer needed for? No other similar macro (e.g. @code_typed, @code_llvm, ...) do it like this but instead do what #46 does.

tecosaur commented 8 months ago

Doing it via an anonymous function is done in response to 875e3bab86e9d22e7cc8995d7baf6d45c7474c9b:

If you rely on allocation-free code for safety/correctness, it is not sufficient to verify check_allocs in test code and expect that the corresponding call in production will not allocate at runtime.

For this case, you must use @check_allocs instead.

Otherwise I'd just use check_allocs as #46 does, and the anonymous function layer wouldn't be needed.

fredrikekre commented 8 months ago

Okay, I missed that. Looking at the expanded code, it seems at least possible to use the called function directly (e.g. use + instead of the fn_alias in your example). Perhaps it doesn't really matter though. Is any of this visible in e.g. a stacktrace?

Tangentially, would it be possible to add this type of indirection to check_alloc to make that stable? Perhaps that uses a completely different machinery though, I don't know.

tecosaur commented 8 months ago

It seems like the stack trace is much less helpful, but it's like that of a @check_alloc function.

julia> @check_allocs rand(2,2) * rand(2, 2)
ERROR: @check_alloc function encountered 1 errors (1 allocations / 0 dynamic dispatches).
Stacktrace:
 [1] macro expansion
   @ ~/.julia/dev/AllocCheck/src/macro.jl:159 [inlined]
 [2] (::var"#8#10"{var"#7#9"})(arg#231::Matrix{Float64}, arg#232::Matrix{Float64})
   @ Main ./REPL[3]:158
 [3] macro expansion
   @ ~/.julia/dev/AllocCheck/src/macro.jl:188 [inlined]
 [4] top-level scope
   @ REPL[3]:1

julia> @check_allocs mymul(a, b) = a * b
mymul (generic function with 1 method)

julia> mymul(rand(2, 2), rand(2, 2))
ERROR: @check_alloc function encountered 1 errors (1 allocations / 0 dynamic dispatches).
Stacktrace:
 [1] macro expansion
   @ ~/.julia/dev/AllocCheck/src/macro.jl:159 [inlined]
 [2] mymul(a::Matrix{Float64}, b::Matrix{Float64})
   @ Main ./REPL[6]:158
 [3] top-level scope
   @ REPL[7]:1