Skip to content

Commit

Permalink
JitStatsDiagnoser (#2243)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
adamsitnik authored Jan 12, 2023
1 parent 0cf1850 commit 12bf220
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 3 deletions.
5 changes: 4 additions & 1 deletion src/BenchmarkDotNet.Diagnostics.Windows/InliningDiagnoser.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using Microsoft.Diagnostics.Tracing.Session;

namespace BenchmarkDotNet.Diagnostics.Windows
{
public class InliningDiagnoser : JitDiagnoser
public class InliningDiagnoser : JitDiagnoser<object>, IProfiler
{
private static readonly string LogSeparator = new string('-', 20);

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

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

public string ShortName => "inlining";

protected override void AttachToEvents(TraceEventSession session, BenchmarkCase benchmarkCase)
{
defaultNamespace = benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.Namespace;
Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet.Diagnostics.Windows/JitDiagnoser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace BenchmarkDotNet.Diagnostics.Windows
{
public abstract class JitDiagnoser : EtwDiagnoser<object>, IDiagnoser
public abstract class JitDiagnoser<TStats> : EtwDiagnoser<TStats>, IDiagnoser where TStats : new()
{
protected override ulong EventType => (ulong)ClrTraceEventParser.Keywords.JitTracing;

Expand Down
109 changes: 109 additions & 0 deletions src/BenchmarkDotNet.Diagnostics.Windows/JitStatsDiagnoser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System.Collections.Generic;
using System.Threading;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;

namespace BenchmarkDotNet.Diagnostics.Windows
{
public class JitStatsDiagnoser : JitDiagnoser<JitStats>, IProfiler
{
public override IEnumerable<string> Ids => new[] { nameof(JitStatsDiagnoser) };

public string ShortName => "jit";

protected override ulong EventType => (ulong)(ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.Compilation);

public override IEnumerable<Metric> ProcessResults(DiagnoserResults results)
{
if (BenchmarkToProcess.TryGetValue(results.BenchmarkCase, out int pid))
{
if (StatsPerProcess.TryGetValue(pid, out JitStats jitStats))
{
yield return new Metric(MethodsJittedDescriptor.Instance, jitStats.MethodsCompiled);
yield return new Metric(MethodsTieredDescriptor.Instance, jitStats.MethodsTiered);
yield return new Metric(JitAllocatedMemoryDescriptor.Instance, jitStats.MemoryAllocated);
}
}
}

protected override void AttachToEvents(TraceEventSession session, BenchmarkCase benchmarkCase)
{
session.Source.Clr.MethodJittingStarted += methodData =>
{
if (StatsPerProcess.TryGetValue(methodData.ProcessID, out JitStats jitStats))
{
Interlocked.Increment(ref jitStats.MethodsCompiled);
}
};

session.Source.Clr.MethodMemoryAllocatedForJitCode += memoryAllocated =>
{
if (StatsPerProcess.TryGetValue(memoryAllocated.ProcessID, out JitStats jitStats))
{
Interlocked.Add(ref jitStats.MemoryAllocated, memoryAllocated.AllocatedSizeForJitCode);
}
};

session.Source.Clr.TieredCompilationBackgroundJitStart += tieredData =>
{
if (StatsPerProcess.TryGetValue(tieredData.ProcessID, out JitStats jitStats))
{
Interlocked.Increment(ref jitStats.MethodsTiered);
}
};
}

private sealed class MethodsJittedDescriptor : IMetricDescriptor
{
internal static readonly MethodsJittedDescriptor Instance = new ();

public string Id => nameof(MethodsJittedDescriptor);
public string DisplayName => "Methods JITted";
public string Legend => "Total number of methods JITted during entire benchmark execution (including warmup).";
public bool TheGreaterTheBetter => false;
public string NumberFormat => "N0";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public int PriorityInCategory => 0;
}

private sealed class MethodsTieredDescriptor : IMetricDescriptor
{
internal static readonly MethodsTieredDescriptor Instance = new ();

public string Id => nameof(MethodsTieredDescriptor);
public string DisplayName => "Methods Tiered";
public string Legend => "Total number of methods re-compiled by Tiered JIT during entire benchmark execution (including warmup).";
public bool TheGreaterTheBetter => false;
public string NumberFormat => "N0";
public UnitType UnitType => UnitType.Dimensionless;
public string Unit => "Count";
public int PriorityInCategory => 0;
}

private sealed class JitAllocatedMemoryDescriptor : IMetricDescriptor
{
internal static readonly JitAllocatedMemoryDescriptor Instance = new ();

public string Id => nameof(JitAllocatedMemoryDescriptor);
public string DisplayName => "JIT allocated memory";
public string Legend => "Total memory allocated by the JIT during entire benchmark execution (including warmup).";
public bool TheGreaterTheBetter => false;
public string NumberFormat => "N0";
public UnitType UnitType => UnitType.Size;
public string Unit => SizeUnit.B.Name;
public int PriorityInCategory => 0;
}
}

public sealed class JitStats
{
public long MethodsCompiled;
public long MethodsTiered;
public long MemoryAllocated;
}
}
5 changes: 4 additions & 1 deletion src/BenchmarkDotNet.Diagnostics.Windows/TailCallDiagnoser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
using BenchmarkDotNet.Running;
using Microsoft.Diagnostics.Tracing.Session;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Diagnosers;

namespace BenchmarkDotNet.Diagnostics.Windows
{
/// <summary>
/// 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>
/// and <see href="https://georgeplotnikov.github.io/articles/tale-tail-call-dotnet">detailed blog post by George Plotnikov</see> for more info
/// </summary>
public class TailCallDiagnoser : JitDiagnoser
public class TailCallDiagnoser : JitDiagnoser<object>, IProfiler
{
private static readonly string LogSeparator = new string('-', 20);

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

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

public string ShortName => "tail";

protected override void AttachToEvents(TraceEventSession traceEventSession, BenchmarkCase benchmarkCase)
{
expectedNamespace = benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.Namespace ?? benchmarkCase.Descriptor.WorkloadMethod.DeclaringType.FullName;
Expand Down
2 changes: 2 additions & 0 deletions src/BenchmarkDotNet/Diagnosers/DiagnosersLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ private static IDiagnoser[] LoadWindowsDiagnosers()
return new[]
{
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.InliningDiagnoser"),
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.TailCallDiagnoser"),
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.JitStatsDiagnoser"),
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.EtwProfiler"),
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.ConcurrencyVisualizerProfiler"),
CreateDiagnoser(diagnosticsAssembly, "BenchmarkDotNet.Diagnostics.Windows.NativeMemoryProfiler")
Expand Down

0 comments on commit 12bf220

Please sign in to comment.