Skip to content

Commit 12bf220

Browse files
authored
JitStatsDiagnoser (#2243)
* change JitDiagnoser base class to be able to specify TStats type * implement JitStatsDiagnoser * make it possible to use existing JIT diagnosers from command line args
1 parent 0cf1850 commit 12bf220

File tree

5 files changed

+120
-3
lines changed

5 files changed

+120
-3
lines changed

src/BenchmarkDotNet.Diagnostics.Windows/InliningDiagnoser.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using System.Collections.Generic;
22
using System.Linq;
3+
using BenchmarkDotNet.Diagnosers;
34
using BenchmarkDotNet.Loggers;
45
using BenchmarkDotNet.Running;
56
using Microsoft.Diagnostics.Tracing.Session;
67

78
namespace BenchmarkDotNet.Diagnostics.Windows
89
{
9-
public class InliningDiagnoser : JitDiagnoser
10+
public class InliningDiagnoser : JitDiagnoser<object>, IProfiler
1011
{
1112
private static readonly string LogSeparator = new string('-', 20);
1213

@@ -43,6 +44,8 @@ public InliningDiagnoser(bool logFailuresOnly = true, string[] allowedNamespaces
4344

4445
public override IEnumerable<string> Ids => new[] { nameof(InliningDiagnoser) };
4546

47+
public string ShortName => "inlining";
48+
4649
protected override void AttachToEvents(TraceEventSession session, BenchmarkCase benchmarkCase)
4750
{
4851
defaultNamespace = benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.Namespace;

src/BenchmarkDotNet.Diagnostics.Windows/JitDiagnoser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace BenchmarkDotNet.Diagnostics.Windows
1313
{
14-
public abstract class JitDiagnoser : EtwDiagnoser<object>, IDiagnoser
14+
public abstract class JitDiagnoser<TStats> : EtwDiagnoser<TStats>, IDiagnoser where TStats : new()
1515
{
1616
protected override ulong EventType => (ulong)ClrTraceEventParser.Keywords.JitTracing;
1717

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System.Collections.Generic;
2+
using System.Threading;
3+
using BenchmarkDotNet.Columns;
4+
using BenchmarkDotNet.Diagnosers;
5+
using BenchmarkDotNet.Reports;
6+
using BenchmarkDotNet.Running;
7+
using Microsoft.Diagnostics.Tracing.Parsers;
8+
using Microsoft.Diagnostics.Tracing.Session;
9+
10+
namespace BenchmarkDotNet.Diagnostics.Windows
11+
{
12+
public class JitStatsDiagnoser : JitDiagnoser<JitStats>, IProfiler
13+
{
14+
public override IEnumerable<string> Ids => new[] { nameof(JitStatsDiagnoser) };
15+
16+
public string ShortName => "jit";
17+
18+
protected override ulong EventType => (ulong)(ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.Compilation);
19+
20+
public override IEnumerable<Metric> ProcessResults(DiagnoserResults results)
21+
{
22+
if (BenchmarkToProcess.TryGetValue(results.BenchmarkCase, out int pid))
23+
{
24+
if (StatsPerProcess.TryGetValue(pid, out JitStats jitStats))
25+
{
26+
yield return new Metric(MethodsJittedDescriptor.Instance, jitStats.MethodsCompiled);
27+
yield return new Metric(MethodsTieredDescriptor.Instance, jitStats.MethodsTiered);
28+
yield return new Metric(JitAllocatedMemoryDescriptor.Instance, jitStats.MemoryAllocated);
29+
}
30+
}
31+
}
32+
33+
protected override void AttachToEvents(TraceEventSession session, BenchmarkCase benchmarkCase)
34+
{
35+
session.Source.Clr.MethodJittingStarted += methodData =>
36+
{
37+
if (StatsPerProcess.TryGetValue(methodData.ProcessID, out JitStats jitStats))
38+
{
39+
Interlocked.Increment(ref jitStats.MethodsCompiled);
40+
}
41+
};
42+
43+
session.Source.Clr.MethodMemoryAllocatedForJitCode += memoryAllocated =>
44+
{
45+
if (StatsPerProcess.TryGetValue(memoryAllocated.ProcessID, out JitStats jitStats))
46+
{
47+
Interlocked.Add(ref jitStats.MemoryAllocated, memoryAllocated.AllocatedSizeForJitCode);
48+
}
49+
};
50+
51+
session.Source.Clr.TieredCompilationBackgroundJitStart += tieredData =>
52+
{
53+
if (StatsPerProcess.TryGetValue(tieredData.ProcessID, out JitStats jitStats))
54+
{
55+
Interlocked.Increment(ref jitStats.MethodsTiered);
56+
}
57+
};
58+
}
59+
60+
private sealed class MethodsJittedDescriptor : IMetricDescriptor
61+
{
62+
internal static readonly MethodsJittedDescriptor Instance = new ();
63+
64+
public string Id => nameof(MethodsJittedDescriptor);
65+
public string DisplayName => "Methods JITted";
66+
public string Legend => "Total number of methods JITted during entire benchmark execution (including warmup).";
67+
public bool TheGreaterTheBetter => false;
68+
public string NumberFormat => "N0";
69+
public UnitType UnitType => UnitType.Dimensionless;
70+
public string Unit => "Count";
71+
public int PriorityInCategory => 0;
72+
}
73+
74+
private sealed class MethodsTieredDescriptor : IMetricDescriptor
75+
{
76+
internal static readonly MethodsTieredDescriptor Instance = new ();
77+
78+
public string Id => nameof(MethodsTieredDescriptor);
79+
public string DisplayName => "Methods Tiered";
80+
public string Legend => "Total number of methods re-compiled by Tiered JIT during entire benchmark execution (including warmup).";
81+
public bool TheGreaterTheBetter => false;
82+
public string NumberFormat => "N0";
83+
public UnitType UnitType => UnitType.Dimensionless;
84+
public string Unit => "Count";
85+
public int PriorityInCategory => 0;
86+
}
87+
88+
private sealed class JitAllocatedMemoryDescriptor : IMetricDescriptor
89+
{
90+
internal static readonly JitAllocatedMemoryDescriptor Instance = new ();
91+
92+
public string Id => nameof(JitAllocatedMemoryDescriptor);
93+
public string DisplayName => "JIT allocated memory";
94+
public string Legend => "Total memory allocated by the JIT during entire benchmark execution (including warmup).";
95+
public bool TheGreaterTheBetter => false;
96+
public string NumberFormat => "N0";
97+
public UnitType UnitType => UnitType.Size;
98+
public string Unit => SizeUnit.B.Name;
99+
public int PriorityInCategory => 0;
100+
}
101+
}
102+
103+
public sealed class JitStats
104+
{
105+
public long MethodsCompiled;
106+
public long MethodsTiered;
107+
public long MemoryAllocated;
108+
}
109+
}

src/BenchmarkDotNet.Diagnostics.Windows/TailCallDiagnoser.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
using BenchmarkDotNet.Running;
33
using Microsoft.Diagnostics.Tracing.Session;
44
using BenchmarkDotNet.Loggers;
5+
using BenchmarkDotNet.Diagnosers;
56

67
namespace BenchmarkDotNet.Diagnostics.Windows
78
{
89
/// <summary>
910
/// See <see href="https://blogs.msdn.microsoft.com/clrcodegeneration/2009/05/11/jit-etw-tracing-in-net-framework-4/">MSDN blog post about JIT tracing events</see>
1011
/// and <see href="https://georgeplotnikov.github.io/articles/tale-tail-call-dotnet">detailed blog post by George Plotnikov</see> for more info
1112
/// </summary>
12-
public class TailCallDiagnoser : JitDiagnoser
13+
public class TailCallDiagnoser : JitDiagnoser<object>, IProfiler
1314
{
1415
private static readonly string LogSeparator = new string('-', 20);
1516

@@ -32,6 +33,8 @@ public TailCallDiagnoser(bool logFailuresOnly = true, bool filterByNamespace = t
3233

3334
public override IEnumerable<string> Ids => new[] { nameof(TailCallDiagnoser) };
3435

36+
public string ShortName => "tail";
37+
3538
protected override void AttachToEvents(TraceEventSession traceEventSession, BenchmarkCase benchmarkCase)
3639
{
3740
expectedNamespace = benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.Namespace ?? benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.FullName;

src/BenchmarkDotNet/Diagnosers/DiagnosersLoader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ private static IDiagnoser[] LoadWindowsDiagnosers()
7373
return new[]
7474
{
7575
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.InliningDiagnoser"),
76+
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.TailCallDiagnoser"),
77+
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.JitStatsDiagnoser"),
7678
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.EtwProfiler"),
7779
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.ConcurrencyVisualizerProfiler"),
7880
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.NativeMemoryProfiler")

0 commit comments

Comments
 (0)