Skip to content

Fix allocation tests on Julia >= 1.13 - #536

Merged
devmotion merged 1 commit into
masterfrom
dmw/fix_allocated
Aug 5, 2026
Merged

Fix allocation tests on Julia >= 1.13#536
devmotion merged 1 commit into
masterfrom
dmw/fix_allocated

Conversation

@devmotion

Copy link
Copy Markdown
Member

The GPU compatibility tests in test/gamma_inc.jl fail on Julia 1.13 (12 failures, 4 code paths x 3 float types), e.g.

gamma_inc allocations: Test Failed at test/gamma_inc.jl:301
  Expression: iszero(((FT->@allocated gamma_inc(FT(1.7), FT(2.5))))(FT))
   Evaluated: iszero(16)

OpenLibm is a Libdl.LazyLibrary on Julia >= 1.13, so a ccall into it can no longer be bound at compile time. Its target is resolved on first use and cached per callsite, and resolving one allocates 16 bytes.

Each test measured a single call of a newly created closure, and since the arguments are literals constant propagation inlines the ccall into that closure - code_typed(FT -> gamma_inc(FT(1.7), FT(2.5))) contains

Expr(:foreigncall, :((:tgamma, SpecialFunctions.libopenlibm)), ...)

So every measurement included the 16 bytes of resolving a fresh callsite. Only the paths that reach a ccall are affected: gamma(a) in rgammax for 1 <= a <= 20, and erfc for a == 0.5. The other paths take the stirling_error (a > 20) or rgamma1pm1 (a < 1) branches and are pure Julia, which is why they pass.

Warming up with a separate call does not help, because the lazy binding is cached per callsite and not per callee. So this now calls each closure twice and only asserts on the second measurement.

test/gamma_inc.jl passes on 1.10.11, 1.12.6 and 1.14.0-DEV (1.13.0-rc1 was unavailable locally, nightly reproduces the failure identically). A negative control run_twice(FT -> @allocated(sum(zeros(FT, 100))), FT) still reports 912/928, 480/512 and 256/272 bytes, so the tests still detect real allocations.

Note this is unrelated to #535 - the same failures are on the master push run 27935023667 and on #534.

🤖 Generated with Claude Code

OpenLibm is a `Libdl.LazyLibrary` on Julia >= 1.13. Its `ccall` targets are
resolved on first use and cached per callsite, and resolving one allocates
16 bytes.

Each test measured a single call of a newly created closure, into which the
`ccall` is inlined by constant propagation. So every measurement included the
16 bytes of resolving a fresh callsite. Affected are the paths that call
`gamma` (`1 <= a <= 20`) or `erfc` (`a == 0.5`).

Now each closure is called twice and only the second measurement is used.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.28%. Comparing base (02a51af) to head (9c25072).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #536   +/-   ##
=======================================
  Coverage   94.28%   94.28%           
=======================================
  Files          14       14           
  Lines        3026     3026           
=======================================
  Hits         2853     2853           
  Misses        173      173           
Flag Coverage Δ
unittests 94.28% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@devmotion
devmotion merged commit e477922 into master Aug 5, 2026
15 checks passed
@devmotion
devmotion deleted the dmw/fix_allocated branch August 5, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant