Suspect `-p ETW` is not enabling the CLR rundown provider
When there's a benchmark that spends substantial amounts of time in R2R code, neither PerfView or my own ETL parsing can resolve CPU samples down to the method level.
For example https://github.com/dotnet/runtime/issues/84264#issuecomment-1521994085.
Seems like we might see similar things on desktop with NGEN, though I have not tried this.
https://github.com/microsoft/perfview/blob/564309807cb280823377db4e6fc24a1aeae34a90/src/TraceEvent/Parsers/ClrTraceEventParser.cs#L13406-L13449
BDN is also not enabling the tiered compilation settings event, so PerfView is confused and thinks TieredCompilation is not enabled:
@brianrob wonder if you could take a look sometime. I can't get method load events for R2R methods no matter what I try.
I have cases where I want to see these events even if there are no samples to attribute to them (eg to prove a particular sequence of rejits was performed by tiered compilation).
Here's a sample app where the ETW config BDN will use is easy to modify:
using System;
using System.Buffers;
using BenchmarkDotNet;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Diagnostics.Windows;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Parsers.Clr;
using Microsoft.Diagnostics.Tracing.Session;
namespace System.Buffers.Tests
{
[GenericTypeArguments(typeof(byte))] // value type
[GenericTypeArguments(typeof(object))] // reference type
public class NonStandardArrayPoolTests<T>
{
private readonly ArrayPool<T> _createdPool = ArrayPool<T>.Create();
private const int Iterations = 100_000;
[Params(64)]
public int RentalSize;
[Params(false, true)]
public bool UseSharedPool { get; set; }
public ArrayPool<T> Pool => UseSharedPool ? ArrayPool<T>.Shared : _createdPool;
[Benchmark(OperationsPerInvoke = Iterations)]
public void RentNoReturn()
{
ArrayPool<T> pool = Pool;
for (int i = 0; i < Iterations; i++)
{
pool.Rent(RentalSize);
}
}
}
}
class Program
{
static void Main(string[] args)
{
var p = new (Guid providerGuid, TraceEventLevel providerLevel, ulong keywords, TraceEventProviderOptions options)[]
{
// following values come from xunit-performance, were selected by the .NET Runtime Team
(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose,
(ulong) (ClrTraceEventParser.Keywords.Exception
| ClrTraceEventParser.Keywords.StartEnumeration
| ClrTraceEventParser.Keywords.Jit
| ClrTraceEventParser.Keywords.Loader
| ClrTraceEventParser.Keywords.NGen),
new TraceEventProviderOptions { StacksEnabled = false }), // stacks are too expensive for our purposes
// following values come from xunit-performance, were selected by the .NET Runtime Team
// (
// ClrRundownTraceEventParser.ProviderGuid,
// // g,
// TraceEventLevel.Verbose,
// (ulong) (ClrRundownTraceEventParser.Keywords.StartEnumeration
// | ClrRundownTraceEventParser.Keywords.Loader
// // | ClrRundownTraceEventParser.Keywords.ForceEndRundown
// | ClrRundownTraceEventParser.Keywords.Jit
// | ClrRundownTraceEventParser.Keywords.NGen),
// new TraceEventProviderOptions { StacksEnabled = false }) // stacks are too expensive for our purposes
};
var ep = new EtwProfilerConfig(performExtraBenchmarksRun: false, providers: p);
BenchmarkSwitcher
.FromAssembly(typeof(Program).Assembly)
.Run(args,
DefaultConfig.Instance.AddDiagnoser(new EtwProfiler(ep))); // HERE
}
}
There should be quite a few R2R method loads here, in particular I am looking for various SpinWait methods.
@AndyAyersMS it looks like you're doing this right. A Method/LoadVerbose can be emitted during R2R method restore. However, it looks like this either never worked or was broken at some point. Debugging it, the call to MethodAndStartAddressToEECodeInfoPointer returns NULL. I suspect the issue is that the code hasn't been fully loaded yet, as I am able to get the R2R events to fire properly at rundown.
If this is something that would be useful to you, we probably need to file a bug in https://github.com/dotnet/runtime.