Skip to content

⚡ perf: reduce avoidable work in the request hot path#4490

Merged
ReneWerner87 merged 3 commits into
mainfrom
perf/hot-path-micro-optimizations
Jul 2, 2026
Merged

⚡ perf: reduce avoidable work in the request hot path#4490
ReneWerner87 merged 3 commits into
mainfrom
perf/hot-path-micro-optimizations

Conversation

@ReneWerner87

Copy link
Copy Markdown
Member

Summary

Three small, behavior-preserving optimizations in the request hot path:

  • app.ErrorHandler: return early when no sub-apps are mounted. The mount lookup normalized (copied) the request path on every handler error and every router 404, even though appListKeys is empty for non-mounted apps, where the whole prefix loop is dead code. For paths beyond the stack-allocation limit this copy is a heap allocation.
  • DefaultCtx.Route: the route == nil fallback called the variadic c.Method(), pushing Route to inline cost 88 (budget 80). Using app.method(c.methodInt) directly, which is what Method() resolves to without an override, makes Route inlinable into hot callers such as Params and FullPath.
  • Bounds-check elimination in route matching: the bucket-scan loops in next/nextCustom compared the index against a len(tree)-1 copy, and getMatch compared the segment length against a stale local, so the compiler kept bounds checks on tree[indexRoute] and detectionPath[:i] for every candidate route. Clamping the start index with max(..., 0) and comparing unsigned against the live length lets BCE remove both. The cold 405 fallback loops are unchanged because they read the index after the loop.

Benchmarks

benchstat vs current main, Apple M2 Pro, -count 10:

Benchmark main PR delta
Router_NotFound 210.3n ± 1% 202.5n ± 1% -3.76% (p=0.000)
Router_Chain 117.0n ± 2% 112.0n ± 2% -4.31% (p=0.000)
Router_Next 45.86n ± 24% 42.41n ± 1% -7.53% (p=0.000)
Router_Handler 79.66n ± 1% 77.90n ± 1% -2.21% (p=0.000)
Ctx_Params 54.60n ± 1% 52.46n ± 1% -3.92% (p=0.000)
Communication_Flow 37.33n ± 1% 37.09n ± 1% -0.64% (p=0.012)
Route_Match 13.17n ± 3% 13.27n ± 1% ~ (p=0.125)

All benchmarks stay at 0 B/op, 0 allocs/op.

Verification

  • go test .: 1400 tests pass
  • make lint: 0 issues
  • -d=ssa/check_bce: no bounds check left on tree[indexRoute] (both hot loops) or detectionPath[:i]; the cold 405 loops intentionally keep theirs
  • -gcflags=-m: can inline (*DefaultCtx).Route, inlined at its in-package call sites

🤖 Generated with Claude Code

ReneWerner87 and others added 3 commits July 1, 2026 22:44
app.ErrorHandler normalized the request path on every handler error and
router 404 even though the mount list is empty for non-mounted apps,
copying the path each time (a heap allocation once the path outgrows
the stack-allocation limit). Return early instead;
Benchmark_Router_NotFound improves by ~4%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The variadic c.Method() call in the route==nil fallback pushed Route to
inline cost 88 (budget 80), blocking inlining into hot callers such as
Params and FullPath. Using app.method(c.methodInt) directly, which is
what Method() resolves to without an override, makes Route inlinable;
Benchmark_Ctx_Params improves by ~4%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bucket-scan loops in next/nextCustom compared the index against a
len(tree)-1 copy, and getMatch compared the segment length against a
stale local, so the compiler kept bounds checks on tree[indexRoute] and
detectionPath[:i] for every candidate route. Clamping the start index
and comparing unsigned against the live length lets BCE remove both,
verified with -d=ssa/check_bce. The cold 405 fallback loops are
unchanged because they read the index after the loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 1, 2026 20:51
@ReneWerner87
ReneWerner87 requested a review from a team as a code owner July 1, 2026 20:51
@ReneWerner87
ReneWerner87 requested review from efectn, gaby and sixcolors July 1, 2026 20:51
@ReneWerner87 ReneWerner87 added this to v3 Jul 1, 2026
@ReneWerner87 ReneWerner87 added this to the v3 milestone Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR applies several performance-oriented micro-optimizations: an early-return fast path in ErrorHandler when no sub-apps are mounted, a variadic-call-avoiding Method computation in DefaultCtx.Route's fallback path, a bounds-check-free unsigned comparison in path segment matching, and restructured loop iteration in router next/nextCustom functions.

Changes

Routing performance tweaks

