Repository navigation
perf: make hot index helpers static inline for faster cellToChildren and gridDisk - #1301
justinhwang wants to merge 1 commit into
Conversation
…line them cellToChildren, gridDisk and the vertex and edge functions spend much of their time calling tiny helpers defined in a different .c file, which the compiler cannot inline without LTO: - cellToChildren (h3Index.c) calls iterStepChild (iterators.c) once per child. - h3NeighborRotations (algos.c) calls _h3LeadingNonZeroDigit and isResolutionClassIII (h3Index.c) and _isBaseCellPentagon, _isBaseCellPolarPentagon and _baseCellIsCwOffset (baseCells.c). - gridDisk, vertex and directed edge code calls the exported isPentagon. Move those helpers into their headers as static inline, following the approach of the header-only coordijk.h. isPentagon keeps its exported definition as a wrapper around a new internal _h3IsPentagon, which library code now calls directly. No behavior change. In Release builds cellToChildren is about 2x faster and gridDisk about 30% faster, in static and shared builds alike. Co-Authored-By: Claude Code <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. WalkthroughSeveral helper functions now have inline definitions in headers. Child-iterator advancement also moves into a header implementation. Library call sites replace exported pentagon checks with the internal ChangesInline helper migration
Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Refactor Possibly related PRs
Merge Risk:
|
Summary
Several hot paths call tiny helpers that are defined in a different
.cfile, so the compiler cannot inline them without LTO:cellToChildren(h3Index.c) callsiterStepChild(iterators.c) once per child.h3NeighborRotations(algos.c), which dominatesgridDisk, calls_h3LeadingNonZeroDigitandisResolutionClassIII(h3Index.c) and_isBaseCellPentagon,_isBaseCellPolarPentagonand_baseCellIsCwOffset(baseCells.c).gridDisk, vertex and directed edge code calls the exportedisPentagon.This moves those helpers into their headers as
static inline, the same approach as the header-onlycoordijk.h(#1154).isPentagonkeeps its exported definition as a one-line wrapper around a new internal_h3IsPentagon, which library code now calls directly. Function bodies are moved unchanged; there is no behavior or public API change.iterStepChildwasDECLSPECbut is not part ofh3api.h. It is no longer an exported symbol of the shared library; in-repo callers (utility.c, tests) get the inline version fromiterators.h.Benchmark
Apple M3 Max,
CMAKE_BUILD_TYPE=Release, master vs. this branch, median of 10 alternating runs. Apple clang 21 and Homebrew GCC 16.2, static and shared builds.Notes:
gridDiskPentagon*improved less on Clang static (-2% to -6%) than in the other three configurations (-12% to -27%). I have not tracked down why.Relation to LTO (#325, #326)
I measured #326 (LTO, applied to current master) on the same machine. On shared Release builds LTO alone gives about the same result as this change (-18% to -20% geomean), from the same call sites. With this change in place, adding LTO on top gave no further improvement in my runs (+1% on Clang, +3% on GCC, geomean). Unlike LTO, this also applies to static builds and needs no build-system change.
Closes #325
Test plan
make test, 326/326 passing, on macOS arm64:-DWARNINGS_AS_ERRORS=ON(Apple clang 21)-DENABLE_COVERAGE=ON -DH3_PREFIX=testprefix_): all lines of the moved code inbaseCells.h,h3Index.handiterators.hare covered.make formatwith clang-format-14 produces no further changes.🤖 Generated with Claude Code