Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions tracer/test/benchmarks/Benchmarks.Trace/ActivityBenchmark.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#nullable enable
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
Expand All @@ -25,13 +25,14 @@ namespace Benchmarks.Trace;
public class ActivityBenchmark
{
private const string SourceName = "BenchmarkSource";
private static readonly Datadog.Trace.Activity.DuckTypes.ActivitySource _duckSource;
private static readonly DateTime _startTime = DateTimeOffset.FromUnixTimeSeconds(0).UtcDateTime;
private static readonly DateTime _endTime = DateTimeOffset.FromUnixTimeSeconds(5).UtcDateTime;

private static readonly ActivitySource _source;
private Datadog.Trace.Activity.DuckTypes.ActivitySource _duckSource;
private ActivitySource _source;

static ActivityBenchmark()
[GlobalSetup]
public void GlobalSetup()
{
_source = new ActivitySource(SourceName);

Expand Down Expand Up @@ -59,7 +60,7 @@ public void StartStopWithChild()
handler.ActivityStopped(SourceName, parentMock);
}

private static Activity CreateActivity(Activity? parent = null)
private Activity CreateActivity(Activity? parent = null)
{
var activity = parent is null
? _source.CreateActivity("parent", System.Diagnostics.ActivityKind.Internal)
Expand Down
45 changes: 24 additions & 21 deletions tracer/test/benchmarks/Benchmarks.Trace/AgentWriterBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,18 @@ namespace Benchmarks.Trace
[MemoryDiagnoser]
[BenchmarkAgent1]
[BenchmarkCategory(Constants.TracerCategory)]

public class AgentWriterBenchmark
{
private const int SpanCount = 1000;

private static readonly IAgentWriter AgentWriter;
private static readonly ArraySegment<Span> EnrichedSpans;
static AgentWriterBenchmark()
{
var overrides = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.StartupDiagnosticLogEnabled, false.ToString() },
{ ConfigurationKeys.TraceEnabled, false.ToString() },
});
var sources = new CompositeConfigurationSource(new[] { overrides, GlobalConfigurationSource.Instance });
var settings = new TracerSettings(sources);

var api = new Api(new FakeApiRequestFactory(settings.Exporter.AgentUri), statsd: null, updateSampleRates: null, partialFlushEnabled: false);

AgentWriter = new AgentWriter(api, statsAggregator: null, statsd: null, automaticFlush: false);
private IAgentWriter _agentWriter;
private ArraySegment<Span> _enrichedSpans;

[GlobalSetup]
public void GlobalSetup()
{
// Create spans in GlobalSetup, not static constructor
// This ensures BenchmarkDotNet excludes allocation overhead from measurements
var enrichedSpans = new Span[SpanCount];
var now = DateTimeOffset.UtcNow;

Expand All @@ -46,10 +37,22 @@ static AgentWriterBenchmark()
enrichedSpans[i].SetMetric(Metrics.SamplingRuleDecision, 1.0);
}

EnrichedSpans = new ArraySegment<Span>(enrichedSpans);
_enrichedSpans = new ArraySegment<Span>(enrichedSpans);

var overrides = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.StartupDiagnosticLogEnabled, false.ToString() },
{ ConfigurationKeys.TraceEnabled, false.ToString() },
});
var sources = new CompositeConfigurationSource(new[] { overrides, GlobalConfigurationSource.Instance });
var settings = new TracerSettings(sources);

var api = new Api(new FakeApiRequestFactory(settings.Exporter.AgentUri), statsd: null, updateSampleRates: null, partialFlushEnabled: false);

_agentWriter = new AgentWriter(api, statsAggregator: null, statsd: null, automaticFlush: false);

// Run benchmarks once to reduce noise
new AgentWriterBenchmark().WriteAndFlushEnrichedTraces().GetAwaiter().GetResult();
// Warmup to reduce noise
WriteAndFlushEnrichedTraces().GetAwaiter().GetResult();
}

