public static void Run()

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();
            }
        }