Skip to content

chore(metrics): replace vendored JSF PRNG with inline SplitMix64 (#700)#786

Merged
leoparente merged 1 commit into
developfrom
chore/replace-jsf-splitmix64
Jun 24, 2026
Merged

chore(metrics): replace vendored JSF PRNG with inline SplitMix64 (#700)#786
leoparente merged 1 commit into
developfrom
chore/replace-jsf-splitmix64

Conversation

@leoparente

Copy link
Copy Markdown
Contributor

Closes #700.

What

Replaces the vendored 3rd/rng/jsf.h (178-line Bob Jenkins "Small Fast" PRNG) with a ~6-line inline SplitMix64 in AbstractMetricsManager.h, and deletes the 3rd/rng/ directory.

JSF was used in exactly one spot — the deep-sampling gate:

_deep_sampling_now.store((_rng() % 100U < _deep_sample_rate), ...);

i.e. "roll 0–99, deep-sample this event if the roll is under deep_sample_rate." The sampling rate is unchanged; only which events get deep-sampled differs, and nothing depends on the specific set (default deep_sample_rate=100 means the RNG is never even called).

Why SplitMix64 instead of the proposed pcg-cpp

The issue suggested the pcg-cpp conan package. I went a different way after weighing the options:

  • pcg-cpp adds a third-party dependency to remove a dependency-free header — the wrong direction for "reduce maintained code" — and its idiomatic seeding seed_seq_from<std::random_device> is exactly the footgun that caused RDRAND failure on Arista switch #109 (below).
  • std::mt19937 works but carries ~2.5 KB of state per handler instance for a 1-in-100 coin flip.
  • Inline SplitMix64 removes the whole 3rd/rng/ dir with no new dependency, 8-byte state, and BigCrush-grade quality. We "own" ~6 auditable lines instead of 178.

Invariant preserved (#109)

#109 ("RDRAND failure on Arista switch") was a startup crash: the pre-JSF randutils RNG auto-seeded from std::random_deviceRDRAND, which faults and throws on some hardware. PR #110 fixed it by switching to a fixed-seeded PRNG. SplitMix64 here is seeded from a fixed constant and never from hardware entropy, preserving that fix. A prominent comment documents the constraint so it isn't "improved" into entropy seeding later.

Build wiring

  • Delete 3rd/rng/ + its add_subdirectory + the rng link in visor-core.
  • Fix a latent copy-paste bug in 3rd/timer/CMakeLists.txt: it called target_include_directories(rng ...) instead of (timer ...), so timer.hpp's include dir was being attached to the rng target and only reached visor-core transitively through it. Removing rng would have broken <timer.hpp>; pointing it at timer makes the timer target self-contained.
  • Update the NOMINMAX comment (it cited jsf.h's static min()/max()); the define stays for general Windows hygiene.

Testing

unit-tests-visor-core (which includes the sampling/metrics tests) passes — 1153 assertions, 21 test cases.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jun 23, 2026

Copy link
Copy Markdown

LCOV of commit 6531af3 during Debug Builds #162

  lines......: 82.4% (14103 of 17109 lines)
  functions..: 72.8% (1424 of 1955 functions)
  branches...: no data found

Files changed coverage rate: n/a

Full coverage report

@leoparente

Copy link
Copy Markdown
Contributor Author

@codex review

…700)

Removes the vendored 3rd/rng/jsf.h (178 lines, Bob Jenkins Small Fast) in favor
of a ~6-line inline SplitMix64 in AbstractMetricsManager.h. This is the deep-
sampling gate's PRNG (roll 0-99, deep-sample when the roll is under
deep_sample_rate), used in exactly one place; sampling RATE is unchanged (only
which events get deep-sampled differs, and nothing depends on the specific set).

Why SplitMix64 over the issue's suggested pcg-cpp conan package: it removes the
maintained code (the whole 3rd/rng dir) without ADDING a third-party dependency,
keeps an 8-byte state (vs jsf's 16, vs std::mt19937's ~2.5KB), and has
BigCrush-grade quality.

CRITICAL invariant preserved (issue #109 "RDRAND failure on Arista switch"): the
generator is seeded from a fixed constant and never from std::random_device /
hardware entropy. The pre-JSF randutils-based RNG auto-seeded via random_device
-> RDRAND, which faulted and threw on startup on some hardware; PR #110 fixed
that by switching to a fixed-seeded PRNG. A prominent comment documents this so
nobody "improves" it into entropy seeding (a particular footgun with pcg-cpp's
idiomatic seed_seq_from<random_device>).

Build wiring:
- Delete 3rd/rng/ and its add_subdirectory + the `rng` link in visor-core.
- Fix a latent copy-paste bug in 3rd/timer/CMakeLists.txt: it called
  target_include_directories(rng ...) instead of (timer ...), so timer.hpp's
  include dir was being attached to the rng target and only reached visor-core
  transitively through it. Removing rng would have broken <timer.hpp>; pointing
  it at timer makes the timer target self-contained.
- Update the NOMINMAX comment in CMakeLists.txt (it cited jsf.h's static
  min()/max()); keep the define for general Windows hygiene.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@leoparente
leoparente force-pushed the chore/replace-jsf-splitmix64 branch from 0a3c868 to 6531af3 Compare June 23, 2026 19:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the vendored JSF PRNG implementation and replaces its sole usage (deep-sampling gate in metrics) with a small inline SplitMix64 PRNG seeded from a fixed constant, while also cleaning up the CMake wiring to drop the removed rng interface target and ensure the timer interface target is self-contained.

Changes:

  • Replace #include <jsf.h> + jsf32 usage with an inline fixed-seed SplitMix64 generator for deep-sampling decisions.
  • Remove the 3rd/rng/ directory and unlink/unsubdir it from the build.
  • Fix 3rd/timer CMake to attach include dirs to the timer target (not the deleted rng target) and update WIN32 NOMINMAX comment to be general-purpose.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/CMakeLists.txt Stops linking visor-core against the removed rng interface target.
src/AbstractMetricsManager.h Introduces inline fixed-seed SplitMix64 PRNG and removes dependency on jsf.h.
CMakeLists.txt Updates WIN32 NOMINMAX comment to reflect broader rationale (not JSF-specific).
3rd/timer/CMakeLists.txt Fixes include-directory attachment to the correct timer target (prevents breakage after rng removal).
3rd/rng/jsf.h Deletes vendored JSF PRNG header.
3rd/rng/CMakeLists.txt Deletes the rng interface target definition.
3rd/CMakeLists.txt Removes add_subdirectory(rng) from third-party build wiring.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 0a3c86889c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@leoparente
leoparente marked this pull request as ready for review June 23, 2026 19:43
@leoparente
leoparente requested review from jajeffries and samiura June 23, 2026 19:44
@leoparente leoparente self-assigned this Jun 23, 2026
@leoparente
leoparente merged commit 55ff30c into develop Jun 24, 2026
23 checks passed
@leoparente
leoparente deleted the chore/replace-jsf-splitmix64 branch June 24, 2026 18:46
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.

[Proposal] Replace JSF with PCG-CPP

3 participants