/// <summary>
Expand All @@ -58,8 +61,8 @@ static AgentWriterBenchmark()
[Benchmark]
public Task WriteAndFlushEnrichedTraces()
{
AgentWriter.WriteTrace(EnrichedSpans);
return AgentWriter.FlushTracesAsync();
_agentWriter.WriteTrace(_enrichedSpans);
return _agentWriter.FlushTracesAsync();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,23 @@ namespace Benchmarks.Trace.Asm
[IgnoreProfile]
public class AppSecBodyBenchmark
{
private static readonly Security _security;
private readonly ComplexModel _complexModel = new()
{
Age = 12,
Gender = "Female",
Name = "Tata",
LastName = "Toto",
Address = new Address { Number = 12, City = new City { Name = "Paris", Country = new Country { Name = "France", Continent = new Continent { Name = "Europe", Planet = new Planet { Name = "Earth" } } } }, IsHouse = false, NameStreet = "lorem ipsum dolor sit amet" },
Address2 = new Address { Number = 15, City = new City { Name = "Madrid", Country = new Country { Name = "Spain", Continent = new Continent { Name = "Europe", Planet = new Planet { Name = "Earth" } } } }, IsHouse = true, NameStreet = "lorem ipsum dolor sit amet" },
Dogs = new List<Dog> { new Dog { Name = "toto", Dogs = new List<Dog> { new Dog { Name = "titi" }, new Dog { Name = "titi" } } }, new Dog { Name = "toto", Dogs = new List<Dog> { new Dog { Name = "tata" }, new Dog { Name = "tata" } } }, new Dog { Name = "tata", Dogs = new List<Dog> { new Dog { Name = "titi" }, new Dog { Name = "titi" }, new Dog { Name = "tutu" } } } }
};

private readonly Props10String _props10 = ConstructionUtils.ConstructProps10String();
private readonly Props100String _props100 = ConstructionUtils.ConstructProps100String();
private readonly Props1000String _props1000 = ConstructionUtils.ConstructProps1000String();

private readonly Props10Rec _props10x3 = ConstructionUtils.ConstructProps10Rec(3);
private readonly Props10Rec _props10x6 = ConstructionUtils.ConstructProps10Rec(6);



private static HttpContext _httpContext;

static AppSecBodyBenchmark()
private Security _security;
private ComplexModel _complexModel;
private Props10String _props10;
private Props100String _props100;
private Props1000String _props1000;
private Props10Rec _props10x3;
private Props10Rec _props10x6;
private HttpContext _httpContext;

[GlobalSetup]
public void GlobalSetup()
{
AppSecBenchmarkUtils.SetupDummyAgent();
var dir = Directory.GetCurrentDirectory();
Environment.SetEnvironmentVariable("DD_APPSEC_ENABLED", "true");
_security = Security.Instance;

#if NETFRAMEWORK
var ms = new MemoryStream();
using var sw = new StreamWriter(ms);
Expand All @@ -66,6 +54,23 @@ static AppSecBodyBenchmark()
#else
_httpContext = new DefaultHttpContext();
#endif

_complexModel = new()
{
Age = 12,
Gender = "Female",
Name = "Tata",
LastName = "Toto",
Address = new Address { Number = 12, City = new City { Name = "Paris", Country = new Country { Name = "France", Continent = new Continent { Name = "Europe", Planet = new Planet { Name = "Earth" } } } }, IsHouse = false, NameStreet = "lorem ipsum dolor sit amet" },
Address2 = new Address { Number = 15, City = new City { Name = "Madrid", Country = new Country { Name = "Spain", Continent = new Continent { Name = "Europe", Planet = new Planet { Name = "Earth" } } } }, IsHouse = true, NameStreet = "lorem ipsum dolor sit amet" },
Dogs = new List<Dog> { new Dog { Name = "toto", Dogs = new List<Dog> { new Dog { Name = "titi" }, new Dog { Name = "titi" } } }, new Dog { Name = "toto", Dogs = new List<Dog> { new Dog { Name = "tata" }, new Dog { Name = "tata" } } }, new Dog { Name = "tata", Dogs = new List<Dog> { new Dog { Name = "titi" }, new Dog { Name = "titi" }, new Dog { Name = "tutu" } } } }
};

_props10 = ConstructionUtils.ConstructProps10String();
_props100 = ConstructionUtils.ConstructProps100String();
_props1000 = ConstructionUtils.ConstructProps1000String();
_props10x3 = ConstructionUtils.ConstructProps10Rec(3);
_props10x6 = ConstructionUtils.ConstructProps10Rec(6);
}

[Benchmark]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,18 @@ namespace Benchmarks.Trace.Asm;
[BenchmarkCategory(Constants.AppSecCategory)]
public class AppSecEncoderBenchmark
{
private static readonly Encoder _encoder;
private static readonly EncoderLegacy _encoderLegacy;
private static readonly NestedMap _args;
private Encoder _encoder;
private EncoderLegacy _encoderLegacy;
private NestedMap _args;

static AppSecEncoderBenchmark()
[GlobalSetup]
public void GlobalSetup()
{
AppSecBenchmarkUtils.SetupDummyAgent();
_encoder = new Encoder();
var wafLibraryInvoker = AppSecBenchmarkUtils.CreateWafLibraryInvoker();
_encoderLegacy = new EncoderLegacy(wafLibraryInvoker);

_args = MakeNestedMap(20);
}

Expand Down
45 changes: 30 additions & 15 deletions tracer/test/benchmarks/Benchmarks.Trace/Asm/AppSecWafBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ public class AppSecWafBenchmark
{
private const int TimeoutMicroSeconds = 1_000_000;

private static readonly Waf Waf;

private static readonly Dictionary<string, object> stage1 = MakeRealisticNestedMapStage1(false);
private static readonly Dictionary<string, object> stage1Attack = MakeRealisticNestedMapStage1(true);
private static readonly Dictionary<string, object> stage2 = MakeRealisticNestedMapStage2();
private static readonly Dictionary<string, object> stage3 = MakeRealisticNestedMapStage3();

static AppSecWafBenchmark()
private Waf _waf;
private Dictionary<string, object> _stage1;
private Dictionary<string, object> _stage1Attack;
private Dictionary<string, object> _stage2;
private Dictionary<string, object> _stage3;

[GlobalSetup]
public void GlobalSetup()
{
AppSecBenchmarkUtils.SetupDummyAgent();
var wafLibraryInvoker = AppSecBenchmarkUtils.CreateWafLibraryInvoker();
Expand All @@ -52,7 +52,22 @@ static AppSecWafBenchmark()
{
throw new ArgumentException($"Waf could not initialize, error message is: {initResult.ErrorMessage}");
}
Waf = initResult.Waf;
_waf = initResult.Waf;

_stage1 = MakeRealisticNestedMapStage1(false);
_stage1Attack = MakeRealisticNestedMapStage1(true);
_stage2 = MakeRealisticNestedMapStage2();
_stage3 = MakeRealisticNestedMapStage3();
}

[IterationSetup]
public void IterationSetup()
{
// Force GC to reduce variance from native memory interactions
// WAF library uses unmanaged memory with allocation patterns outside .NET GC control
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}

private static Dictionary<string, object> MakeRealisticNestedMapStage1(bool withAttack)
Expand Down Expand Up @@ -132,18 +147,18 @@ private static Dictionary<string, object> MakeRealisticNestedMapStage3()
[Benchmark]
public void RunWafRealisticBenchmark()
{
var context = Waf.CreateContext();
context!.Run(stage1, TimeoutMicroSeconds);
context!.Run(stage2, TimeoutMicroSeconds);
context!.Run(stage3, TimeoutMicroSeconds);
var context = _waf.CreateContext();
context!.Run(_stage1, TimeoutMicroSeconds);
context!.Run(_stage2, TimeoutMicroSeconds);
context!.Run(_stage3, TimeoutMicroSeconds);
context.Dispose();
}

[Benchmark]
public void RunWafRealisticBenchmarkWithAttack()
{
var context = Waf.CreateContext();
context!.Run(stage1Attack, TimeoutMicroSeconds);
var context = _waf.CreateContext();
context!.Run(_stage1Attack, TimeoutMicroSeconds);
context.Dispose();
}
}
18 changes: 12 additions & 6 deletions tracer/test/benchmarks/Benchmarks.Trace/AspNetCoreBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ namespace Benchmarks.Trace
[BenchmarkCategory(Constants.TracerCategory)]
public class AspNetCoreBenchmark
{
private static readonly HttpClient Client;
private HttpClient _client;

static AspNetCoreBenchmark()
[GlobalSetup]
public void GlobalSetup()
{
var settings = TracerSettings.Create(new() { { ConfigurationKeys.StartupDiagnosticLogEnabled, false } });

Expand All @@ -33,18 +34,18 @@ static AspNetCoreBenchmark()
.UseStartup<Startup>();

var testServer = new TestServer(builder);
Client = testServer.CreateClient();
_client = testServer.CreateClient();

Datadog.Trace.ClrProfiler.Instrumentation.Initialize();

var bench = new AspNetCoreBenchmark();
bench.SendRequest();
// Warmup to initialize middleware pipeline
SendRequest();
}

[Benchmark]
public string SendRequest()
{
return Client.GetStringAsync("/Home").GetAwaiter().GetResult();
return _client.GetStringAsync("/Home").GetAwaiter().GetResult();
}

private class Startup
Expand Down Expand Up @@ -96,6 +97,11 @@ namespace Benchmarks.Trace
[MemoryDiagnoser]
public class AspNetCoreBenchmark
{
[GlobalSetup]
public void GlobalSetup()
{
}

[Benchmark]
public string SendRequest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,14 @@ public class CIVisibilityProtocolWriterBenchmark
{
private const int SpanCount = 1000;

private static readonly IEventWriter EventWriter;
private static readonly ArraySegment<Span> EnrichedSpans;
private IEventWriter _eventWriter;
private ArraySegment<Span> _enrichedSpans;

static CIVisibilityProtocolWriterBenchmark()
[GlobalSetup]
public void GlobalSetup()
{
var overrides = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.StartupDiagnosticLogEnabled, false.ToString() },
{ ConfigurationKeys.TraceEnabled, false.ToString() },
});
var sources = new CompositeConfigurationSource(new[] { overrides, GlobalConfigurationSource.Instance });
var settings = new TestOptimizationSettings(sources, NullConfigurationTelemetry.Instance);

EventWriter = new CIVisibilityProtocolWriter(settings, new FakeCIVisibilityProtocolWriter());

// Create spans in GlobalSetup, not static constructor
// This ensures BenchmarkDotNet excludes allocation overhead from measurements
var enrichedSpans = new Span[SpanCount];
var now = DateTimeOffset.UtcNow;
for (var i = 0; i < SpanCount; i++)
Expand All @@ -41,10 +34,20 @@ static CIVisibilityProtocolWriterBenchmark()
enrichedSpans[i].SetMetric(Metrics.SamplingRuleDecision, 1.0);
}

EnrichedSpans = new ArraySegment<Span>(enrichedSpans);
_enrichedSpans = new ArraySegment<Span>(enrichedSpans);

var overrides = new NameValueConfigurationSource(new()
{
{ ConfigurationKeys.StartupDiagnosticLogEnabled, false.ToString() },
{ ConfigurationKeys.TraceEnabled, false.ToString() },
});
var sources = new CompositeConfigurationSource(new[] { overrides, GlobalConfigurationSource.Instance });
var settings = new TestOptimizationSettings(sources, NullConfigurationTelemetry.Instance);

_eventWriter = new CIVisibilityProtocolWriter(settings, new FakeCIVisibilityProtocolWriter());

// Run benchmarks once to reduce noise
new CIVisibilityProtocolWriterBenchmark().WriteAndFlushEnrichedTraces().GetAwaiter().GetResult();
// Warmup to reduce noise
WriteAndFlushEnrichedTraces().GetAwaiter().GetResult();
}

/// <summary>
Expand All @@ -53,8 +56,8 @@ static CIVisibilityProtocolWriterBenchmark()
[Benchmark]
public Task WriteAndFlushEnrichedTraces()
{
EventWriter.WriteTrace(EnrichedSpans);
return EventWriter.FlushTracesAsync();
_eventWriter.WriteTrace(_enrichedSpans);
return _eventWriter.FlushTracesAsync();
}

private class FakeCIVisibilityProtocolWriter : ICIVisibilityProtocolWriterSender
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ namespace Benchmarks.Trace;
[BenchmarkCategory(Constants.TracerCategory)]
public class CharSliceBenchmark
{
[IterationSetup]
public void Setup()
{
// Force GC to ensure clean state and reduce variance from GC timing
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}

[Benchmark]
public void OriginalCharSlice()
{
Expand Down
Loading
Loading