Skip to content

refactor: simplify operator cache fast path - #920

Draft
voltjia wants to merge 1 commit into
perf/operator-call-cache-fast-pathfrom
refactor/simplify-operator-cache-fast-path
Draft

refactor: simplify operator cache fast path#920
voltjia wants to merge 1 commit into
perf/operator-call-cache-fast-pathfrom
refactor/simplify-operator-cache-fast-path

Conversation

@voltjia

@voltjia voltjia commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Make CacheKey::Matches return booleans directly and short-circuit on the first mismatch.
  • Store each hot-cache slot as one map-entry pointer instead of parallel key and operator pointers.
  • Restore the established find -> construct -> emplace miss path, removing the temporary null entry and manual rollback.

Motivation

This PR is stacked on #858 and keeps its two-entry thread-local hot path intact. It removes incidental complexity without giving up the measured hot-path improvement.

The try_emplace miss path in #858 inserts {key, nullptr} before constructing the operator and retains the returned iterator across Make. If construction re-enters the same cache, a same-key call can observe the incomplete entry, while a different-key insertion can rehash the map and invalidate the retained iterator.

Constructing before emplace leaves the map unchanged on failure and avoids using a map iterator across operator construction, so the explicit try / erase recovery is no longer needed.

Type of Change

  • feat - new feature / new operator / new platform
  • fix - bug fix
  • perf - performance improvement (no behavioral change)
  • refactor - code restructuring without behavior change
  • test - adding or fixing tests only
  • docs - documentation only
  • build / ci - build system or CI configuration
  • chore - tooling, formatting, or other non-code changes
  • Breaking change

Platforms Affected

  • CPU (WITH_CPU)
  • NVIDIA (WITH_NVIDIA)
  • Iluvatar (WITH_ILUVATAR)
  • MetaX (WITH_METAX)
  • Cambricon (WITH_CAMBRICON)
  • Moore (WITH_MOORE)
  • Ascend (WITH_ASCEND)
  • PyTorch C++ bindings (WITH_TORCH)
  • Build system / CMake / CI
  • Python bindings / user-facing API

Smoke Test Result

NVIDIA A100-SXM4-80GB, fixed container image dd94fce2f83a, the InfiniRT prefix documented by #858, and explicit CMAKE_CUDA_ARCHITECTURES=80:

scripts/dev/build.sh nvidia --smoke --jobs 16
[build] done

python -m pytest tests/test_cpp_api.py::test_cpp_operator_cache_fast_path -q
1 passed

python -m pytest tests/test_add.py -m smoke --devices nvidia -q
6 passed, 258 deselected

Push checks on dff02818914f2524371431142149a269a144bac0:

Clang Format (clang-format 21): passed
Ruff: passed

Test Results on Supported Platforms

Platform Affected Build / Smoke Result Full Result / Notes
CPU Yes Shared CPU code compiled; focused cache test passed Full suite not run
NVIDIA Yes Smoke build and focused Add smoke passed Full suite not run
Iluvatar Yes Not run Hardware unavailable
MetaX Yes Not run Hardware unavailable
Cambricon Yes Not run Hardware unavailable
Moore Yes Not run Hardware unavailable
Ascend Yes Not run Hardware unavailable

Benchmark / Performance Impact

Three revisions were built in the same environment:

Each comparison used seven paired A-B-C-C-B-A blocks. Each process reported the median of nine rounds; block ratios use geometric means and 20,000-sample paired bootstrap 95% confidence intervals. Negative deltas mean the later revision is faster.

The isolated C++ cache benchmark confirms that #858's two intended hot patterns remain faster after this simplification:

Scenario A -> B B -> C B -> C 95% CI Guardrail
Repeated key -54.11% -1.34% [-1.40%, -1.05%] +3%: pass
Two-key alternating -31.26% -1.98% [-2.35%, -1.76%] +5%: pass
Prewarmed 64-key map hit +38.38% +0.75% [-8.70%, +1.09%] +5%: pass
New-key miss +18.67% +3.19% [+1.16%, +3.60%] +10%: pass

The NVIDIA benchmark times Python-to-InfiniOps host submission with CUDA synchronization outside each timed loop:

Scenario A -> B B -> C B -> C 95% CI Guardrail
Repeated key -12.21% -0.48% [-1.90%, +1.96%] +3%: pass
Two-key alternating -10.29% -1.54% [-6.03%, +2.55%] +5%: pass
Prewarmed 64-key map hit (primary) +1.86% -0.74% [-2.84%, +19.84%] +5%: inconclusive
Prewarmed 64-key map hit (independent confirmation) N/A -1.96% [-3.85%, -1.00%] +5%: pass
New-key miss +6.87% -5.15% [-19.72%, -2.08%] +10%: pass

The primary map-hit interval was widened by host noise despite its favorable point estimate, so it is reported unchanged. A predeclared independent confirmation used seven fresh B-C-C-B blocks and 15 rounds per process; it passed without selecting or reusing primary blocks.

The separate A -> B results are reported only to show the gain introduced by #858; they are not combined with B -> C. The simplification preserves the repeated and alternating hot-path improvements. The only intentional cost is a second hash-table probe on first insertion; existing-map fallback hits and hot hits are unchanged.

Notes for Reviewers

  • The two-entry hot path and previous-entry promotion are deliberately retained.
  • CacheKeyBuilder specializations without Matches still fall back to full key construction and hash-table lookup.
  • Hot slots point to map elements. unordered_map insertion and rehash preserve element pointers; cache invalidation clears the map and resets both pointers.
  • Cold-call profiling returns to the pre-perf: avoid redundant operator cache lookups #858 boundary: cache.lookup covers find, while cache.construct covers construction and insertion. Range names and counts are unchanged.
  • No test files are changed; this PR reuses perf: avoid redundant operator cache lookups #858's focused cache and profiling coverage.
  • Review this PR against perf/operator-call-cache-fast-path.

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