[ANN] ArenaPirate.jl: proof-of-concept arena allocator (not in the registry)

repo: https://github.com/artemsolod/ArenaPirate.jl

This package redefines Memory{T}(::UndefInitializer, m::Int64) (hence “pirate” in the name) and provides an @arena macro for marking sections of code to be eligible for arena allocation. Large enough allocations of Memory{T} with isbitstype(T) get arena allocated provided arena has sufficient remaining capacity. Standard julia allocation is used as fallback. I’ve been playing with this for a couple of weeks and found it quite useful in GC-bound workloads.

Here is a comparison of timings for calling f(x) = median(x) vs f_arena(x) = @arena f(x) on a 10 mln element vector and repeated calls (32 runs: single and multithreaded on 8 threads – see examples/medians.jl). Note that the Statistics.median function is allocating and is not @arena-aware.

____ Built-in allocator benchmarks:
  0.154144 seconds (18 allocations: 78.262 MiB, 16.38% gc time) # single call
  4.363108 seconds (298 allocations: 2.446 GiB, 6.95% gc time) # 32 repeated calls
  1.384049 seconds (340 allocations: 2.446 GiB, 25.96% gc time) # 32 calls using Threads.@threads
____ Arena benchmarks:
  0.072805 seconds (55 allocations: 2.000 KiB) # single call (@arena)
  2.346896 seconds (747 allocations: 17.250 KiB) # 32 repeated calls (@arena)
  0.413609 seconds (810 allocations: 21.562 KiB) # 32 calls using Threads.@threads (@arena)

I would like to hear your feedback: ideas for performance improvements, bug reports, interface improvements. And especially how it can be extended, i.e. what are all arena-allocatable things?

7 Likes