Skip to content

perf(error): check SourceFragmentsHidden before formatting sources#139

Merged
samber merged 3 commits into
mainfrom
perf/sources-lazy-format-concat
Jul 5, 2026
Merged

perf(error): check SourceFragmentsHidden before formatting sources#139
samber merged 3 commits into
mainfrom
perf/sources-lazy-format-concat

Conversation

@samber

@samber samber commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • ToMap, LogValue and formatVerbose evaluated if sources := o.Sources(); sources != "" && !SourceFragmentsHidden left-to-right: Sources() formatted the full source-fragment output - reading source files from disk and building per-line strings - and the result was then discarded, because SourceFragmentsHidden is true by default. Checking the flag first skips all of that work in the default configuration; behavior with SourceFragmentsHidden=false is unchanged.
  • Also replaces fmt.Sprintf with direct concatenation in the per-line / per-block builders (getSourceFromFrame, framesToStacktraceBlocks, framesToSourceBlocks), benefiting the non-hidden path too.

Benchmarks

benchstat vs main (darwin/arm64, Apple M3, -count=10 -cpu=1):

         │ before3.txt │              after3.txt              │
         │   sec/op    │    sec/op     vs base                │
ToMap      3.494µ ± 5%   1.631µ ± 15%  -53.31% (p=0.002 n=10)
LogValue   3.499µ ± 4%   1.478µ ±  8%  -57.77% (p=0.000 n=10)
geomean    3.496µ        1.553µ        -55.60%

         │ before3.txt  │              after3.txt              │
         │     B/op     │     B/op      vs base                │
ToMap      5.214Ki ± 0%   2.789Ki ± 0%  -46.51% (p=0.000 n=10)
LogValue   5.357Ki ± 0%   2.745Ki ± 0%  -48.76% (p=0.000 n=10)
geomean    5.285Ki        2.767Ki       -47.65%

         │ before3.txt │             after3.txt             │
         │  allocs/op  │ allocs/op   vs base                │
ToMap       63.00 ± 0%   28.00 ± 0%  -55.56% (p=0.000 n=10)
LogValue    61.00 ± 0%   24.00 ± 0%  -60.66% (p=0.000 n=10)
geomean     61.99        25.92       -58.18%

BenchmarkNewStacktrace was also checked as a control (this path never calls Sources()): allocations and memory are byte-for-byte identical before/after (0% variance), confirming the change is isolated to the Sources()-gated paths.

Test coverage

