[GH-ISSUE #904] Investigate bounded batching of canonical digest writes from real CPU profile #364

Closed
opened 2026-10-15 18:24:19 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @morluto on GitHub (Oct 7, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/904

Optimization candidate

A native Node CPU profile of analyze-javascript-application dist/server identifies canonical digest emission and crypto updates as a substantial optimization candidate.

Environment: macOS 26.3 arm64, supported Node v22.22.2, REA checkout faaee693d5bb4bb957387ebd0f4338513c4c914a using its existing built JavaScript. The working tree has concurrent changes; this report does not claim they were rebuilt. Target: 59 JavaScript files, 143,782 source bytes in dist/server.

Reproduction

From a built REA checkout, create an output directory and run:

/absolute/path/to/node-v22.22.2 \
  --cpu-prof --cpu-prof-dir=/absolute/path/to/profile-output \
  --cpu-prof-name=rea-server.cpuprofile \
  scripts/rea.mjs analyze-javascript-application dist/server \
  --format json --filter-output graph.coverage

The observed workload completed successfully in 5.45 seconds. The native profile contains 5,795 nodes and 4,409 exported samples. Counting exported sample node IDs gives:

Native frame Self samples Location (native zero-based)
update 1,053 node:internal/crypto/hash, line 131
emitCanonical 924 dist/domain/canonicalDigest.js, line 9

These non-overlapping self counts total 1,977 / 4,409 samples, about 44.8% of the profile. This is sampled execution evidence, not a proved percentage of elapsed time or an expected speedup. Recursive inclusive counts are not used. This capture ran concurrently with a larger analysis; confirmatory benchmarks must use isolated repeated workloads.

Native profile SHA-256: 00aaaa832373aeca4f1924bfc2ae756b4d7c20deda0ef9eea76780d334b24189.

Source-backed hypothesis

src/domain/canonicalDigest.ts calls emitCanonical(value, part => hash.update(part), ...). Object/array punctuation, keys, and scalar values each trigger a separate update. This preserves the streaming memory boundary added after #623 but can incur many JS/native crypto crossings.

Hypothesis: coalescing small emitted parts into a bounded chunk buffer could reduce digest overhead while preserving the exact canonical byte stream. This has not been implemented or benchmarked; the profile does not prove that batching is the best fix.

Verification needed

  • Compare the current emitter with bounded buffering, without rebuilding a whole canonical graph string.
  • Preserve exact graph, evidence, and snapshot identifiers. Test byte/digest equivalence against the current implementation and canonicalize for Unicode, sparse arrays, unsupported values, toJSON, invalid numbers, and cycles.
  • Repeat the same real analysis in isolation with preserved CPU/heap profiles, elapsed samples, and peak RSS. Declare the estimand and practical threshold before claiming improvement.
  • Keep validation and failure behavior intact; retain graph facets and schema validation.

Related: #623 (whole-string limits), #723 (complete-result representation costs). This candidate concerns per-token streaming hash overhead after the whole-string hashing change.

Originally created by @morluto on GitHub (Oct 7, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/904 ## Optimization candidate A native Node CPU profile of `analyze-javascript-application dist/server` identifies canonical digest emission and crypto updates as a substantial optimization candidate. Environment: macOS 26.3 arm64, supported Node v22.22.2, REA checkout `faaee693d5bb4bb957387ebd0f4338513c4c914a` using its existing built JavaScript. The working tree has concurrent changes; this report does not claim they were rebuilt. Target: 59 JavaScript files, 143,782 source bytes in `dist/server`. ## Reproduction From a built REA checkout, create an output directory and run: ```console /absolute/path/to/node-v22.22.2 \ --cpu-prof --cpu-prof-dir=/absolute/path/to/profile-output \ --cpu-prof-name=rea-server.cpuprofile \ scripts/rea.mjs analyze-javascript-application dist/server \ --format json --filter-output graph.coverage ``` The observed workload completed successfully in 5.45 seconds. The native profile contains 5,795 nodes and 4,409 exported samples. Counting exported sample node IDs gives: | Native frame | Self samples | Location (native zero-based) | | --- | ---: | --- | | `update` | 1,053 | `node:internal/crypto/hash`, line 131 | | `emitCanonical` | 924 | `dist/domain/canonicalDigest.js`, line 9 | These non-overlapping self counts total 1,977 / 4,409 samples, about 44.8% of the profile. This is sampled execution evidence, not a proved percentage of elapsed time or an expected speedup. Recursive inclusive counts are not used. This capture ran concurrently with a larger analysis; confirmatory benchmarks must use isolated repeated workloads. Native profile SHA-256: `00aaaa832373aeca4f1924bfc2ae756b4d7c20deda0ef9eea76780d334b24189`. ## Source-backed hypothesis `src/domain/canonicalDigest.ts` calls `emitCanonical(value, part => hash.update(part), ...)`. Object/array punctuation, keys, and scalar values each trigger a separate update. This preserves the streaming memory boundary added after #623 but can incur many JS/native crypto crossings. Hypothesis: coalescing small emitted parts into a bounded chunk buffer could reduce digest overhead while preserving the exact canonical byte stream. This has not been implemented or benchmarked; the profile does not prove that batching is the best fix. ## Verification needed - Compare the current emitter with bounded buffering, without rebuilding a whole canonical graph string. - Preserve exact graph, evidence, and snapshot identifiers. Test byte/digest equivalence against the current implementation and canonicalize for Unicode, sparse arrays, unsupported values, `toJSON`, invalid numbers, and cycles. - Repeat the same real analysis in isolation with preserved CPU/heap profiles, elapsed samples, and peak RSS. Declare the estimand and practical threshold before claiming improvement. - Keep validation and failure behavior intact; retain graph facets and schema validation. Related: #623 (whole-string limits), #723 (complete-result representation costs). This candidate concerns per-token streaming hash overhead after the whole-string hashing change.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#364
No description provided.