Repository navigation
Conversation
GetEdges is called for many nodes while building the DFA. It used a Dictionary<EdgeKey, List<Endpoint>> to collect a handful of edges, and most of its time went into growing that dictionary. Use an insertion-ordered list with a linear search instead (keys are compared ordinally, like the dictionary's hash code), and reuse a static array for the 'any method' sentinel. Adds a GetEdges benchmark to HttpMethodMatcherPolicyBenchmark. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the routing edge-allocation optimization.
No open issues 🎉
What changed in this PR
Reduces allocations in HttpMethodMatcherPolicy.GetEdges during routing DFA construction while preserving existing edge ordering and key-matching behavior.
Changes:
- Replaces dictionary-based edge collection with an insertion-ordered list and linear lookup.
- Reuses a static array for the any-method sentinel.
- Adds a focused benchmark and a regression test for custom HTTP methods differing only by case.
| File | Description |
|---|---|
src/Http/Routing/test/UnitTests/Matching/HttpMethodMatcherPolicyTest.cs |
Tests separate edges and insertion order for case-differing custom methods. |
src/Http/Routing/src/Matching/HttpMethodMatcherPolicy.cs |
Uses list-based edge lookup and reuses the any-method array. |
src/Http/Routing/perf/Microbenchmarks/Matching/HttpMethodMatcherPolicyBenchmark.cs |
Adds a GetEdges benchmark with method-specific, CORS, and unrestricted endpoints. |
Review effort: Balanced
|
/azp run aspnetcore-components-e2e Rerunning: the only failure is 🤖 Posted by ASP.NET Core Perf 2 (AI Agent) |
|
No pipelines are associated with this pull request. |
8b6747b to
ec79448
Compare
|
CI status: 🤖 Posted by ASP.NET Core Perf 2 (AI Agent) |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ec79448 to
95e7398
Compare
|
/review |
Reduce allocations in HttpMethodMatcherPolicy.GetEdges
Reduce allocations and time in
HttpMethodMatcherPolicy.GetEdgesduring DFA buildDescription
GetEdgesruns for many nodes while the DFA is built. It collected a handful of edges in aDictionary<EdgeKey, List<Endpoint>>, and most of its time went to growing that dictionary.EdgeKey.Equalsis case-insensitive butGetHashCodeis ordinal. The dictionary therefore kept custom methods that differ only by case (for exampleMERGEandmerge) as separate edges. The lookup keeps exactly that rule: an ordinal fast path, otherwiseEqualsplus a hash-code match.*) sentinel.List<T>indexer loop), with noCollectionsMarshal,Unsafeor custom vectorization.GetEdgesbenchmark toHttpMethodMatcherPolicyBenchmark.GetEdges_CustomMethodsDifferingInCase_CreateSeparateEdgesInInsertionOrder, which pins the existing edge order and case handling. It passes on bothmainand this branch.There are no public API or behavior changes.
Benchmarks
Release builds of
Microsoft.AspNetCore.Routing.Microbenchmarksusingmain's source and this branch's source with the same benchmark harness. Settings: in-process toolchain, 5 warmup and 15 measured iterations,MemoryDiagnoser, 3 interleaved before/after rounds, Linux VM, .NET 12 alpha. Values are the mean of the 3 rounds.HttpMethodMatcherPolicyBenchmark.GetEdges(DestinationCount=3)HttpMethodMatcherPolicyBenchmark.GetEdges(DestinationCount=5)HttpMethodMatcherPolicyBenchmark.GetEdges(DestinationCount=11)MatcherBuilderGithubBenchmark.DfaEach round showed the same direction for
GetEdges. The full GitHub-routes DFA build allocates 4.3% less; its time was lower in every round, but the difference is close to run-to-run noise.Tests
Microsoft.AspNetCore.Routing.Tests: 3506/3506 passed, including the new test.🤖 Posted by ASP.NET Core Perf 2 (AI Agent)