From 32038ef9a0872a0b0d6be0d8dc3c8923ca7aee59 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Fri, 17 Nov 2023 11:47:58 -0500 Subject: [PATCH] Update README based on new docs --- README.md | 79 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 50943b1..57aea8f 100644 --- a/README.md +++ b/README.md @@ -4,26 +4,81 @@ [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://juliacomputing.github.io/AllocCheck.jl/dev/) -AllocCheck.jl is a Julia package that statically checks if a function call may allocate, analyzing the generated LLVM IR of it and it's callees using LLVM.jl and GPUCompiler.jl +[AllocCheck.jl](https://github.com/JuliaComputing/AllocCheck.jl) is a Julia package that statically checks if a function call may allocate, analyzing the generated LLVM IR of it and it's callees using LLVM.jl and GPUCompiler.jl -#### Examples +AllocCheck operates on _functions_, trying to statically determine wether or not a function _may_ allocate memory, and if so, _where_ that allocation appears. This is different from measuring allocations using, e.g., `@time` or `@allocated`, which measures the allocations that _did_ happen during the execution of a function. +## Getting started + +The primary entry point to check allocations is the macro [`@check_allocs`](@ref) which is used to annotate a function definition that you'd like to enforce allocation checks for: ```julia -julia> mymod(x) = mod(x, 2.5) +julia> using AllocCheck + +julia> @check_allocs mymod(x) = mod(x, 2.5) +mymod (generic function with 1 method) + +julia> mymod(1.5) # call automatically checked for allocations +1.5 +``` +This call happened without error, indicating that the function was proven to not allocate any memory after it starts 🎉 + -julia> length(check_allocs(mymod, (Float64,))) -0 +When used on a function that may allocate memory +```julia +julia> @check_allocs linsolve(a, b) = a \ b +linsolve (generic function with 1 method) + +julia> linsolve(rand(10,10), rand(10)) +ERROR: @check_alloc function contains 55 allocations. +``` +the function call raises an `AllocCheckFailure`. + +The `errors` field allows us to inspect the individual errors to get some useful information. For example: + +```julia +julia> try linsolve(rand(10,10), rand(10)) catch err err.allocs[1] end +Allocation of Vector{Float64} in ./boot.jl:475 + | Array{T,1}(::UndefInitializer, m::Int) where {T} = -julia> linsolve(a, b) = a \ b +Stacktrace: + [1] Array + @ ./boot.jl:475 [inlined] + [2] Array + @ ./boot.jl:484 [inlined] + [3] similar + @ ./array.jl:418 [inlined] + [4] \ + @ ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/triangular.jl:1483 [inlined] + [5] \(A::Matrix{Float64}, B::Vector{Float64}) + @ LinearAlgebra ~/.julia/juliaup/julia-1.10.0-rc1+0.x64.linux.gnu/share/julia/stdlib/v1.10/LinearAlgebra/src/generic.jl:1118 + [6] var"##linsolve#225"(a::Matrix{Float64}, b::Vector{Float64}) + @ Main ./REPL[2]:1 +``` + +we see what type of object was allocated, and where in the code the allocation appeared. + + +### Functions that throw exceptions + +Some functions that we do not expect may allocate memory, like `sin`, actually may: +```julia +julia> @allocated try sin(Inf) catch end +48 +``` + +The reason for this is that `sin` needs to allocate if it **throws an error**. + +By default, `@check_allocs` ignores all such allocations and assumes that no exceptions are thrown. If you care about detecting these allocations anyway, you can use `ignore_throw=false`: +```julia +julia> @check_allocs mysin1(x) = sin(x) -julia> length(check_allocs(linsolve, (Matrix{Float64}, Vector{Float64}))) -175 +julia> @check_allocs ignore_throw=false mysin2(x) = sin(x) -julia> length(check_allocs(sin, (Float64,))) -2 +julia> mysin1(1.5) +0.9974949866040544 -julia> length(check_allocs(sin, (Float64,); ignore_throw=true)) # ignore allocations that only happen when throwing errors -0 +julia> mysin2(1.5) +ERROR: @check_alloc function contains 2 allocations. ``` #### Limitations