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

Regression and Perf Fixes #52956

Merged
merged 1 commit into from
May 19, 2021

Conversation

tarekgh
Copy link
Member

@tarekgh tarekgh commented May 19, 2021

This change is fixing two issues:

  • Fixes a regression of setting the recording trace flags on the Activity when having a parent context and the samplers returning a recording flag on. We used to use the parent context trace flags but now we consider the sampler returned value.
  • Fixes extra allocation which was happening when recording a measurement in the metrics instruments. Teh original written code was working fine on .NET 5.0 and 6.0 as the jit was avoiding the extra allocation. But on .NET Core and Full Framework this optimization was not happening. The change here is to avoid this extra allocation.

@ghost
Copy link

ghost commented May 19, 2021

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

Issue Details

This change is fixing two issues:

  • Fixes a regression of setting the recording trace flags on the Activity when having a parent context and the samplers returning a recording flag on. We used to use the parent context trace flags but now we consider the sampler returned value.
  • Fixes extra allocation which was happening when recording a measurement in the metrics instruments. Teh original written code was working fine on .NET 5.0 and 6.0 as the jit was avoiding the extra allocation. But on .NET Core and Full Framework this optimization was not happening. The change here is to avoid this extra allocation.
Author: tarekgh
Assignees: -
Labels:

area-System.Diagnostics.Tracing

Milestone: -

@tarekgh
Copy link
Member Author

tarekgh commented May 19, 2021

CC @reyang @cijothomas @victlu

Thanks to @victlu for catching these issues that early :-)

Copy link
Member

@noahfalk noahfalk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@tarekgh
Copy link
Member Author

tarekgh commented May 19, 2021

#52685

@tarekgh
Copy link
Member Author

tarekgh commented May 19, 2021

The failure in the CI leg runtime (Libraries Test Run release mono Linux x64 Debug) is unrelated to the change and tracked by the issue #44689

@tarekgh tarekgh merged commit 220fee4 into dotnet:main May 19, 2021
@tarekgh tarekgh deleted the FixCasesFailingWithOpenTelemetry branch May 19, 2021 17:59
@tarekgh
Copy link
Member Author

tarekgh commented May 19, 2021

/backport to release/6.0-preview5

@github-actions
Copy link
Contributor

Started backporting to release/6.0-preview5: https://github.com/dotnet/runtime/actions/runs/857818026

{
if (measurement is byte byteMeasurement)
if (typeof(T) == typeof(byte))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tarekgh Hey I was just noticing this change. Would you indulge me on a couple of questions?

  • Why remove the else if from the checks?

  • I understand the switch from is to typeof(T) is because some frameworks allocate on is. If we added back the old version under a preprocessor directive for >= NET5.0 would it then be allocation free for users on NET5.0 or NET6.0? Right now those users will see at least one boxing from the object cast, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the else if from the checks?

It doesn't matter as the JIT optimize the code anyway and will remove all other code when generating type specific code.

I understand the switch from is to typeof(T) is because some frameworks allocate on is. If we added back the old version under a preprocessor directive for >= NET5.0 would it then be allocation free for users on NET5.0 or NET6.0? Right now those users will see at least one boxing from the object cast, no?

No, boxing will be optimized away too. no boxing will occur. try it yourself writing some simple code like:

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        internal static int NotifyMeasurement<T>(T measurement) where T : struct
        {
            if (typeof(T) == typeof(int))
            {
                return (int)(object)measurement;
            }
            if (typeof(T) == typeof(long))
            {
                return (int)(long)(object)measurement;
            }
            return 0;
        }

        [Benchmark]
        public void TestAllocation()
        {
            int t = 0;
            for (int i = 0; i < 10; i++)
            {
                t += NotifyMeasurement<int>(i);
                t += NotifyMeasurement<long>(i);
            }
        }

and you will see no allocation happening

|         Method |     Mean |     Error |    StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------- |---------:|----------:|----------:|------:|------:|------:|----------:|
| TestAllocation | 6.096 ns | 0.0659 ns | 0.0584 ns |     - |     - |     - |         - |

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff thanks @tarekgh! Is this JIT magic documented anywhere? A cheat sheet of things it will optimize away would be great to have.

@ghost ghost locked as resolved and limited conversation to collaborators Jul 18, 2021
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.

3 participants