# \[ANN\] AllocCheck.jl: Static code analysis to prove allocation-free behavior

**URL:** <https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414>\
**Category:** Package Announcements\
**Tags:** package, control, memory-allocation, garbage-collection, realtime\
**Created:** [November 18, 2023, 6:08pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414 "2023-11-18T18:08:29Z")\
**Posts on this page:** 8\
**Page:** 2

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 25, 2023, 7:16pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/21 "2023-11-25T19:16:38Z")

</div>

The reason it doesn’t work is that the alias analysis isn’t happening in LLVM, it is happening at the julia level, so `unsafe_assume_condition` is operating too late.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 25, 2023, 7:36pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/22 "2023-11-25T19:36:45Z")

</div>

Looks like the easiest way to make the compiler do this, is to just assert that there’s no aliasing by adding an error path.

The compiler is pretty good at using that information.

```julia-repl
function f_noalias!(x, y)
    Base.mightalias(x, y) && throw("No aliasing allowed!")
    x .= x .+ y
end

```

```julia
julia> check_allocs(f_noalias!, (Vector{Int}, Vector{Int}))
Any[]

```

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [November 25, 2023, 8:17pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/23 "2023-11-25T20:17:15Z")

</div>

Perhaps a newbie question but in which cases would the behavior / results of AllocCheck.jl differ from a good old `@ballocated` or `BenchmarkTools.@ballocated`? Is one always more precise than the other, or does it depend?

---

<div class="post-metadata">

**Author:** ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)\
**Post date:** [November 25, 2023, 8:19pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/24 "2023-11-25T20:19:43Z")

</div>

AllocCheck gives stacktraces to pointing to any allocations that the compiler thinks _could_ happen based on the types of the inputs (not the values). `@allocated` and `@ballocated` are runtime metrics, where the code actually executes and the change in gc metrics (tracked in the Julia runtime) is inspected to see how many allocations actually took place. So an easy way to make them differ is to allocate conditionally on a runtime value, and then take another path. (`if x == 1; arr = ones(n); end` or whatever).

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 25, 2023, 9:07pm UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/25 "2023-11-25T21:07:08Z")

</div>

> [@Mason](#):
>
> The reason it doesn’t work

Actually, it does work, but it depends on the Julia version. On Julia v1.10.0-rc1, `check_allocs` reports `Any[]` for both your `f_noalias!`, the one that throws, and mine, the one that uses UnsafeAssume.jl!

But on v1.11 nightly, two allocations are reported for both versions of the function!

Github issue: [Array allocation elimination regression · Issue #52305 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/52305)

---

<div class="post-metadata">

**Author:** ![aerappa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aerappa/32/212281_2.png) [@aerappa](https://discourse.julialang.org/u/aerappa)\
**Post date:** [December 6, 2023, 10:15am UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/26 "2023-12-06T10:15:51Z")

</div>

Speaking of which, I am considering making a PR so that `@check_allocs` plays nice with `Bumper.jl`’s `@alloc`. The following example demonstrates this:

```julia
using AllocCheck
using BenchmarkTools
using Bumper

function test_allocs_bench()
  @no_escape begin
    x = @alloc(Float64, 10)
    nothing
  end
end

@check_allocs test_allocs() = test_allocs_bench()

let
  bench = @benchmark test_allocs_bench()
  @show maximum(bench).memory # = 0
  try
    test_allocs()
  catch err
    err.errors[1] # Allocation of Vector{Any} in ./boot.jl:477
  end
end

```

Not sure how much work this would entail though…

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [December 6, 2023, 10:35am UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/27 "2023-12-06T10:35:58Z")

</div>

The Bumper.jl function you showed _can_ allocate though, because the first time you call `default_buffer()` in a given task, the task local buffer is allocated. Furthermore, `default_buffer()` itself returns a `SlabBuffer` which can allocate when it grows, so you’d need to use `AllocBuffer`

If you want something that can’t possibly allocate, you’d need to do it more like

```julia
julia> using AllocCheck, Bumper

julia> function test_allocs_bench(buf)
           @no_escape buf begin
               x = @alloc(Float64, 10)
               nothing
           end
       end
test_allocs_bench (generic function with 1 method)

julia> check_allocs(test_allocs_bench, Tuple{AllocBuffer{Vector{UInt8}}})
Any[]

```

---

<div class="post-metadata">

**Author:** ![aerappa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aerappa/32/212281_2.png) [@aerappa](https://discourse.julialang.org/u/aerappa)\
**Post date:** [December 6, 2023, 10:56am UTC](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414/28 "2023-12-06T10:56:02Z")

</div>

Ah, ok thanks for the clarification!

[Previous page](https://discourse.julialang.org/t/ann-alloccheck-jl-static-code-analysis-to-prove-allocation-free-behavior/106414.md?page=1)
