Skip to content

Commit ce90f40

Browse files
authored
Optimise StackTraceSnippet.Get (MiniProfiler#605)
* Remove RuntimeIdentifier This creates a self-contained executable, which BDN doesn't seem to support * Remove commented test code * Set up profiler per iteration If the benchmark is fast enough BDN will run enough operations per iteration that the accumulated CustomTimings will eat all memory. * Bench with stack trace vs without * Cache assembly & module names These are not (currently) cached in any meaningful way. Type & MethodInfo don't have the same problem.
1 parent 55f5ac2 commit ce90f40

File tree

4 files changed

+15
-14
lines changed

4 files changed

+15
-14
lines changed

benchmarks/MiniProfiler.Benchmarks/Benchmarks/CustomTimingBenchmarks.cs

+9-6
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,35 @@
44

55
namespace Benchmarks
66
{
7-
[SimpleJob(RuntimeMoniker.Net472)]
8-
[SimpleJob(RuntimeMoniker.Net50)]
7+
[SimpleJob(RuntimeMoniker.Net472, invocationCount: 50_000)]
8+
[SimpleJob(RuntimeMoniker.Net50, invocationCount: 50_000)]
99
[Config(typeof(Configs.Memory))]
1010
public class CustomTimingBenchmarks
1111
{
1212
private MiniProfiler Profiler;
1313

14-
[GlobalSetup]
14+
[Params(true, false)]
15+
public bool IncludeStackTrace { get; set; }
16+
17+
[IterationSetup]
1518
public void SetupData()
1619
{
1720
Profiler = new MiniProfiler("Test", new MiniProfilerBenchmarkOptions());
1821
}
1922

2023
[Benchmark(Description = "Creation of a standalone CustomTiming")]
21-
public CustomTiming Creation() => new CustomTiming(Profiler, "Test");
24+
public CustomTiming Creation() => new CustomTiming(Profiler, "Test", includeStackTrace: IncludeStackTrace);
2225

2326
[Benchmark(Description = "Creation a CustomTiming via MiniProfiler")]
2427
public void AddingToMiniProfiler()
2528
{
26-
Profiler.CustomTiming("Test", "MyCategory");
29+
Profiler.CustomTiming("Test", "MyCategory", includeStackTrace: IncludeStackTrace);
2730
}
2831

2932
[Benchmark(Description = "Using a CustomTiming with MiniProfiler")]
3033
public void UsingWithMiniProfiler()
3134
{
32-
using (Profiler.CustomTiming("Test", "MyCategory"))
35+
using (Profiler.CustomTiming("Test", "MyCategory", includeStackTrace: IncludeStackTrace))
3336
{
3437
// Trigger the .Dispose()
3538
}

benchmarks/MiniProfiler.Benchmarks/MiniProfiler.Benchmarks.csproj

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
<RootNamespace>Benchmarks</RootNamespace>
77
<Configuration>Release</Configuration>
88
<TargetFrameworks>net472;net5.0</TargetFrameworks>
9-
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
109
<PlatformTarget>AnyCPU</PlatformTarget>
1110
<SignAssembly>false</SignAssembly>
1211
<LangVersion>9</LangVersion>

benchmarks/MiniProfiler.Benchmarks/Program.cs

-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ public static class Program
77
{
88
public static void Main(string[] args)
99
{
10-
//var creation = new Benchmarks.CreationBenchmarks();
11-
//while (true)
12-
//{
13-
// creation.StartStopProfiler();
14-
//}
1510
BenchmarkSwitcher.FromAssembly(typeof(Program).GetTypeInfo().Assembly).Run(args);
1611
}
1712
}

src/MiniProfiler.Shared/Helpers/StackTraceSnippet.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using StackExchange.Profiling.Internal;
22
using System;
3+
using System.Collections.Concurrent;
34
using System.Collections.Generic;
45
using System.Diagnostics;
56
using System.Net;
@@ -14,6 +15,9 @@ namespace StackExchange.Profiling.Helpers
1415
/// </summary>
1516
public static class StackTraceSnippet
1617
{
18+
private static readonly ConcurrentDictionary<Assembly, string> AssemblyNames = new();
19+
private static readonly ConcurrentDictionary<Module, string> ModuleNames = new();
20+
1721
/// <summary>
1822
/// Gets the current formatted and filtered stack trace.
1923
/// </summary>
@@ -56,14 +60,14 @@ bool ShouldExcludeType(MethodBase method)
5660
if (stackLength >= options.StackMaxLength
5761
// ASP.NET: no need to continue up the chain
5862
|| method.Name == "System.Web.HttpApplication.IExecutionStep.Execute"
59-
|| (method.Module.Name == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor"))
63+
|| (ModuleNames.GetOrAdd(method.Module, m => m.Name) == "Microsoft.AspNetCore.Mvc.Core.dll" && method.DeclaringType.Name == "ObjectMethodExecutor"))
6064
{
6165
frames[i] = null;
6266
startFrame = i < 0 ? 0 : i - 1;
6367
break;
6468
}
6569
else if (ShouldExcludeType(method)
66-
|| options.ExcludedAssemblies.Contains(method.Module.Assembly.GetName().Name)
70+
|| options.ExcludedAssemblies.Contains(AssemblyNames.GetOrAdd(method.Module.Assembly, a => a.GetName().Name))
6771
|| options.ExcludedMethods.Contains(method.Name))
6872
{
6973
frames[i] = null;

0 commit comments

Comments
 (0)