mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
fa762a11ec
The default harness loads shared helpers and smoke checks before topic includes, registers poroelastic and thermo_poroelastic, drops the retired IO topic, and removes the orphaned ASCII fixture. - Add zero_alloc_helpers.jl, test_api_contract.jl, test_pkg_hygiene.jl, and test_inference_smoke.jl included once from runtests.jl - Extend TOPICS; remove io; clarify test_args accepts topic names only - Delete test/testdata/cantilever_beam.msh
77 lines
2.3 KiB
Julia
77 lines
2.3 KiB
Julia
# SPDX-FileCopyrightText: 2015-2026 Jukka Aho
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
Shared helpers for zero-allocation regression tests.
|
|
|
|
`@allocated` can miss some paths or mask one-shot caches; scanning optimized
|
|
LLVM IR for Julia GC entrypoints catches heap traffic inside compiled code.
|
|
Names differ across Julia versions (`jl_*` vs `ijl_*`, `julia.gc_alloc`, …);
|
|
`count_llvm_gc_alloc_sites` tracks the union used in practice.
|
|
|
|
Note: `Pkg.test` runs Julia with `--check-bounds=yes` (`JLOptions().check_bounds == 1`).
|
|
Some small indexed kernels then show GC-related `call` lines in optimized IR even when
|
|
`@allocated` is zero. Prefer `@allocated` plus LLVM scans for large stable kernels
|
|
(`assemble!`, `apply_K!`, …); for tight index loops, gate IR scans or accept that CI
|
|
skips the IR assertion.
|
|
"""
|
|
|
|
using InteractiveUtils: code_llvm
|
|
|
|
# Every needle must appear only inside a `call` line in IR we care about.
|
|
const _LLVM_GC_ALLOC_MARKERS = (
|
|
"julia.gc_alloc",
|
|
"jl_gc_pool_alloc",
|
|
"jl_gc_big_alloc",
|
|
"jl_gc_alloc_typed",
|
|
"jl_gc_small_alloc",
|
|
"ijl_gc_pool_alloc",
|
|
"ijl_gc_big_alloc",
|
|
"ijl_gc_alloc_typed",
|
|
"ijl_gc_small_alloc",
|
|
)
|
|
|
|
"""
|
|
count_llvm_gc_alloc_sites(ir::AbstractString) -> Int
|
|
|
|
Count LLVM `call` lines that invoke a Julia GC allocation runtime function.
|
|
Used on the output of `llvm_ir` / `InteractiveUtils.code_llvm`.
|
|
"""
|
|
function count_llvm_gc_alloc_sites(ir::AbstractString)
|
|
n = 0
|
|
for line in eachsplit(ir, '\n')
|
|
occursin("call ", line) || continue
|
|
for needle in _LLVM_GC_ALLOC_MARKERS
|
|
if occursin(needle, line)
|
|
n += 1
|
|
break
|
|
end
|
|
end
|
|
end
|
|
return n
|
|
end
|
|
|
|
"""
|
|
llvm_ir(f, ::Type{<:Tuple}; optimize::Bool=true) -> String
|
|
|
|
Optimized LLVM IR for `f` at argument tuple type `T`, as a single string.
|
|
"""
|
|
function llvm_ir(@nospecialize(f), @nospecialize(T::Type{<:Tuple}); optimize::Bool = true)
|
|
io = IOBuffer()
|
|
code_llvm(io, f, T; optimize = optimize)
|
|
return String(take!(io))
|
|
end
|
|
|
|
"""
|
|
llvm_gc_alloc_site_count(f, ::Type{<:Tuple}; optimize::Bool=true) -> Int
|
|
|
|
Convenience: `count_llvm_gc_alloc_sites` ∘ `llvm_ir`.
|
|
"""
|
|
function llvm_gc_alloc_site_count(
|
|
@nospecialize(f),
|
|
@nospecialize(T::Type{<:Tuple});
|
|
optimize::Bool = true,
|
|
)
|
|
return count_llvm_gc_alloc_sites(llvm_ir(f, T; optimize = optimize))
|
|
end
|