Skip to content

Run-time pass plans for juliac --trim (type depends on T and N only) - #25

Closed
tknopp wants to merge 5 commits into
mainfrom
trim-runtime-passes
Closed

tknopp wants to merge 5 commits into
mainfrom
trim-runtime-passes

Conversation

@tknopp

@tknopp tknopp commented Nov 10, 2026

Copy link
Copy Markdown
Member

Based on #24 (removal of the pruning); the diff here is the run-time pass plans only.

NFFT.jl stores its passes in containers of one plan type. The plans of plan_pass, plan_r2c_pass and
plan_c2r_pass have a type that depends on the length (the kernel types of the length), so such a
container cannot be compiled with juliac --trim. This pull request adds run-time versions whose type
depends on the element type and the number of dimensions only:

  • plan_pass_runtime(v, d), plan_r2c_pass_runtime(v, d), plan_c2r_pass_runtime(v, d): the same
    transforms as the specialised functions, with run-time kernels only (RChain; Bluestein and composite over
    RChain; four-step over RChain). The plan type is PassPlan{T,N,RPassKern{T}} resp.
    RealPassPlan{T,N,RealLine{T,RKern{T}}} for every length.
  • The specialised functions are unchanged in their kernels and their results.
  • The line offsets of a pass are built by doubling, which makes planning faster (see below).
  • The trimmable plans are described in the how-to on compiling ahead of time, and the decision is in the
    design decisions page.

Why separate functions and not a keyword

The first version had a keyword runtime = true. The trim verifier checks the code of both branches, and the
specialised branch has calls whose types depend on the length, so the verifier refused it. A constant
keyword is not folded before verification, which Base.@constprop did not change.

Checks

  • Trim probe (juliac --trim=safe, the same invocation as libfftl/build.sh): a library with a vector of
    plan_pass_runtime plans and a vector of plan_r2c_pass_runtime plans, both applied with mul!. The
    verifier reports no errors. Called from C, both entry points agree with the direct DFT to 4·10⁻¹⁴ (n = 64
    and n = 100, several columns).
  • Quick test selection (AMD EPYC 7702, two Julia threads): 2739 pass, 10 broken, 0 fail. New test set "run-time pass plans" (plan types for
    several lengths, agreement with the specialised plans for smooth, Bluestein, composite and four-step lengths,
    strided views in dimensions 2 and 3, and a direct DFT check).
  • Planning (M1, 64 × 64 × 64 views, one thread): the specialised plan takes 4.7 µs for dimension 1 and
    2.8 µs for dimension 2 on main, and 1.8 µs and 0.9 µs with this change. Applying a plan is unchanged within
    the noise of the measurement.

🤖 Generated with Claude Code

tknopp and others added 5 commits November 10, 2026 12:04
plan_pass(...; runtime = true) and plan_r2c_pass / plan_c2r_pass with runtime = true build their
kernels from run-time kernels only (RChain, Bluestein and composite over RChain, four-step over
RChain). Their plan type is PassPlan{T,N,RPassKern{T}} resp. RealPassPlan{T,N,RealLine{T,RKern{T}}},
the same for every length, so a container of such plans can be compiled ahead of time
(juliac --trim). The default plans are unchanged.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
plan_pass_runtime, plan_r2c_pass_runtime and plan_c2r_pass_runtime build the plans from run-time
kernels only. The length-specialised plan_pass, plan_r2c_pass and plan_c2r_pass are unchanged in
their kernels. A keyword could not do this: juliac --trim verifies the code of both branches of a
run-time `runtime` argument, and the specialised branch has unresolved calls.

The layout of the lines no longer uses tuples of run-time length (line_offsets takes a vector),
and the plan type is given explicitly to the constructor.

A trimmed library (juliac --trim=safe) holding plan_pass_runtime and plan_r2c_pass_runtime plans
in containers passes the verifier and computes results that agree with the direct DFT to 3e-14.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
The offsets of the lines are built one dimension at a time (first index fastest), so that
the cost of planning a pass is linear in the number of lines without divisions. Plan creation
on 64 × 64 × 64 views is 1.8 µs (d = 1) and 0.9 µs (d = 2) on the M1, against 4.7 µs and 2.8 µs.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@tknopp
tknopp changed the base branch from cleanup-pruning to main November 10, 2026 13:18
@tknopp

tknopp commented Nov 10, 2026

Copy link
Copy Markdown
Member Author

Replaced by a new draft pull request: the branch was rebased onto main after #24 was merged (merge commit), and the history of the old branch was not rewritten. The content is the same plus the reference page for the new functions (fixes the failing documentation build).

@tknopp tknopp closed this Nov 10, 2026
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