Skip to content

[perf] Add fast path for unescaped W3C baggage - #134647

Open
martincostello wants to merge 2 commits into
dotnet:mainfrom
martincostello:baggage-decode-fastpath
Open

martincostello wants to merge 2 commits into
dotnet:mainfrom
martincostello:baggage-decode-fastpath

Conversation

@martincostello

@martincostello martincostello commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Mirror EncodeBaggageValue() by adding a fast path for baggage values that do not need percent decoding.

Benchmarks

BenchmarkDotNet v0.15.4, Windows 11 (10.0.26200.9457)
13th Gen Intel Core i7-13700H 2.90GHz, 1 CPU, 20 logical and 14 physical cores
.NET SDK 11.0.100-rc.1.26420.103
  [Host] : .NET 11.0.0 (11.0.0-rc.1.26420.103, 11.0.26.42103), X64 RyuJIT x86-64-v3

Job=MediumRun  Toolchain=InProcessEmitToolchain  IterationCount=15  LaunchCount=2  WarmupCount=10
Build Method Mean Error StdDev Gen0 Allocated
main ExtractPlainBaggage 160.0 ns 12.69 ns 19.00 ns 0.0293 368 B
PR ExtractPlainBaggage 145.0 ns 8.16 ns 11.97 ns 0.0293 368 B
main ExtractEscapedBaggage 176.6 ns 12.07 ns 17.69 ns 0.0279 352 B
PR ExtractEscapedBaggage 178.3 ns 13.16 ns 19.29 ns 0.0279 352 B

vs. main: plain (common case) ~9% faster, allocation unchanged (a string must be produced
either way). Escaped (uncommon case): within noise across repeated runs (bounced between -4%
and +3%), versus a consistent ~+5% before this change.

Benchmark code
using System.Diagnostics;
using System.Linq;
using BenchmarkDotNet.Attributes;

namespace System.Diagnostics.Microbenchmarks;

[MemoryDiagnoser]
public class W3CBaggageDecodeBenchmarks
{
    private readonly DistributedContextPropagator _propagator = DistributedContextPropagator.CreateDefaultPropagator();
    private readonly Dictionary<string, string> _plainCarrier = new();
    private readonly Dictionary<string, string> _escapedCarrier = new();

    private static readonly DistributedContextPropagator.PropagatorGetterCallback s_getter = static (object? carrier, string fieldName, out string? value, out IEnumerable<string>? values) =>
    {
        values = null;
        ((Dictionary<string, string>)carrier!).TryGetValue(fieldName, out value);
    };

    [GlobalSetup]
    public void Setup()
    {
        // Typical unescaped baggage: short ascii key=value pairs, no '%' escapes needed.
        _plainCarrier["baggage"] = "userId=12345,sessionId=abcdef0123456789,requestType=read";

        // Baggage containing values that need percent-decoding (e.g. spaces, non-ascii-derived escapes).
        _escapedCarrier["baggage"] = "userName=John%20Doe,city=San%20Francisco,note=100%25%20done";
    }

    [Benchmark(Baseline = true)]
    public int ExtractPlainBaggage() => _propagator.ExtractBaggage(_plainCarrier, s_getter)!.Count();

    [Benchmark]
    public int ExtractEscapedBaggage() => _propagator.ExtractBaggage(_escapedCarrier, s_getter)!.Count();
}

Mirror `EncodeBaggageValue()` by adding a fast path for baggage values that do not need percent decoding.
@martincostello
martincostello requested a balanced review from Copilot September 25, 2026 10:18
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Sep 25, 2026
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics-tracing
See info in area-owners.md if you want to be subscribed.

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.

Copilot review overview

🟡 Changes recommended

The fast path redundantly scans conforming values twice, undermining its marginal performance benefit.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
What changed in this PR

Adds a .NET-only fast path for unescaped ASCII W3C baggage values.

Changes:

  • Returns plain ASCII baggage directly without using ValueStringBuilder.
  • Retains existing decoding for escaped or non-ASCII values.
File Description
src/​libraries/​System.Diagnostics.DiagnosticSource/​src/​System/​Diagnostics/​W3CPropagator.cs Adds the baggage-decoding fast path.

Do a single scan with `IndexOfAnyExcept()`.

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.

Copilot review overview

🟢 Approval recommended

The optimization preserves existing behavior, uses the established character set, has existing functional coverage, and includes benchmark evidence.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@martincostello
martincostello marked this pull request as ready for review September 25, 2026 11:14

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Diagnostics.Tracing community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants