From cd6af0e07c07376eacab182808b636d643db25f0 Mon Sep 17 00:00:00 2001 From: Gregory LEOCADIE Date: Fri, 7 Mar 2025 15:45:21 +0100 Subject: [PATCH] [Profiler] Add tag GC CPU samples (#6746) --- .../GCThreadsCpuProvider.cpp | 5 ++++ .../GCThreadsCpuProvider.h | 1 + .../NativeThreadsCpuProviderBase.cpp | 5 ++++ .../NativeThreadsCpuProviderBase.h | 2 ++ .../GarbageCollectorCpuTimeTest.cs | 23 ++++++++++++------- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.cpp index b2b4614a5148..d27dc34eb276 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.cpp @@ -59,6 +59,11 @@ std::vector> const& GCThreadsCpuProvider::GetThread return _gcThreads; } +Labels GCThreadsCpuProvider::GetLabels() +{ + return Labels{Label{"gc_cpu_sample", "true"}}; +} + std::vector GCThreadsCpuProvider::GetFrames() { return diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.h index fc5f7167df1e..a9d840655cca 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/GCThreadsCpuProvider.h @@ -24,6 +24,7 @@ class GCThreadsCpuProvider : public NativeThreadsCpuProviderBase private: bool IsGcThread(std::shared_ptr const& thread); std::vector> const& GetThreads() override; + Labels GetLabels() override; std::vector GetFrames() override; std::vector> _gcThreads; diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.cpp b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.cpp index 43a808c9fefd..0adb8e6cf626 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.cpp +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.cpp @@ -96,6 +96,11 @@ std::unique_ptr NativeThreadsCpuProviderBase::GetSamples() sample->AddFrame(frame); } + for (auto const& label : GetLabels()) + { + sample->AddLabel(Label{label.first,label.second}); + } + enumerator->Set(sample); return enumerator; diff --git a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.h b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.h index 699946f57112..290c506cf32f 100644 --- a/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.h +++ b/profiler/src/ProfilerEngine/Datadog.Profiler.Native/NativeThreadsCpuProviderBase.h @@ -8,6 +8,7 @@ #include "IFrameStore.h" #include "ISamplesProvider.h" #include "IThreadInfo.h" +#include "Sample.h" #include @@ -26,6 +27,7 @@ class NativeThreadsCpuProviderBase : public ISamplesProvider std::unique_ptr GetSamples() override; virtual std::vector GetFrames() = 0; virtual std::vector> const& GetThreads() = 0; + virtual Labels GetLabels() = 0; CpuTimeProvider* _cpuTimeProvider; std::chrono::milliseconds _previousTotalCpuTime; diff --git a/profiler/test/Datadog.Profiler.IntegrationTests/GarbageCollections/GarbageCollectorCpuTimeTest.cs b/profiler/test/Datadog.Profiler.IntegrationTests/GarbageCollections/GarbageCollectorCpuTimeTest.cs index 9843554340e7..e5cfaf1acbb5 100644 --- a/profiler/test/Datadog.Profiler.IntegrationTests/GarbageCollections/GarbageCollectorCpuTimeTest.cs +++ b/profiler/test/Datadog.Profiler.IntegrationTests/GarbageCollections/GarbageCollectorCpuTimeTest.cs @@ -3,6 +3,8 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2022 Datadog, Inc. // +using System; +using System.Linq; using Datadog.Profiler.IntegrationTests.Helpers; using FluentAssertions; using Xunit; @@ -19,7 +21,7 @@ public class GarbageCollectorCpuTimeTest private static readonly StackFrame GcFrame = new("|lm:[native] GC |ns: |ct: |cg: |fn:Garbage Collector |fg: |sg:"); private static readonly StackFrame ClrFrame = new("|lm:[native] CLR |ns: |ct: |cg: |fn:.NET |fg: |sg:"); - private readonly StackTrace gcStack = new(GcFrame, ClrFrame); + private static readonly StackTrace GcStack = new(GcFrame, ClrFrame); private readonly ITestOutputHelper _output; @@ -47,7 +49,7 @@ public void CheckCpuTimeForGcThreadsIsReported(string appName, string framework, SamplesHelper.GetSamples(runner.Environment.PprofDir).Should() // match the GC stacktrace and check that the waltime value is 0 and the cpu value is not 0 - .Contain(sample => sample.StackTrace.Equals(gcStack) && sample.Values[0] == 0 && sample.Values[1] != 0); + .Contain(sample => IsGcCpuSample(sample) && sample.Values[0] == 0 && sample.Values[1] != 0); } [TestAppFact("Samples.Computer01", new[] { "net6.0", "net7.0" })] @@ -68,7 +70,7 @@ public void CheckNoGcSampleIfCpuProfilingIsDisabled(string appName, string frame runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(GcStack)); } [TestAppFact("Samples.Computer01", new[] { "net6.0", "net7.0" })] @@ -87,7 +89,7 @@ public void CheckNoGcSampleIfNotGcServerSetToOne(string appName, string framewor runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => IsGcCpuSample(sample)); } [TestAppFact("Samples.Computer01", new[] { "net6.0", "net7.0" })] @@ -106,7 +108,7 @@ public void CheckNoGcSampleIfFeatureDeactivated(string appName, string framework runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => IsGcCpuSample(sample)); } [TestAppFact("Samples.Computer01", new[] { "net6.0", "net7.0" })] @@ -125,7 +127,7 @@ public void CheckNoGcSampleIfFeatureDeactivatedByDefault(string appName, string runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(GcStack) && sample.Labels.Any(x => x.Name == "" && x.Value == "") ); } [TestAppFact("Samples.Computer01", new[] { "netcoreapp3.1" })] @@ -144,7 +146,7 @@ public void CheckFeatureIsDisabledIfNetCoreVersionIsLessThan_5(string appName, s runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => IsGcCpuSample(sample)); } [TestAppFact("Samples.Computer01", new[] { "net462" })] @@ -163,7 +165,12 @@ public void CheckFeatureIsDisabledIfDotNetFramework(string appName, string frame runner.Run(agent); Assert.True(agent.NbCallsOnProfilingEndpoint > 0); - SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => sample.StackTrace.Equals(gcStack)); + SamplesHelper.GetSamples(runner.Environment.PprofDir).Should().NotContain(sample => IsGcCpuSample(sample)); + } + + private static bool IsGcCpuSample((StackTrace StackTrace, PprofHelper.Label[] Labels, long[] Values) sample) + { + return sample.StackTrace.Equals(GcStack) && sample.Labels.Any(label => label.Name == "gc_cpu_sample" && label.Value == "true"); } } }