Skip to content

perf: optimize LineCache to reduce allocations#2903

Merged
sl0thentr0py merged 1 commit intomasterfrom
perf/linecache-optimization
Mar 19, 2026
Merged

perf: optimize LineCache to reduce allocations#2903
sl0thentr0py merged 1 commit intomasterfrom
perf/linecache-optimization

Conversation

@HazAT
Copy link
Member

@HazAT HazAT commented Mar 18, 2026

✅ Low risk — internal refactor of LineCache

Part of #2901 (reduce memory allocations by ~53%)

Changes

  • Use Hash#fetch instead of ||= to avoid double hash lookup in getlines
  • Remove valid_path?/getline indirection — inline bounds checking via line_at helper
  • Build pre/post context arrays directly with Array.new instead of creating a single large array and slicing it
  • Add set_frame_context method that sets frame attributes directly, avoiding the intermediate [pre, context_line, post] array allocation
  • Cache context results per (filename, lineno) since the same frames repeat across exceptions — avoids recreating identical arrays

The public get_file_context API is preserved for custom LineCache implementations.

HazAT added a commit that referenced this pull request Mar 18, 2026
Reduce total allocated memory from 442k to 206k bytes (-53.5%) and
objects from 3305 to 1538 (-53.5%) per Rails exception capture.

All changes are internal optimizations with zero behavior changes.

Key optimizations:
- Cache longest_load_path and compute_filename results (class-level,
  invalidated on $LOAD_PATH changes)
- Cache backtrace line parsing and Line/Frame object creation (bounded
  at 2048 entries)
- Optimize LineCache with Hash#fetch, direct context setting, and
  per-(filename, lineno) caching
- Avoid unnecessary allocations: indexed regex captures, match? instead
  of =~, byteslice, single-pass iteration in StacktraceBuilder
- RequestInterface: avoid env.dup, cache header name transforms, ASCII
  fast-path for encoding
- Scope/BreadcrumbBuffer: shallow dup instead of deep_dup where inner
  values are not mutated after duplication
- Hub#add_breadcrumb: hint default nil instead of {} to avoid empty
  hash allocation

See sub-PRs for detailed review by risk level:
- #2902 (low risk) — hot path allocation avoidance
- #2903 (low risk) — LineCache optimization
- #2904 (medium risk) — load path and filename caching
- #2905 (needs review) — backtrace parse caching
- #2906 (needs review) — Frame object caching
- #2907 (needs review) — Scope/BreadcrumbBuffer shallow dup
- #2908 (medium risk) — RequestInterface optimizations
@sl0thentr0py sl0thentr0py force-pushed the perf/linecache-optimization branch from 7ce022e to 542ee21 Compare March 19, 2026 16:28
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@sl0thentr0py
Copy link
Member

set_frame_context is not used so removing, plus the context_cache would've grown unboundedly, not a good design anyway.

Refactor LineCache internals to reduce memory allocations when reading
source context for stacktrace frames:

- Use Hash#fetch instead of ||= to avoid double hash lookup in getlines
- Remove valid_path?/getline indirection — inline bounds checking via
  line_at helper
- Build pre/post context arrays directly with Array.new instead of
  creating a single large array and slicing it
- Add set_frame_context method that sets frame attributes directly,
  avoiding the intermediate [pre, context_line, post] array allocation
- Cache context results per (filename, lineno) since the same frames
  repeat across exceptions — avoids recreating identical arrays

The public get_file_context API is preserved for custom LineCache
implementations.
@sl0thentr0py sl0thentr0py force-pushed the perf/linecache-optimization branch from 542ee21 to 5eb86fb Compare March 19, 2026 16:59
@sl0thentr0py sl0thentr0py merged commit aaa5a9a into master Mar 19, 2026
135 checks passed
@sl0thentr0py sl0thentr0py deleted the perf/linecache-optimization branch March 19, 2026 17:06
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.

2 participants