The SourceFragmentsHidden=false path (and, by extension, oopsStacktrace.Source() and framesToSourceBlocks) had no coverage at all before this PR — every existing test ran with the package default (true), so the new gated branches and the two previously-0%-covered functions were untested. Added:

  • TestOopsSourceFragmentsVisible / TestOopsSourceFragmentsHiddenByDefault: assert ToMap, LogValue and formatVerbose include/omit "sources" depending on the flag. Both run sequentially (no t.Parallel(), //nolint:paralleltest) since the former temporarily flips the package-level flag and the latter asserts on its default.
  • TestOopsStacktraceSource: direct coverage of oopsStacktrace.Source() (empty-frames and with-frames cases).
  • TestFramesToSourceBlocks: direct coverage of framesToSourceBlocks, including the no-body-skips-block and multi-block-reversal cases.

Package coverage: 90.8% -> 94.0%. Source and framesToSourceBlocks are now at 100%.

Test plan

Verified with go build ./..., go vet ./..., go test ./..., golangci-lint run ./... (0 issues), and go test -bench=BenchmarkToMap -bench=BenchmarkLogValue -benchmem -count=10 -cpu=1 ./benchmarks run before/after the change and compared with benchstat.

ToMap, LogValue and formatVerbose evaluated the condition

    if sources := o.Sources(); sources != "" && !SourceFragmentsHidden

left-to-right: Sources() formatted the full source-fragment output -
reading source files from disk and building per-line strings - and the
result was then discarded, because SourceFragmentsHidden is true by
default. Checking the flag first skips all of that work in the default
configuration; behavior with SourceFragmentsHidden=false is unchanged.

Also replaces fmt.Sprintf with direct concatenation in the per-line /
per-block builders (getSourceFromFrame, framesToStacktraceBlocks,
framesToSourceBlocks), benefiting the non-hidden path too.

benchstat vs main (darwin/arm64, Apple M3, -count=10 -cpu=1):

         | before3.txt |              after3.txt              |
         |   sec/op    |    sec/op     vs base                |
ToMap      3.494u ± 5%   1.631u ± 15%  -53.31% (p=0.002 n=10)
LogValue   3.499u ± 4%   1.478u ±  8%  -57.77% (p=0.000 n=10)
geomean    3.496u        1.553u        -55.60%

         | before3.txt  |              after3.txt              |
         |     B/op     |     B/op      vs base                |
ToMap      5.214Ki ± 0%   2.789Ki ± 0%  -46.51% (p=0.000 n=10)
LogValue   5.357Ki ± 0%   2.745Ki ± 0%  -48.76% (p=0.000 n=10)
geomean    5.285Ki        2.767Ki       -47.65%

         | before3.txt | after3.txt                          |
         |  allocs/op  | allocs/op   vs base                 |
ToMap       63.00 ± 0%   28.00 ± 0%  -55.56% (p=0.000 n=10)
LogValue    61.00 ± 0%   24.00 ± 0%  -60.66% (p=0.000 n=10)
geomean     61.99        25.92       -58.18%
@samber samber marked this pull request as ready for review July 5, 2026 15:19
Copilot AI review requested due to automatic review settings July 5, 2026 15:19
@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.20%. Comparing base (4579c2c) to head (d2050d3).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
error.go 87.50% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #139      +/-   ##
==========================================
+ Coverage   90.50%   91.20%   +0.70%     
==========================================
  Files          15       15              
  Lines        1243     1251       +8     
==========================================
+ Hits         1125     1141      +16     
+ Misses         93       88       -5     
+ Partials       25       22       -3     
Flag Coverage Δ
unittests 91.20% <90.90%> (+0.70%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 optimizes OopsError formatting paths by avoiding expensive source-fragment generation when SourceFragmentsHidden is enabled (the default), while preserving behavior when source fragments are explicitly enabled.

Changes:

  • Reorders the SourceFragmentsHidden check ahead of Sources() in LogValue, ToMap, and formatVerbose to skip unnecessary disk reads/string building by default.
  • Replaces some fmt.Sprintf usages with direct string concatenation / strconv.Itoa in per-line and per-block formatting helpers.
  • Removes now-unneeded fmt imports in files where formatting no longer uses it.

Reviewed changes

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

File Description
error.go Checks SourceFragmentsHidden before calling Sources() in LogValue, ToMap, and formatVerbose to avoid wasted work in the default configuration.
sources.go Replaces fmt.Sprintf with strconv.Itoa + concatenation in per-line source formatting; removes fmt import.
stacktrace.go Simplifies stacktrace/source block string assembly via concatenation; removes fmt import.

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

samber added 2 commits July 5, 2026 17:32
The previous commit gated Sources() behind SourceFragmentsHidden in
ToMap, LogValue and formatVerbose, but no existing test ever set
SourceFragmentsHidden=false, leaving oopsStacktrace.Source() and
framesToSourceBlocks at 0% coverage and the new gated branches
partially untested.

Adds:
- TestOopsSourceFragmentsVisible / TestOopsSourceFragmentsHiddenByDefault:
  verify ToMap, LogValue and formatVerbose include/omit "sources"
  depending on the flag.
- TestOopsStacktraceSource: direct coverage of oopsStacktrace.Source().
- TestFramesToSourceBlocks: direct coverage of framesToSourceBlocks,
  including the no-body-skips-block and multi-block-reversal cases.

Coverage: 90.8% -> 94.0%.
TestOopsSourceFragmentsHiddenByDefault asserts on the package-level
SourceFragmentsHidden default, which TestOopsSourceFragmentsVisible
temporarily flips. Both must run outside the parallel pool so the
flip-and-restore in the latter cannot interleave with the former
assumption; add the paralleltest lint suppression that comes with
opting out of t.Parallel() for that reason.
@samber samber merged commit 74199a3 into main Jul 5, 2026
10 checks passed
@samber samber deleted the perf/sources-lazy-format-concat branch July 5, 2026 15:42
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