Skip to content

Suppress heap allocations in TracerSettings.IsIntegrationEnabled#772

Merged
kevingosse merged 2 commits into
masterfrom
kevin/integrationsenabled
Jul 1, 2020
Merged

Suppress heap allocations in TracerSettings.IsIntegrationEnabled#772
kevingosse merged 2 commits into
masterfrom
kevin/integrationsenabled

Conversation

@kevingosse

Copy link
Copy Markdown
Contributor
  • Remove closure allocation in IntegrationSettingsCollection
  • Getting the AppDomain friendly name seems to internally call Assembly.GetName, which seems to allocate quite a bit (especially on .net core). Used AppDomain.SetData to cache the result and prevent further allocations

Benchmark:

TracerSettings.IsIntegrationEnabled("Test")
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
  [Host]     : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
  Job-VTGAFA : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
  Job-MNUBEA : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT

Method Runtime Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
Old .NET 4.7.2 254.26 ns 5.100 ns 7.149 ns 1.00 0.00 0.0191 - - 120 B
New .NET 4.7.2 108.29 ns 2.160 ns 2.731 ns 0.43 0.02 - - - -
Old .NET Core 3.1 894.16 ns 17.648 ns 28.499 ns 1.00 0.00 0.0744 - - 472 B
New .NET Core 3.1 59.63 ns 1.178 ns 1.102 ns 0.07 0.00 - - - -

{
return true;
isAppInsight = AppDomainName.IndexOf("ApplicationInsights", StringComparison.OrdinalIgnoreCase) >= 0;
appDomain.SetData(IsAppInsightKey, isAppInsight);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since we only use the current appdomain, I'm wondering if we can go even further and cache the value in a static field. With all those "domain neutral" thingies, I'm not sure anymore of whether this instance is shared across appdomains or not

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.

Static fields are not shared across AppDomains (even if the assembly is domain-neutral) so that's a good idea. There's some good information here on how domain-neutral assemblies are treated: https://docs.microsoft.com/en-us/dotnet/framework/app-domains/application-domains

@lucaspimentel lucaspimentel Jun 29, 2020

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Accessing static fields is slower if the assembly is shared. Since all the AppDomains share the same code, but the field value is not shared, static field access requires an extra level of indirection. If we will be reading this field a lot in domain-neutral scenarios, making it static could be counter-productive.

On the other hand, I don't think we are ever loaded domain-neutral in AAS, so if this value is only read in AAS, it's probably fine.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

GetData does a bunch of checks, acquires a lock, then fetches the boxed value from a dictionary. My gut feeling is that whatever mechanism is involved in fetching static field in domain-neutral assemblies, it shouldn't be slower than that. Unfortunately, the assumption seems really hard to test :/

public static bool ShouldAvoidAppDomain()
{
if (AppDomainName.IndexOf("ApplicationInsights", StringComparison.OrdinalIgnoreCase) >= 0)
var appDomain = AppDomain.CurrentDomain;

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.

Please not the Slack discussion on using VAR. Depending on how that goes, this would be an example where var should not be used. :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I really wish, for the sake of my muscle memory, that we'll end-up allowing both :P

Comment thread src/Datadog.Trace/Util/DomainMetadata.cs Outdated
@@ -100,12 +101,15 @@ public static int AppDomainId

public static bool ShouldAvoidAppDomain()

@macrogreg macrogreg Jun 29, 2020

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.

@lucaspimentel For my education - why are we checking for AppInsights here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In azure app services there are AppInsights AppDomains which spin up underneath the web worker and those would either break or submit traces for AppInsights.
It is a best effort at harmonious co-existence.

Comment thread src/Datadog.Trace/Util/DomainMetadata.cs Outdated
@lucaspimentel
lucaspimentel self-requested a review June 29, 2020 21:07
@kevingosse

Copy link
Copy Markdown
Contributor Author

Rewrote to use a static field + added a unit test (this bit of logic seems to critical not to have one).

New benchmark:

BenchmarkDotNet=v0.12.0, OS=Windows 10.0.19041
Intel Core i7-9750H CPU 2.60GHz, 1 CPU, 12 logical and 6 physical cores
  [Host]     : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
  Job-VTGAFA : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
  Job-MNUBEA : .NET Core 3.1.5 (CoreCLR 4.700.20.26901, CoreFX 4.700.20.27001), X64 RyuJIT

Method Runtime Mean Error StdDev Ratio Gen 0 Gen 1 Gen 2 Allocated
Old .NET 4.7.2 224.47 ns 3.787 ns 3.542 ns 1.00 0.0191 - - 120 B
New .NET 4.7.2 103.12 ns 0.888 ns 0.831 ns 0.46 - - - -
Static .NET 4.7.2 28.96 ns 0.236 ns 0.184 ns 0.13 - - - -
Old .NET Core 3.1 820.41 ns 7.249 ns 6.053 ns 1.00 0.0744 - - 472 B
New .NET Core 3.1 56.87 ns 0.438 ns 0.388 ns 0.07 - - - -
Static .NET Core 3.1 25.99 ns 0.159 ns 0.149 ns 0.03 - - - -

I also realized, while writing the test, that the whole thing could be eluded on .net core (since there are no appdomains), but I'd say it's cheap enough not to bother for now.

@kevingosse
kevingosse marked this pull request as ready for review June 30, 2020 09:55
@kevingosse
kevingosse requested a review from a team as a code owner June 30, 2020 09:55
@kevingosse
kevingosse merged commit 0078656 into master Jul 1, 2020
@kevingosse
kevingosse deleted the kevin/integrationsenabled branch July 1, 2020 10:15
@zacharycmontoya zacharycmontoya added this to the 1.18.2 milestone Jul 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants