Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce allocation in Activity.{Parent}Id #86685

Merged
merged 1 commit into from May 24, 2023

Conversation

stephentoub
Copy link
Member

When activities are enabled, we end up allocating Activity.Id eg once per HTTP request, and in addition to the result string, Id is allocating both a two-char string from a span as well as a string[6], both of which can be avoided.

Method Toolchain Mean Ratio Allocated Alloc Ratio
Test \main\corerun.exe 7.814 ms 1.00 22.89 MB 1.00
Test \pr\corerun.exe 4.240 ms 0.54 12.97 MB 0.57
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

[MemoryDiagnoser(false)]
[HideColumns("Error", "StdDev", "Median")]
public class Program
{
    public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);

    private Action<Activity, string> _setter;

    [GlobalSetup]
    public void Setup()
    {
        Activity.DefaultIdFormat = ActivityIdFormat.W3C;
        _setter = BuildSetter<Activity, string>(typeof(Activity).GetField("_id", BindingFlags.NonPublic | BindingFlags.Instance));
    }

    [Benchmark]
    public void Test()
    {
        using Activity activity = new Activity("Test");
        activity.Start();
        Action<Activity, string> setter = _setter;
        for (int i = 0; i < 100_000; i++)
        {
            _ = activity.Id;
            setter(activity, null);
        }
        activity.Stop();
    }

    private static Action<TSource, TArg> BuildSetter<TSource, TArg>(FieldInfo field)
    {
        ParameterExpression target = Expression.Parameter(typeof(TSource));
        ParameterExpression value = Expression.Parameter(typeof(TArg));
        return Expression.Lambda<Action<TSource, TArg>>(
            Expression.Assign(Expression.Field(target, field), value),
            target,
            value).Compile();
    }
}

@ghost
Copy link

ghost commented May 24, 2023

Tagging subscribers to this area: @tarekgh, @tommcdon, @pjanotti
See info in area-owners.md if you want to be subscribed.

Issue Details

When activities are enabled, we end up allocating Activity.Id eg once per HTTP request, and in addition to the result string, Id is allocating both a two-char string from a span as well as a string[6], both of which can be avoided.

Method Toolchain Mean Ratio Allocated Alloc Ratio
Test \main\corerun.exe 7.814 ms 1.00 22.89 MB 1.00
Test \pr\corerun.exe 4.240 ms 0.54 12.97 MB 0.57
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;

[MemoryDiagnoser(false)]
[HideColumns("Error", "StdDev", "Median")]
public class Program
{
    public static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);

    private Action<Activity, string> _setter;

    [GlobalSetup]
    public void Setup()
    {
        Activity.DefaultIdFormat = ActivityIdFormat.W3C;
        _setter = BuildSetter<Activity, string>(typeof(Activity).GetField("_id", BindingFlags.NonPublic | BindingFlags.Instance));
    }

    [Benchmark]
    public void Test()
    {
        using Activity activity = new Activity("Test");
        activity.Start();
        Action<Activity, string> setter = _setter;
        for (int i = 0; i < 100_000; i++)
        {
            _ = activity.Id;
            setter(activity, null);
        }
        activity.Stop();
    }

    private static Action<TSource, TArg> BuildSetter<TSource, TArg>(FieldInfo field)
    {
        ParameterExpression target = Expression.Parameter(typeof(TSource));
        ParameterExpression value = Expression.Parameter(typeof(TArg));
        return Expression.Lambda<Action<TSource, TArg>>(
            Expression.Assign(Expression.Field(target, field), value),
            target,
            value).Compile();
    }
}
Author: stephentoub
Assignees: stephentoub
Labels:

area-System.Diagnostics.Tracing

Milestone: -

@stephentoub stephentoub requested a review from tarekgh May 24, 2023 04:56
@stephentoub stephentoub merged commit dafc07d into dotnet:main May 24, 2023
105 checks passed
@stephentoub stephentoub deleted the activityid branch May 24, 2023 16:37
@dotnet dotnet locked as resolved and limited conversation to collaborators Jun 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants