Skip to content

chore: add source-map heap profiling harness - #115

Merged
luojiyin1987 merged 3 commits into
masterfrom
chore/source-map-heap-profile
Sep 7, 2026
Merged

luojiyin1987 merged 3 commits into
masterfrom
chore/source-map-heap-profile

Conversation

@luojiyin1987

Copy link
Copy Markdown
Contributor

Adds scripts/profile-source-map-heap.mjs for capturing V8 heap
snapshots at build/raw/range phases. Verifies lazy lineStarts and
sourceGapPrefix do not exist in retained heap until first use.

Fixtures: many-nodes (10k paragraphs), segments (256 KiB high
density), fenced-code (1 MiB code block), urls (1000 definitions).

Documents analysis method in CONTRIBUTING.md. Not added to CI —
heap snapshots are large and V8-version-dependent.

Adds scripts/profile-source-map-heap.mjs for capturing V8 heap
snapshots at build/raw/range phases. Verifies lazy lineStarts and
sourceGapPrefix do not exist in retained heap until first use.

Fixtures: many-nodes (10k paragraphs), segments (256 KiB high
density), fenced-code (1 MiB code block), urls (1000 definitions).

Documents analysis method in CONTRIBUTING.md. Not added to CI —
heap snapshots are large and V8-version-dependent.
- fenced-code fixture: replace O(n²) while-loop with calculated
  repeat count; fixture now produces ~1 MiB without GC pressure
- raw phase: remove blanket try-catch on getRaw(); owned nodes
  with snapshotted offsets should always succeed
- range phase: catch only RangeError (non-contiguous ranges);
  real bugs now propagate instead of being swallowed
- fix comment: fenced code does have code-value source mapping
- Remove unused writeFileSync import and collectNodes function
- CONTRIBUTING.md: fenced-code description 'no segments' → 'with
  source-map segments'
- CONTRIBUTING.md: 'every text node' → 'every mapped value node'
- CONTRIBUTING.md: qualify sourceGapPrefix with 'for multi-segment
  ranges'
@luojiyin1987
luojiyin1987 merged commit 1fd0f0f into master Sep 7, 2026
14 checks passed
@luojiyin1987

Copy link
Copy Markdown
Contributor Author

Analyzed the generated heap snapshots.

The profiling harness is giving useful structural evidence:

  • segments-build and segments-raw are effectively identical, confirming that getRaw() does not materialize the lazy range indexes.
  • segments-range retains about 616 KiB more array backing storage than segments-raw. The retaining path matches the WeakMap<segments[], number[]> shape used by sourceGapPrefix, confirming that perf(source-map): lazy-build sourceGapPrefix on first range query #110's prefix is created only after a multi-segment range query.
  • lineStarts is also absent before the first range query. Its size is negligible in the single-line segment fixture, so this run validates laziness but does not meaningfully quantify perf(source-map): lazy-build lineStarts in parseMdWithSourceMap #109's memory saving.
  • The pathological segment-heavy fixture retains roughly 74.9k source-map segment objects. The identifiable segment object/property/array storage is about 7.1 MiB, roughly 44% of the 16.3 MiB snapshot, or approximately 100 bytes per segment.
  • many-nodes shows measurable overhead from many single-element segment arrays, but there is not enough evidence yet to justify changing the representation.
  • Large fenced-code snapshots are dominated by source/value strings; source-map segment overhead is negligible.
  • URL source-map retained memory is also small. The earlier URL optimization should therefore be viewed mainly as a CPU/allocation-pressure improvement.

This confirms the intended lazy-index behavior and gives us a useful boundary for future memory work.

For now, I don't think we should pursue further source-map memory optimization without evidence from real workloads. In particular, changing the segment representation would add complexity and should require profiling that shows segment density is a real production bottleneck.

A useful final comparison, if needed later, would be parseMd() vs parseMdWithSourceMap() using the same fixtures to isolate the incremental retained cost of source-map support.

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