AllocCheck.check_allocs
— Methodcheck_allocs(func, types; ignore_throw=true)
Compiles the given function and types to LLVM IR and checks for allocations.
Returns a vector of AllocationSite
, DynamicDispatch
, and AllocatingRuntimeCall
The Julia language/compiler does not guarantee that this result is stable across Julia invocations.
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.
Example
julia> function foo(x::Int, y::Int)
z = x + y
return z
end
foo (generic function with 1 method)
julia> allocs = check_allocs(foo, (Int, Int))
AllocCheck.AllocationSite[]
AllocCheck.classify_runtime_fn
— Methodclassify_runtime_fn(name)
A :dispatch function is responsible for a "dynamic dispatch" to an unknown Julia function.
An :alloc functions is used by codegen to lower allocations for mutable structs, arrays, and other Julia objects.
A :runtime function is any function used by the runtime which does not explicitly perform allocation, but which might allocate to get its job done (e.g. jl_subtype).
AllocCheck.compile_callable
— Methodcompile_callable(f, tt=Tuple{}; kwargs...)
Low-level interface to compile a function invocation for the provided function and tuple of argument types using the naive JuliaOJIT() pipeline.
The output of this function is automatically cached, so that new code will be generated automatically and checked for allocations whenever the function changes or when different types or keyword arguments are provided.
AllocCheck.find_allocs!
— MethodFind all static allocation sites in the provided LLVM IR.
This function modifies the LLVM module in-place, effectively trashing it.
AllocCheck.fixup_source_path
— Methodpath = fixup_source_path(path)
Return a normalized, absolute path for a source file path
.
AllocCheck.forward_args!
— MethodTakes a function definition and returns the expressions needed to forward the arguments to an inner function.
For example function foo(a, ::Int, c...; x, y=1, z...)
will
- modify the function to
gensym()
nameless arguments - return
(:a, gensym(), :(c...)), (:x, :y, :(z...)))
AllocCheck.rename_call!
— MethodResolve the callee of a call embedded in Julia-constructed LLVM IR and replace it with a new locally-declared function that has the resolved name as its identifier.
AllocCheck.resolve_allocations
— MethodReturns nothing
if the type could not be resolved statically.
AllocCheck.resolve_static_jl_value_t
— MethodReturns nothing
if the value could not be resolved statically.
AllocCheck.@check_allocs
— Macro@check_allocs ignore_throw=true (function def)
Wraps the provided function definition so that all calls to it will be automatically checked for allocations.
If the check fails, an AllocCheckFailure
exception is thrown containing the detailed failures, including the backtrace for each defect.
Note: All calls to the wrapped function are effectively a dynamic dispatch, which means they are type-unstable and may allocate memory at function entry. @check_allocs
only guarantees the absence of allocations after the function has started running.
Example
julia> @check_allocs multiply(x,y) = x*y
multiply (generic function with 1 method)
julia> multiply(1.5, 3.5) # no allocations for Float64
5.25
julia> multiply(rand(3,3), rand(3,3)) # matmul needs to allocate the result
ERROR: @check_allocs function contains 1 allocations.
Stacktrace:
[1] macro expansion
@ ~/repos/AllocCheck/src/macro.jl:134 [inlined]
[2] multiply(x::Matrix{Float64}, y::Matrix{Float64})
@ Main ./REPL[2]:133
[3] top-level scope
@ REPL[5]:1