Uh oh!
There was an error while loading. Please reload this page.
PROPOSAL (do not merge): what core/ means, and a naming scheme - #148
Closed
balbasty wants to merge 6 commits into
Closed
PROPOSAL (do not merge): what core/ means, and a naming scheme#148balbasty wants to merge 6 commits into
balbasty wants to merge 6 commits into
Conversation
Answers the two questions the owner asked together -- what moves from impl/kernels/ to core/, and how namespaces, kernels and internal helpers should be named -- plus the thread-count API question that follows from them. The recommended definition, which decides every borderline file: core/ holds every header that more than one layer depends on and that is not itself the computation of a named fastfields operation -- device- specialised or not. impl/kernels/ keeps only the per-element maths of a named operation. That admits atomic.h (device-specialised, but not an operation) and the parallel/threadpool group, and it excludes splinc.h (it IS the operation exported as spline_coeff). Ten files move, 4,262 lines; the closure is clean, so core/ never acquires a dependency on impl/kernels/. Two premises in the brief turned out not to hold, and both are recorded with the evidence: * core/ was said to be barred from opening the device namespace. core/autocast.h already opens FF_NAMESPACE_BEGIN(FF_DEVICE), and core/cuda_switch.h exists to branch on __CUDACC__. The real constraint is narrower: a core/ header must compile under both compilers and mean the right thing in each. * core/dispatch.h says canUse32BitIndexMath comes from core/autocast.h. It is defined in impl/kernels/utils.h, which is why 17 files in src/ include the kernels layer directly. The dependency inversion this proposal repairs already exists. Findings that are independent of any decision here, worth acting on separately: impl/cpu/tetrahedron.h does not compile and is referenced by nothing; impl/kernels/vector/ (2,389 lines) is used only by a scratch target and duplicates the point hierarchy in distance/mesh_utils.h; the CUDA backend launches all 39 kernels at the architectural maximum of 1024 threads per block and checks for no launch error anywhere, so a cudaErrorLaunchOutOfResources would be discarded silently. tools/move-core-headers.py carries the move with a self-verifying --check, following the pattern of rename-macros.py and dedup-dispatch-helpers.py. It does not hard-code an include delimiter -- it measures the tree's dominant one -- so it survives the in-flight <fastfields/...> sweep by being re-run rather than hand-merged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AjQcY78NgbagPSbPJRr6Z
This commit exists so the proposal's cost figures are measurements rather than estimates. It is the output of `tools/move-core-headers.py` run on 85fdac7, nothing else. Drop it and the design in the previous commit still stands. 10 headers moved, 4,262 lines 82 files rewritten, 150 insertions / 150 deletions `--check` clean and idempotent afterwards, no dependency leak Measured gate on this tree (clang++, legs default,lib): distance 2352/0 distance_mesh 4622/0 distance_spline 704/0 posdef 4012/0 pushpull 308/0 pushpull_backward 6381/0 reg_field 19250/0 reg_flow 16347/0 reg_op 186/0 resize 630/0 restrict 65/0 solve_field 452/0 splinc 4577/0 lib_device_check 5/0 lib_splinc_bound 9/0 Row-for-row identical to tools/test-baseline.expected: 13 cpu-lib suites, 59,886 checks, 0 failures, plus the hub's 2 suites / 14 checks. Two of the six recorded legs were run, so `--check` reports NOT COMPARABLE on leg coverage rather than on any differing row; the remaining four legs vary only the bound/spline compile policy, which this change does not touch. One thing the move breaks that is easy to miss, and is fixed here: tools/test-baseline.sh probes for impl/kernels/bounds.h to validate tree layout, so the gate tool dies before running a single test, with a message that reads like a broken checkout. tools/consolidate.sh and the six-repo probe in the same script reference the same paths and are deliberately NOT updated -- they describe the frozen pre-consolidation layout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AjQcY78NgbagPSbPJRr6Z
… move" This reverts commit b67b52e.
#146 (angle-bracket includes) and #143 (FF_INDEX32) landed on main while this proposal was being written, which turned the script's central claim from an assertion into something demonstrable. The rebase was done the way the docstring prescribes -- revert, merge main, re-run unedited -- and the same script emitted <fastfields/...> on the new base with no edit and no hand-merging. Both runs are now recorded in Appendix A. Also corrects the vox migration cost: 26 FF_NAMESPACE_BEGIN(<module>) sites across 25 files, not 28 across 26, with the per-module breakdown. The earlier figure came from a scan that counted non-module namespaces (bound, spline, meta, internal, _splinc) alongside the module ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AjQcY78NgbagPSbPJRr6Z
… on the new base Regenerated by re-running `tools/move-core-headers.py` unedited on de288a9 (main after #146 and #143), which is the whole point: the earlier prototype commit was reverted rather than hand-merged, and this is what the script produced on its own. 10 headers moved, 4,262 lines 81 files rewritten, now emitting <fastfields/...> instead of "fastfields/..." `--check`: clean, idempotent, no dependency leak Drop this commit and the design in the preceding ones still stands. The one-line tools/test-baseline.sh probe update rides along here because the script does not touch that file: the gate tool probes for impl/kernels/bounds.h to validate tree layout and dies before running a single test if it is absent. tools/consolidate.sh and the six-repo probe in the same script name the same paths and are deliberately left alone -- they describe the frozen pre-consolidation layout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016AjQcY78NgbagPSbPJRr6Z
balbasty
commented
Aug 20, 2026
CollaboratorAuthor
Superseded by #149 — same content, same two commits, rebased onto Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Answers the two questions asked together, plus the thread-count question
that follows from them. Full document:
docs/proposals/core-and-naming.md.Recommended definition
It decides every borderline file: it admits
atomic.h(device-specialised, butnot an operation) and the parallel/threadpool group, and it excludes
splinc.h(which is the operation exported as
spline_coeff).Two premises in the brief that do not hold
core/was said to be barred from opening the device namespace.core/autocast.halready opensFF_NAMESPACE_BEGIN(FF_DEVICE), andcore/cuda_switch.hexists to branch on__CUDACC__and pulls<cuda_fp16.h>under nvcc. The real constraint is narrower: acore/header must compile under both compilers and mean the right thing in each.
So no fourth directory and no
core/cpu+core/cudasplit is needed.core/dispatch.h:28,48sayscanUse32BitIndexMathcomes fromcore/autocast.h. It is defined atimpl/kernels/utils.h:668. That iswhy 17 files in
src/include the kernels layer directly — the dependencyinversion this proposal repairs is load-bearing today and mis-documented.
Also: the header-guard PR (#145) landed the opposite of what the brief
described — guards everywhere, no
#pragma once— and existing guards keeptheir names, so a file move needs no guard renames.
The file list
Ten files, 4,262 lines. Closure is clean and checked mechanically:
core/never acquires a dependency on
impl/kernels/.utils.h·bounds.h·spline.h·batch.h·atomic.h·meta.h·parallel.h·parallel_impl.h·threadpool.h·threadpool.inlimpl/kernels/then holds only per-operation implementations.Not moved, with reasons in the doc:
vector/(11 files, 2,389 lines) — not infrastructure, superseded.Its only includer is a scratch target that is compiled but never run, and
distance/mesh_utils.hcontains an independent parallel hierarchy of thesame abstraction. Decide its fate separately.
tetrahedron.h— this is not a placement question. Both copies arereferenced by nothing, and
impl/cpu/tetrahedron.hdoes not compile(uses
parallel_for/GRAIN_SIZEwith no includes, and sits inff::tetrarather than
ff::cpu::tetra). Nothing builds it, so nothing catches it.splinc.h— the owner's instinct is right and the one-character gapfrom
spline.his the trap worth naming out loud.Naming
The
voxidea is right for a stronger reason than "marking voxelwise-ness":the kernels layer and the impl layer share a namespace — all seven module
namespaces are opened by both. It does not collide today only because every
kernel entry point is hidden inside a class template (
Kernels,RegFlow,Multiscale,Child) rather than being a free function. Two pieces ofevidence that this workaround is load-bearing:
impl/cpu/pushpull.h:37-82has a lambda named
pullshadowing the functionpullit sits inside, andteeny's commitb7dbd08fixed exactly this collision with exactly thisvox. Recommended:ff::<device>::<module>::vox, 28 sites.elemis themore accurate name by the codebase's own prose — the doc gives the trade
rather than pretending it is settled.
atomic.his the case that tests the scheme, and it is a real bug, confirmedby brace-depth scan: the whole CUDA branch is at global scope, including
an overload of CUDA's own built-in
atomicAdd(line 263) and ATen'sAtomicFPOp/gpuAtomicAddnames verbatim — in an installed header, withfastfields-torchas a planned downstream consumer.FF_GPU_ATOMIC_INTEGERis also defined, never used, and never
#undef'd.On internal helpers: the
_sigil marks two unrelated things (116 distinctidentifiers, 2,943 mentions — overwhelmingly narrowed locals like
_stride_out, and only incidentally functions). Keep it for locals; forfunctions adopt the convention #147 is already landing (
ff::cuda::flow_slice::,a named nested namespace, no sigil) rather than inventing a competing one.
Thread-count API
ff::set_num_threads/get_num_threadsalready exist, fullyimplemented, in
threadpool.inl:58-69;parallel_impl.halready wraps themin a backend-abstracted pair covering the OpenMP and single-threaded builds.
The task is export, not design. Three things a public setter would expose:
the obvious public name is already taken by the internal helper;
set_parallel_threads(-1)reachesThreadPool(size_t(-1))and spawnsthreads until the process dies; and the setter mutates two function-local
statics with no lock, in a pool where #97 has just fixed races reachable only
at higher thread counts. The
/2default is a deliberate x86-only SMTcorrection — keep it, document it, note that CI therefore runs the pool at
2 threads.
CUDA: do not mirror it. But the real finding is not the API — all 39
launch sites use
CUDA_NUM_THREADS = 1024(the architectural maximum) andcudaGetLastError/cudaPeekAtLastErrorappear zero times anywhere, so acudaErrorLaunchOutOfResourcesis discarded silently and the output tensorkeeps whatever it held. Adding launch error checking is the highest-value item
in this document and is independent of everything else in it.
Gate
Prototype commit,
clang++, legsdefault,lib— row-for-row identical totools/test-baseline.expected: 13 cpu-lib suites, 59,886 checks, 0failures, plus the hub's 2 suites / 14 checks.
--checkreports NOTCOMPARABLE on leg coverage (2 of 6 recorded legs), not on any differing
row; the other four legs vary only the bound/spline compile policy, which
this change does not touch.
tools/move-core-headers.py --check→ clean, no dependency leak, idempotent.Sequencing
Must land after#145 and #146. The script does not hard-code an include
delimiter — it measures the tree's dominant one — so it emits
"fastfields/…"before that sweep and
<fastfields/…>after, and a rebase is resolved byre-running it, never by hand.
Verified independent: #147 touches
src/lib-cuda/only (16 files, noneunder
include/) — zero overlap, and itsflow_slice::seam is an inputto the naming section rather than a conflict. #143 intersects only on the
~16
src/*.cppwhoseutils.hinclude line changes — different lines in thesame files. CI is neutral:
ci.yml:102already putsimpl/kernels/andcore/in the same "trigger EVERYTHING" clause.Everything in the naming section should wait and land as separate PRs;
bundling a rename into a relocation makes both unreviewable.
Generated by Claude Code