Layer / File(s) Summary
ErrorHandler fast path
app.go
Adds early return delegating directly to configured ErrorHandler when no sub-apps are mounted, skipping prefix lookup.
Route fallback Method computation
ctx.go
Fallback Route construction now computes Method via c.app.method(c.methodInt) instead of calling c.Method().
Bounds-safe const segment matching
path.go
Replaces signed i > partLen check with unsigned bounds comparison against detectionPath length before slicing.
Router loop iteration restructuring
router.go
Rewrites next and nextCustom scanning loops to use a clamped starting index with a direct bounds-checked for loop instead of the prior lenr-based pattern.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

  • gofiber/fiber#3907: Both PRs modify (*App).ErrorHandler logic—one changes mounted sub-app selection, the other adds a no-mount fast path.
  • gofiber/fiber#3922: Both PRs modify (*App).ErrorHandler in app.go, one optimizing path-prefix segment counting.

Suggested labels: ⚡️ Performance

Suggested reviewers: sixcolors, efectn

Poem

A hop, a skip, a tighter loop,
No mounts? Then straight through the hoop!
Bounds checked clean, no signed mistake,
Method computed for goodness' sake.
This bunny thumps in pure delight 🐇⚡

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description is substantial and includes summary, benchmarks, and verification, though some template sections are omitted.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the PR’s main goal of performance optimizations in the request hot path.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/hot-path-micro-optimizations

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.91%. Comparing base (05919e5) to head (dac0998).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4490      +/-   ##
==========================================
- Coverage   92.91%   92.91%   -0.01%     
==========================================
  Files         138      138              
  Lines       13609    13607       -2     
==========================================
- Hits        12645    12643       -2     
  Misses        597      597              
  Partials      367      367              
Flag Coverage Δ
unittests 92.91% <100.00%> (-0.01%) ⬇️

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 applies a set of small, behavior-preserving optimizations aimed at reducing avoidable work on Fiber’s request hot path (routing + error handling), with the goal of improving latency without introducing allocations.

Changes:

  • Skip mount-prefix normalization and lookup in App.ErrorHandler when there are no mounted sub-apps.
  • Make (*DefaultCtx).Route cheaper/inlinable by avoiding the variadic Method() fallback call.
  • Restructure hot route-scan loops and a const-segment check to enable better bounds-check elimination by the compiler.

Reviewed changes

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

File Description
app.go Adds an early return in App.ErrorHandler when no mount prefixes exist to avoid path normalization/copy work.
ctx.go Replaces c.Method() with c.app.method(c.methodInt) in the nil-route fallback to reduce inlining cost.
router.go Adjusts next / nextCustom scanning loops to start from a clamped index and iterate with indexRoute < len(tree) for BCE.
path.go Uses an unsigned length guard to keep detectionPath[:i] slice bounds-check free in routeParser.getMatch.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
router.go (1)

291-320: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Cold 405-fallback loop unchanged — good, but same pattern could get the same treatment later.

This secondary scan loop still uses the old lenr/indexRoute++ pattern. The PR explicitly leaves this alone since it's the cold path, which is a reasonable scoping decision, but worth flagging as a candidate for a consistent BCE-friendly rewrite in a future pass if this path ever becomes hot (e.g., heavy 405 traffic).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@router.go` around lines 291 - 320, The 405-fallback scan in router.go still
uses the older lenr/indexRoute++ traversal pattern, so if you decide to align it
with the rest of the routing code, refactor this loop in the same style as the
other route-walk logic around treeStack/treeHash by avoiding manual
post-increment indexing and keeping the bounds-check-friendly access pattern
consistent. This is a low-priority follow-up for Router route matching,
especially if the fallback path becomes hot later.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@router.go`:
- Around line 291-320: The 405-fallback scan in router.go still uses the older
lenr/indexRoute++ traversal pattern, so if you decide to align it with the rest
of the routing code, refactor this loop in the same style as the other
route-walk logic around treeStack/treeHash by avoiding manual post-increment
indexing and keeping the bounds-check-friendly access pattern consistent. This
is a low-priority follow-up for Router route matching, especially if the
fallback path becomes hot later.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c4ebbef6-ab98-44a2-ab14-9a456d38b12b

📥 Commits

Reviewing files that changed from the base of the PR and between 05919e5 and dac0998.

📒 Files selected for processing (4)
  • app.go
  • ctx.go
  • path.go
  • router.go

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

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

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

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

@gaby gaby changed the title perf: reduce avoidable work in the request hot path ⚡ perf: reduce avoidable work in the request hot path Jul 1, 2026
@ReneWerner87
ReneWerner87 merged commit 83ad285 into main Jul 2, 2026
26 checks passed
@ReneWerner87
ReneWerner87 deleted the perf/hot-path-micro-optimizations branch July 2, 2026 06:32
@github-project-automation github-project-automation Bot moved this to Done in v3 Jul 2, 2026
@ReneWerner87 ReneWerner87 modified the milestones: v3, v3.4.0 Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants