in Microsoft.Diagnostics.Tracing/TraceEvent/TraceEvent/21_ObserveJitEvents.cs [26:110]
public static void Run()
{
Out.WriteLine("******************** ObserveJitEvents DEMO ********************");
Out.WriteLine("This program Demos using the reactive framework (IObservable) to monitor");
Out.WriteLine(".NET Runtime JIT compiler events.");
Out.WriteLine();
Out.WriteLine("This program shows how you can use the reactive framework to find pairs");
Out.WriteLine("of related events (in this the JIT start and stop events) and use them");
Out.WriteLine("to calculate values (in this case the time spent JIT compiling. ");
Out.WriteLine();
Out.WriteLine("The program also shows how to create on the fly aggregate statistics using");
Out.WriteLine("the reactive framework. ");
Out.WriteLine();
Out.WriteLine("The program will print a line every time a .NET method is JIT compiled");
Out.WriteLine("in any process on the machine and will print stats every 8 methods.");
Out.WriteLine();
Out.WriteLine("Start a .NET Program while the monitoring is active to see the JIT events.");
Out.WriteLine();
if (TraceEventSession.IsElevated() != true)
{
Out.WriteLine("Must be elevated (Admin) to run this method.");
Debugger.Break();
return;
}
var monitoringTimeSec = 10;
Out.WriteLine("The monitor will run for a maximum of {0} seconds", monitoringTimeSec);
Out.WriteLine("Press Ctrl-C to stop monitoring early.");
// create a real time user mode session
using (var userSession = new TraceEventSession("ObserveJitEvents1"))
{
// Set up Ctrl-C to stop both user mode and kernel mode sessions
SetupCtrlCHandler(() => { if (userSession != null) userSession.Stop(); });
// enable the CLR JIT compiler events.
userSession.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)(ClrTraceEventParser.Keywords.Default));
// Get the stream of starts.
IObservable<MethodJittingStartedTraceData> jitStartStream = userSession.Source.Clr.Observe<MethodJittingStartedTraceData>("Method/JittingStarted");
// And the stream of ends.
IObservable<MethodLoadUnloadVerboseTraceData> jitEndStream = userSession.Source.Clr.Observe<MethodLoadUnloadVerboseTraceData>("Method/LoadVerbose");
// Compute the stream of matched-up pairs, and for each create a tuple of the start event and the time between the pair of events.
// Note that the 'Take(1)' is pretty important because a nested 'from' statement logically creates the 'cross product' of a two streams
// In this case the stream of starts and the stream of ends). Because we filter this stream only to matching entities and then only
// take the first entry, we stop waiting. Thus we only 'remember' those 'starts' that are not yet matched, which is very important
// for efficiency. Note that any 'lost' end events will never be matched and will accumulate over time, slowing things down.
// We should put a time window on it as well to 'forget' old start events.
var jitTimes =
from start in jitStartStream
from end in jitEndStream.Where(e => start.MethodID == e.MethodID && start.ProcessID == e.ProcessID).Take(1)
select new
{
Name = GetName(start),
ProcessID = start.ProcessID,
JitTIme = end.TimeStampRelativeMSec - start.TimeStampRelativeMSec
};
// Create a stream of just the JIT times and compute statistics every 8 methods that are JIT compiled.
IObservable<Statistics> jitStats = ComputeRunningStats(jitTimes, jitData => jitData.JitTIme, windowSize: 8);
// Print every time you compile a method
jitTimes.Subscribe(onNext: jitData => Out.WriteLine("JIT_TIME: {0,7:f2} PROC: {1,10} METHOD: {2}", jitData.JitTIme, GetProcessName(jitData.ProcessID), jitData.Name));
// Also output the statistics.
jitStats.Subscribe(onNext: Out.WriteLine); // print some aggregation stats
// for debugging purposes to see any events that entered by were not handled by any parser. These can be bugs.
// IObservable<TraceEvent> unhandledEventStream = userSession.Source.ObserveUnhandled();
// unhandledEventStream.Subscribe(onNext: ev => Out.WriteLine("UNHANDLED : PID: {0,5} {1}/{2} ", ev.ProcessID, ev.ProviderName, ev.EventName));
// Set up a timer to stop processing after monitoringTimeSec
IObservable<long> timer = Observable.Timer(new TimeSpan(0, 0, monitoringTimeSec));
timer.Subscribe(delegate
{
Out.WriteLine("Stopped after {0} sec", monitoringTimeSec);
userSession.Stop();
});
// OK we are all set up, time to listen for events and pass them to the observers.
userSession.Source.Process();
}
}