Skip to content

[Exception Replay] Added test suite for ASP.NET Core (#5821 -> v2)#5970

Merged
andrewlock merged 1 commit into
release/2.xfrom
andrew/matang/exception-replay-testing-suite-v2
Sep 2, 2024
Merged

[Exception Replay] Added test suite for ASP.NET Core (#5821 -> v2)#5970
andrewlock merged 1 commit into
release/2.xfrom
andrew/matang/exception-replay-testing-suite-v2

Conversation

@andrewlock

Copy link
Copy Markdown
Member

Added the infrastructure of integration testing for Exception Replay in ASP.NET Core.

To add a test, one needs to simply create a class that inherits from IRun / IAsyncRun and decorated with ExceptionReplayTestData attribute, providing to the attribute the amount of snapshots anticipated both in default configuration and full stack trace capture configuration.

This PR also introduces the renaming of the configs of Exception Replay from Exception Debugging. In the early days we used to call Exception Replay internally Exception Debugging, thus some of the configs held this name. This PR renamed those leftovers to Exception Replay, including the enablement config of DD_EXCEPTION_REPLAY_ENABLED. Introduced a PR to
dd-go
too where these configs were added to the config_norm_rules.json file.

Laying the groundwork for integration testing of Exception Replay.

The testing infra bootstraps the web app, queries via reflection all the tests (classes inheriting from IRun/IAsyncRun and decorated with ExceptionReplayTestData attribute) and list them. Upon executing a test, a request will hit an endpoint of RunTest with the name of the test to run (FQN of the class name). The crafted test must throw an exception to be considered valid.
For a more complex test scenarios, more endpoints could be introduced.

Every test runs in 4 flavors:

  • With Exception Replay while Dynamic Instrumentation is enabled, default stack trace capturing limit.
  • With Exception Replay while Dynamic Instrumentation is enabled, full stack trace capturing limit.
  • With Exception Replay while Dynamic Instrumentation is disabled, default stack trace capturing limit.
  • With Exception Replay while Dynamic Instrumentation is disabled, full stack trace capturing limit.

This whole PR 🤓. I've added two tests that utilize the infra:

  • ExceptionWithNonSupportedFramesTest
  • RecursiveExceptionTest

Fixes DEBUG-2681, DEBUG-2732, DEBUG-1642.

Backport of #5821

@andrewlock andrewlock added area:tests unit tests, integration tests area:debugger labels Aug 30, 2024
@andrewlock
andrewlock requested review from a team as code owners August 30, 2024 14:37
namespace Datadog.Trace.Debugger.IntegrationTests
{
[UsesVerify]
public class AspNetBase : TestHelper

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Code Quality Violation

class with a Dispose() method must implement IDisposable (...read more)

IDisposable provides an interface for the cleanup of unmanaged resources through the function void Dispose().

To avoid confusion, this rule ensures that any class that exposes a public void Dispose() function must implement IDisposable.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public abstract class AspNetCore5ExceptionReplay : AspNetBase, IClassFixture<AspNetCoreTestFixture>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Code Quality Violation

class with a Dispose() method must implement IDisposable (...read more)

IDisposable provides an interface for the cleanup of unmanaged resources through the function void Dispose().

To avoid confusion, this rule ensures that any class that exposes a public void Dispose() function must implement IDisposable.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public class AspNetCore5ExceptionReplayEnabledDynamicInstrumentationEnabled_FullCallStack : AspNetCore5ExceptionReplay

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

The name does not comply with naming convention (...read more)

Class names should use the PascalCase and start with an uppercase.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public class AspNetCore5ExceptionReplayEnabledDynamicInstrumentationDisabled_FullCallStack : AspNetCore5ExceptionReplay

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

The name does not comply with naming convention (...read more)

Class names should use the PascalCase and start with an uppercase.

Learn More

View in Datadog  Leave us feedback  Documentation


ref struct PingPonged
{
public static async Task<int> Me(Func<int, Task<int>> method, int iteration)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

Avoid short method names under 3 characters (...read more)

Method names should be descriptive of the function behavior and functionalities. Instead of using a very short name, always have a name that indicates what the function is doing.

Learn More

View in Datadog  Leave us feedback  Documentation


ref struct PingPonged
{
public static async Task<int> Me(Func<int, Task<int>> method, int iteration)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

Avoid short method names under 3 characters (...read more)

Method names should be descriptive of the function behavior and functionalities. Instead of using a very short name, always have a name that indicates what the function is doing.

Learn More

View in Datadog  Leave us feedback  Documentation

private static readonly string[] KnownClassNamesToRemoveFromExceptionReplayFrame = { "<<Configure>b__5_2>d" };

// This class is used to test Exception Replay with Dynamic Instrumentation enabled or disabled.
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

View all suggested fixes
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
private AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
protected AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
private protected AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
avoid using public for constructor in abstract class (...read more)

Using an abstract modifier in a class declaration indicates that a class is intended only to be a base class of other classes and not instantiated by itself. Due to this, there is no need for public or internal constructors within. Any initialization logic should be added in a private,private protected, or protected constructor.

View in Datadog  Leave us feedback  Documentation

await asyncRun.RunAsync();
break;
default:
throw new Exception($"Test class not found: {testClassName}");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

do not throw generic exceptions (...read more)

Exceptions should be specific to the application to help points the exact issue. For these reasons, generic exceptions should not be used and we should instead favor specific exception types.

View in Datadog  Leave us feedback  Documentation

return true;
}

if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith("<"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

Suggested change
if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith("<"))
if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith('<'))
use a character, not a string (...read more)

This rule is designed to ensure that you use the most efficient methods for string comparison in C#. When using the StartsWith or EndsWith methods with a single character, the performance can be significantly reduced compared to using the indexer with the first or last index. This is because these methods are designed to work with substrings, not single characters, and therefore involve unnecessary overhead when used in this way.

The importance of this rule lies in writing efficient and performant code. In large-scale applications, using inefficient methods for string comparison can lead to noticeable performance issues. Therefore, it's crucial to use the appropriate methods for each specific use-case.

Learn More

View in Datadog  Leave us feedback  Documentation

ref MeRefStruct NotSupportedFrame(string str)
{
SupportedFrame(str);
throw new Exception();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

do not throw generic exceptions (...read more)

Exceptions should be specific to the application to help points the exact issue. For these reasons, generic exceptions should not be used and we should instead favor specific exception types.

View in Datadog  Leave us feedback  Documentation

namespace Datadog.Trace.Debugger.IntegrationTests
{
[UsesVerify]
public class AspNetBase : TestHelper

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Code Quality Violation

class with a Dispose() method must implement IDisposable (...read more)

IDisposable provides an interface for the cleanup of unmanaged resources through the function void Dispose().

To avoid confusion, this rule ensures that any class that exposes a public void Dispose() function must implement IDisposable.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public abstract class AspNetCore5ExceptionReplay : AspNetBase, IClassFixture<AspNetCoreTestFixture>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Code Quality Violation

class with a Dispose() method must implement IDisposable (...read more)

IDisposable provides an interface for the cleanup of unmanaged resources through the function void Dispose().

To avoid confusion, this rule ensures that any class that exposes a public void Dispose() function must implement IDisposable.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public class AspNetCore5ExceptionReplayEnabledDynamicInstrumentationEnabled_FullCallStack : AspNetCore5ExceptionReplay

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

The name does not comply with naming convention (...read more)

Class names should use the PascalCase and start with an uppercase.

Learn More

View in Datadog  Leave us feedback  Documentation

}
}

public class AspNetCore5ExceptionReplayEnabledDynamicInstrumentationDisabled_FullCallStack : AspNetCore5ExceptionReplay

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

The name does not comply with naming convention (...read more)

Class names should use the PascalCase and start with an uppercase.

Learn More

View in Datadog  Leave us feedback  Documentation


ref struct PingPonged
{
public static async Task<int> Me(Func<int, Task<int>> method, int iteration)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

Avoid short method names under 3 characters (...read more)

Method names should be descriptive of the function behavior and functionalities. Instead of using a very short name, always have a name that indicates what the function is doing.

Learn More

View in Datadog  Leave us feedback  Documentation


ref struct PingPonged
{
public static async Task<int> Me(Func<int, Task<int>> method, int iteration)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

Avoid short method names under 3 characters (...read more)

Method names should be descriptive of the function behavior and functionalities. Instead of using a very short name, always have a name that indicates what the function is doing.

Learn More

View in Datadog  Leave us feedback  Documentation

private static readonly string[] KnownClassNamesToRemoveFromExceptionReplayFrame = { "<<Configure>b__5_2>d" };

// This class is used to test Exception Replay with Dynamic Instrumentation enabled or disabled.
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Quality Violation

View all suggested fixes
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
private AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
protected AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
Suggested change
public AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
private protected AspNetCore5ExceptionReplay(AspNetCoreTestFixture fixture, ITestOutputHelper outputHelper, bool enableDynamicInstrumentation, bool captureFullCallStack)
avoid using public for constructor in abstract class (...read more)

Using an abstract modifier in a class declaration indicates that a class is intended only to be a base class of other classes and not instantiated by itself. Due to this, there is no need for public or internal constructors within. Any initialization logic should be added in a private,private protected, or protected constructor.

View in Datadog  Leave us feedback  Documentation

await asyncRun.RunAsync();
break;
default:
throw new Exception($"Test class not found: {testClassName}");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

do not throw generic exceptions (...read more)

Exceptions should be specific to the application to help points the exact issue. For these reasons, generic exceptions should not be used and we should instead favor specific exception types.

View in Datadog  Leave us feedback  Documentation

return true;
}

if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith("<"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

Suggested change
if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith("<"))
if (tag.Key.EndsWith(classNameSuffix) && tag.Value.StartsWith('<'))
use a character, not a string (...read more)

This rule is designed to ensure that you use the most efficient methods for string comparison in C#. When using the StartsWith or EndsWith methods with a single character, the performance can be significantly reduced compared to using the indexer with the first or last index. This is because these methods are designed to work with substrings, not single characters, and therefore involve unnecessary overhead when used in this way.

The importance of this rule lies in writing efficient and performant code. In large-scale applications, using inefficient methods for string comparison can lead to noticeable performance issues. Therefore, it's crucial to use the appropriate methods for each specific use-case.

Learn More

View in Datadog  Leave us feedback  Documentation

ref MeRefStruct NotSupportedFrame(string str)
{
SupportedFrame(str);
throw new Exception();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 Code Quality Violation

do not throw generic exceptions (...read more)

Exceptions should be specific to the application to help points the exact issue. For these reasons, generic exceptions should not be used and we should instead favor specific exception types.

View in Datadog  Leave us feedback  Documentation

@andrewlock

andrewlock commented Aug 30, 2024

Copy link
Copy Markdown
Member Author

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing the following branches/commits:

Execution-time benchmarks measure the whole time it takes to execute a program. And are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are shown in red. The following thresholds were used for comparing the execution times:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).

gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (73ms)  : 63, 83
     .   : milestone, 73,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (1,034ms)  : 1012, 1057
     .   : milestone, 1034,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (109ms)  : 106, 113
     .   : milestone, 109,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (722ms)  : 695, 750
     .   : milestone, 722,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (96ms)  : 89, 102
     .   : milestone, 96,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (675ms)  : 651, 700
     .   : milestone, 675,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (190ms)  : 188, 192
     .   : milestone, 190,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (1,115ms)  : 1095, 1136
     .   : milestone, 1115,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (276ms)  : 271, 280
     .   : milestone, 276,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (875ms)  : 853, 898
     .   : milestone, 875,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (5970) - mean (265ms)  : 259, 270
     .   : milestone, 265,

    section CallTarget+Inlining+NGEN
    This PR (5970) - mean (872ms)  : 853, 891
     .   : milestone, 872,

Loading

@datadog-ddstaging

datadog-ddstaging Bot commented Aug 30, 2024

Copy link
Copy Markdown

Datadog Report

Branch report: andrew/matang/exception-replay-testing-suite-v2
Commit report: a6842de
Test service: dd-trace-dotnet

✅ 0 Failed, 44 Passed, 0 Skipped, 28m 8.47s Total Time
⌛ 14 Performance Regressions

⌛ Performance Regressions vs Default Branch (14)

This report shows up to 5 performance regressions.

  • Profiler_cpu_walltime_old_stackwalk - scenarios 3.23s (+891.7ms, +38%) - Details
  • Profiler_cpu_walltime - scenarios 3.24s (+894.9ms, +38%) - Details
  • Profiler_walltime - scenarios 3.25s (+901.45ms, +38%) - Details
  • Profiler_cpu_walltime_timer_create - scenarios 3.24s (+901.78ms, +38%) - Details
  • Profiler_liveheap - scenarios 4.21s (+1.03s, +32%) - Details

@andrewlock

andrewlock commented Aug 30, 2024

Copy link
Copy Markdown
Member Author

Benchmarks Report for tracer 🐌

Benchmarks for #5970 compared to master:

  • 1 benchmarks are slower, with geometric mean 1.177
  • All benchmarks have the same allocations

The following thresholds were used for comparing the benchmark speeds:

  • Mann–Whitney U test with statistical test for significance of 5%
  • Only results indicating a difference greater than 10% and 0.3 ns are considered.

Allocation changes below 0.5% are ignored.

Benchmark details

Benchmarks.Trace.ActivityBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 7.46μs 41.8ns 268ns 0.0116 0.00386 0 5.43 KB
master StartStopWithChild netcoreapp3.1 9.99μs 45.8ns 183ns 0.0145 0.00483 0 5.62 KB
master StartStopWithChild net472 15.9μs 34.7ns 134ns 1.02 0.313 0.0963 6.05 KB
#5970 StartStopWithChild net6.0 7.88μs 43.7ns 270ns 0.0149 0.00747 0 5.43 KB
#5970 StartStopWithChild netcoreapp3.1 9.96μs 51.6ns 297ns 0.0283 0.0141 0 5.62 KB
#5970 StartStopWithChild net472 16.1μs 24.5ns 91.8ns 1.03 0.303 0.0955 6.06 KB
Benchmarks.Trace.AgentWriterBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 488μs 369ns 1.38μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 639μs 472ns 1.83μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 846μs 553ns 1.99μs 0.422 0 0 3.3 KB
#5970 WriteAndFlushEnrichedTraces net6.0 465μs 221ns 854ns 0 0 0 2.7 KB
#5970 WriteAndFlushEnrichedTraces netcoreapp3.1 644μs 209ns 809ns 0 0 0 2.7 KB
#5970 WriteAndFlushEnrichedTraces net472 843μs 501ns 1.88μs 0.422 0 0 3.3 KB
Benchmarks.Trace.AspNetCoreBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendRequest net6.0 183μs 1μs 5.59μs 0.182 0 0 18.45 KB
master SendRequest netcoreapp3.1 209μs 1.2μs 9.23μs 0.213 0 0 20.61 KB
master SendRequest net472 0.00263ns 0.000963ns 0.00373ns 0 0 0 0 b
#5970 SendRequest net6.0 189μs 1.08μs 7.69μs 0.183 0 0 18.45 KB
#5970 SendRequest netcoreapp3.1 210μs 1.19μs 8.41μs 0.201 0 0 20.61 KB
#5970 SendRequest net472 0.00241ns 0.000723ns 0.0028ns 0 0 0 0 b
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 557μs 1.46μs 5.64μs 0.534 0 0 41.61 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 661μs 2.5μs 9.68μs 0.326 0 0 41.86 KB
master WriteAndFlushEnrichedTraces net472 860μs 3.23μs 12.5μs 8.3 2.62 0.437 53.23 KB
#5970 WriteAndFlushEnrichedTraces net6.0 565μs 1.48μs 5.35μs 0.548 0 0 41.65 KB
#5970 WriteAndFlushEnrichedTraces netcoreapp3.1 680μs 2.95μs 11.4μs 0.338 0 0 41.88 KB
#5970 WriteAndFlushEnrichedTraces net472 881μs 3.24μs 11.7μs 8.36 2.64 0.44 53.33 KB
Benchmarks.Trace.DbCommandBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteNonQuery net6.0 1.26μs 1.36ns 5.27ns 0.0145 0 0 1.02 KB
master ExecuteNonQuery netcoreapp3.1 1.71μs 1.58ns 5.91ns 0.0129 0 0 1.02 KB
master ExecuteNonQuery net472 1.94μs 3.05ns 11.8ns 0.156 0 0 987 B
#5970 ExecuteNonQuery net6.0 1.19μs 1.36ns 5.25ns 0.0142 0 0 1.02 KB
#5970 ExecuteNonQuery netcoreapp3.1 1.71μs 0.805ns 3.12ns 0.0137 0 0 1.02 KB
#5970 ExecuteNonQuery net472 2.02μs 1.28ns 4.79ns 0.156 0 0 987 B
Benchmarks.Trace.ElasticsearchBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master CallElasticsearch net6.0 1.25μs 0.672ns 2.6ns 0.0139 0 0 976 B
master CallElasticsearch netcoreapp3.1 1.57μs 0.875ns 3.27ns 0.0125 0 0 976 B
master CallElasticsearch net472 2.45μs 2.59ns 10ns 0.158 0 0 995 B
master CallElasticsearchAsync net6.0 1.22μs 0.494ns 1.85ns 0.0134 0 0 952 B
master CallElasticsearchAsync netcoreapp3.1 1.61μs 0.607ns 2.27ns 0.0135 0 0 1.02 KB
master CallElasticsearchAsync net472 2.65μs 1.03ns 3.72ns 0.167 0 0 1.05 KB
#5970 CallElasticsearch net6.0 1.35μs 0.921ns 3.57ns 0.0135 0 0 976 B
#5970 CallElasticsearch netcoreapp3.1 1.5μs 0.603ns 2.17ns 0.0128 0 0 976 B
#5970 CallElasticsearch net472 2.48μs 1.36ns 4.89ns 0.157 0.00124 0 995 B
#5970 CallElasticsearchAsync net6.0 1.2μs 1.26ns 4.7ns 0.013 0 0 952 B
#5970 CallElasticsearchAsync netcoreapp3.1 1.63μs 0.919ns 3.56ns 0.0138 0 0 1.02 KB
#5970 CallElasticsearchAsync net472 2.54μs 1.37ns 5.3ns 0.167 0 0 1.05 KB
Benchmarks.Trace.GraphQLBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteAsync net6.0 1.25μs 0.983ns 3.68ns 0.0135 0 0 952 B
master ExecuteAsync netcoreapp3.1 1.63μs 1.16ns 4.48ns 0.0129 0 0 952 B
master ExecuteAsync net472 1.75μs 1.34ns 5.18ns 0.145 0 0 915 B
#5970 ExecuteAsync net6.0 1.26μs 0.468ns 1.81ns 0.0131 0 0 952 B
#5970 ExecuteAsync netcoreapp3.1 1.55μs 1.13ns 4.24ns 0.0125 0 0 952 B
#5970 ExecuteAsync net472 1.77μs 1.31ns 5.07ns 0.145 0 0 915 B
Benchmarks.Trace.HttpClientBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendAsync net6.0 4.18μs 2.75ns 10.7ns 0.0312 0 0 2.22 KB
master SendAsync netcoreapp3.1 5.11μs 1.72ns 6.19ns 0.0358 0 0 2.76 KB
master SendAsync net472 7.69μs 1.37ns 5.12ns 0.5 0 0 3.15 KB
#5970 SendAsync net6.0 4.28μs 9.45ns 35.4ns 0.0297 0 0 2.22 KB
#5970 SendAsync netcoreapp3.1 5.26μs 1.99ns 7.72ns 0.0367 0 0 2.76 KB
#5970 SendAsync net472 7.72μs 2.48ns 9.59ns 0.497 0 0 3.15 KB
Benchmarks.Trace.ILoggerBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 1.48μs 0.651ns 2.44ns 0.023 0 0 1.64 KB
master EnrichedLog netcoreapp3.1 2.27μs 1.16ns 4.48ns 0.0226 0 0 1.64 KB
master EnrichedLog net472 2.63μs 1.84ns 7.14ns 0.249 0 0 1.57 KB
#5970 EnrichedLog net6.0 1.62μs 0.609ns 2.36ns 0.0226 0 0 1.64 KB
#5970 EnrichedLog netcoreapp3.1 2.22μs 0.66ns 2.38ns 0.0221 0 0 1.64 KB
#5970 EnrichedLog net472 2.65μs 2.37ns 9.16ns 0.249 0 0 1.57 KB
Benchmarks.Trace.Log4netBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 116μs 300ns 1.16μs 0 0 0 4.28 KB
master EnrichedLog netcoreapp3.1 119μs 189ns 708ns 0.0593 0 0 4.28 KB
master EnrichedLog net472 151μs 327ns 1.26μs 0.685 0.228 0 4.46 KB
#5970 EnrichedLog net6.0 114μs 199ns 771ns 0.0569 0 0 4.28 KB
#5970 EnrichedLog netcoreapp3.1 120μs 161ns 622ns 0 0 0 4.28 KB
#5970 EnrichedLog net472 148μs 200ns 776ns 0.671 0.224 0 4.46 KB
Benchmarks.Trace.NLogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 3.03μs 1.03ns 3.99ns 0.0302 0 0 2.2 KB
master EnrichedLog netcoreapp3.1 4.27μs 2.23ns 8.66ns 0.0303 0 0 2.2 KB
master EnrichedLog net472 5.06μs 1.35ns 5.24ns 0.321 0 0 2.02 KB
#5970 EnrichedLog net6.0 3.18μs 1.14ns 4.26ns 0.0303 0 0 2.2 KB
#5970 EnrichedLog netcoreapp3.1 4.27μs 2.24ns 8.69ns 0.0297 0 0 2.2 KB
#5970 EnrichedLog net472 5μs 1.43ns 5.52ns 0.321 0 0 2.02 KB
Benchmarks.Trace.RedisBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendReceive net6.0 1.43μs 1.25ns 4.85ns 0.0157 0 0 1.14 KB
master SendReceive netcoreapp3.1 1.7μs 0.98ns 3.67ns 0.0155 0 0 1.14 KB
master SendReceive net472 2.24μs 1.64ns 6.34ns 0.183 0.0011 0 1.16 KB
#5970 SendReceive net6.0 1.35μs 0.97ns 3.76ns 0.016 0 0 1.14 KB
#5970 SendReceive netcoreapp3.1 1.72μs 0.6ns 2.24ns 0.0155 0 0 1.14 KB
#5970 SendReceive net472 2.21μs 1ns 3.76ns 0.183 0 0 1.16 KB
Benchmarks.Trace.SerilogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 2.68μs 0.594ns 2.14ns 0.0215 0 0 1.6 KB
master EnrichedLog netcoreapp3.1 3.84μs 1.24ns 4.65ns 0.0211 0 0 1.65 KB
master EnrichedLog net472 4.42μs 2.44ns 9.47ns 0.323 0 0 2.04 KB
#5970 EnrichedLog net6.0 2.7μs 0.741ns 2.87ns 0.0216 0 0 1.6 KB
#5970 EnrichedLog netcoreapp3.1 4.01μs 0.926ns 3.58ns 0.0223 0 0 1.65 KB
#5970 EnrichedLog net472 4.42μs 1.62ns 6.06ns 0.322 0 0 2.04 KB
Benchmarks.Trace.SpanBenchmark - Slower ⚠️ Same allocations ✔️

Slower ⚠️ in #5970

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.SpanBenchmark.StartFinishSpan‑net6.0 1.177 393.62 463.44

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartFinishSpan net6.0 394ns 0.368ns 1.43ns 0.00814 0 0 576 B
master StartFinishSpan netcoreapp3.1 547ns 0.718ns 2.68ns 0.00782 0 0 576 B
master StartFinishSpan net472 661ns 0.274ns 1.06ns 0.0918 0 0 578 B
master StartFinishScope net6.0 471ns 0.169ns 0.653ns 0.00989 0 0 696 B
master StartFinishScope netcoreapp3.1 742ns 0.516ns 2ns 0.00932 0 0 696 B
master StartFinishScope net472 854ns 1.11ns 4.31ns 0.104 0 0 658 B
#5970 StartFinishSpan net6.0 464ns 0.362ns 1.4ns 0.00816 0 0 576 B
#5970 StartFinishSpan netcoreapp3.1 549ns 0.219ns 0.847ns 0.00799 0 0 576 B
#5970 StartFinishSpan net472 694ns 0.823ns 3.19ns 0.0916 0 0 578 B
#5970 StartFinishScope net6.0 499ns 0.275ns 1.07ns 0.00981 0 0 696 B
#5970 StartFinishScope netcoreapp3.1 694ns 0.371ns 1.44ns 0.0096 0 0 696 B
#5970 StartFinishScope net472 847ns 1.23ns 4.76ns 0.104 0 0 658 B
Benchmarks.Trace.TraceAnnotationsBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunOnMethodBegin net6.0 665ns 0.486ns 1.88ns 0.00959 0 0 696 B
master RunOnMethodBegin netcoreapp3.1 876ns 0.816ns 3.16ns 0.00929 0 0 696 B
master RunOnMethodBegin net472 1.12μs 1.26ns 4.86ns 0.104 0 0 658 B
#5970 RunOnMethodBegin net6.0 654ns 0.588ns 2.28ns 0.00995 0 0 696 B
#5970 RunOnMethodBegin netcoreapp3.1 912ns 1.13ns 4.37ns 0.00929 0 0 696 B
#5970 RunOnMethodBegin net472 1.12μs 1.4ns 5.41ns 0.104 0 0 658 B

@andrewlock

Copy link
Copy Markdown
Member Author

Throughput/Crank Report:zap:

Throughput results for AspNetCoreSimpleController comparing the following branches/commits:

Cases where throughput results for the PR are worse than latest master (5% drop or greater), results are shown in red.

Note that these results are based on a single point-in-time result for each branch. For full results, see one of the many, many dashboards!

gantt
    title Throughput Linux x64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (5970) (11.189M)   : 0, 11188782
    master (11.115M)   : 0, 11114864
    benchmarks/2.9.0 (11.120M)   : 0, 11120231

    section Automatic
    This PR (5970) (7.511M)   : 0, 7510928
    master (7.311M)   : 0, 7311158
    benchmarks/2.9.0 (7.874M)   : 0, 7874046

    section Trace stats
    master (7.660M)   : 0, 7659733

    section Manual
    This PR (5970) (9.684M)   : crit ,0, 9683897
    master (11.297M)   : 0, 11296697

    section Manual + Automatic
    This PR (5970) (7.079M)   : 0, 7079074
    master (6.770M)   : 0, 6770096

Loading
gantt
    title Throughput Linux arm64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (5970) (9.661M)   : 0, 9661049
    benchmarks/2.9.0 (9.342M)   : 0, 9341974

    section Automatic
    This PR (5970) (6.652M)   : 0, 6651809

    section Manual
    This PR (5970) (8.268M)   : 0, 8268116

    section Manual + Automatic
    This PR (5970) (6.242M)   : 0, 6241600

Loading
gantt
    title Throughput Windows x64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (5970) (10.012M)   : 0, 10012186
    master (10.030M)   : 0, 10029859
    benchmarks/2.9.0 (10.105M)   : 0, 10105239

    section Automatic
    This PR (5970) (6.547M)   : 0, 6546926
    master (6.746M)   : 0, 6746187
    benchmarks/2.9.0 (7.518M)   : 0, 7517801

    section Trace stats
    master (7.324M)   : 0, 7323510

    section Manual
    This PR (5970) (8.671M)   : crit ,0, 8670666
    master (9.931M)   : 0, 9931035

    section Manual + Automatic
    This PR (5970) (6.390M)   : 0, 6389559
    master (6.245M)   : 0, 6244786

Loading

Added the infrastructure of integration testing for Exception Replay in
ASP.NET Core.

To add a test, one needs to simply create a class that inherits from
`IRun` / `IAsyncRun` and decorated with `ExceptionReplayTestData`
attribute, providing to the attribute the amount of snapshots
anticipated both in default configuration and full stack trace capture
configuration.

This PR also introduces the renaming of the configs of Exception Replay
from Exception Debugging. In the early days we used to call Exception
Replay internally Exception Debugging, thus some of the configs held
this name. This PR renamed those leftovers to Exception Replay,
including the enablement config of `DD_EXCEPTION_REPLAY_ENABLED`.
[Introduced a PR to
`dd-go`](https://github.com/DataDog/dd-go/pull/146180) too where these
configs were added to the `config_norm_rules.json` file.

Laying the groundwork for integration testing of Exception Replay.

The testing infra bootstraps the web app, queries via reflection all the
tests (classes inheriting from `IRun`/`IAsyncRun` and decorated with
`ExceptionReplayTestData` attribute) and list them. Upon executing a
test, a request will hit an endpoint of `RunTest` with the name of the
test to run (FQN of the class name). The crafted test must throw an
exception to be considered valid.
For a more complex test scenarios, more endpoints could be introduced.

Every test runs in 4 flavors:
- With Exception Replay while Dynamic Instrumentation is **enabled**,
default stack trace capturing limit.
- With Exception Replay while Dynamic Instrumentation is **enabled**,
full stack trace capturing limit.
- With Exception Replay while Dynamic Instrumentation is **disabled**,
default stack trace capturing limit.
- With Exception Replay while Dynamic Instrumentation is **disabled**,
full stack trace capturing limit.

This whole PR 🤓. I've added two tests that utilize the infra:
- `ExceptionWithNonSupportedFramesTest`
- `RecursiveExceptionTest`

Fixes DEBUG-2681, DEBUG-2732, DEBUG-1642.
@GreenMatan
GreenMatan force-pushed the andrew/matang/exception-replay-testing-suite-v2 branch from 5c41798 to a6842de Compare September 2, 2024 09:33
@andrewlock
andrewlock merged commit 4a31b32 into release/2.x Sep 2, 2024
@andrewlock
andrewlock deleted the andrew/matang/exception-replay-testing-suite-v2 branch September 2, 2024 11:02
@github-actions github-actions Bot added this to the vNext-v2 milestone Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:debugger area:tests unit tests, integration tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants