private static void RealTimeSession() { if (options.ParsedClrKeywords == 0 && options.ParsedKernelKeywords == KernelTraceEventParser.Keywords.None && options.OtherProviders.Count == 0) { Bail("No events to collect"); } Console.CancelKeyPress += (_, __) => CloseSession(); if (options.DurationInSeconds > 0) { Task.Delay(TimeSpan.FromSeconds(options.DurationInSeconds)) .ContinueWith(_ => CloseSession()); } using (session = new TraceEventSession("etrace-realtime-session")) { if (options.ParsedKernelKeywords != KernelTraceEventParser.Keywords.None) { session.EnableKernelProvider(options.ParsedKernelKeywords); } if (options.ParsedClrKeywords != 0) { session.EnableProvider(ClrTraceEventParser.ProviderGuid, matchAnyKeywords: (ulong)options.ParsedClrKeywords); } if (options.OtherProviders.Any()) { foreach (var provider in options.OtherProviders) { Guid guid; if (Guid.TryParse(provider, out guid)) { session.EnableProvider(Guid.Parse(provider)); } else { guid = TraceEventProviders.GetProviderGuidByName(provider); if (guid != Guid.Empty) { session.EnableProvider(guid); } } } } if (options.IsOutFile) { outRelogger = new ETWReloggerTraceEventSource(session.SessionName, TraceEventSourceType.Session, options.OutFile); isOutReloggerSet = true; ProcessTrace(outRelogger); } else { ProcessTrace(session.Source); } } }
protected PerformanceTestContext(TraceEventDispatcher source) { _source = source; _relogger = source as ETWReloggerTraceEventSource; IsWriteEnabled = _relogger != null; if (IsWriteEnabled) { _relogger.Dynamic.All += WriteEvent; _relogger.Kernel.All += WriteEvent; _relogger.Clr.All += WriteEvent; } }
/// <summary> /// This routine shows how to use ETWReloggerTraceEventSource take a ETL file (inputFileName) /// and filter out events to form another ETL file (outputFileName). /// /// For this example we filter out all events that are not GCAllocationTicks /// </summary> private static void FilterData(string inputFileName, string outFileName) { // Open the input file and output file. You will then get a callback on every input event, // and if you call 'WriteEvent' you can copy it to output file. // In our example we only copy large object using (var relogger = new ETWReloggerTraceEventSource(inputFileName, outFileName)) { // Here we register callbacks for data we are interested in and further filter by. // In this case we keep the image load events for DLL with 'clr' in their name. relogger.Kernel.ImageGroup += delegate(ImageLoadTraceData data) { if (0 <= data.FileName.IndexOf("clr", StringComparison.OrdinalIgnoreCase)) { relogger.WriteEvent(data); } }; // Keep all the process start events relogger.Kernel.ProcessStart += delegate(ProcessTraceData data) { relogger.WriteEvent(data); }; // Keep GC Start and stop events. This can be done more efficiently if you // use multiple callbacks, but this technique may be easier if the events are // not known at compile time. relogger.Clr.All += delegate(TraceEvent data) { if (data.EventName == "GC/Start" || data.EventName == "GC/Stop") { relogger.WriteEvent(data); } }; #if false // Turn on to get debugging on unhandled events. relogger.UnhandledEvents += delegate(TraceEvent data) { Console.WriteLine("Unknown Event " + data); }; #endif relogger.Process(); } }
/// <summary> /// This routine shows how to use ETWReloggerTraceEventSource take a ETL file (inputFileName) /// and filter out events to form another ETL file (outputFileName). /// /// For this example we filter out all events that are not GCAllocationTicks /// </summary> private static void FilterData(string inputFileName, string outFileName) { // Open the input file and output file. You will then get a callback on every input event, // and if you call 'WriteEvent' you can copy it to output file. // In our example we only copy large object using (var relogger = new ETWReloggerTraceEventSource(inputFileName, outFileName)) { // Here we register callbacks for data we are interested in and further filter by. // In this case we keep the image load events for DLL with 'clr' in their name. relogger.Kernel.ImageGroup += delegate(ImageLoadTraceData data) { if (0 <= data.FileName.IndexOf("clr", StringComparison.OrdinalIgnoreCase)) relogger.WriteEvent(data); }; // Keep all the process start events relogger.Kernel.ProcessStart += delegate(ProcessTraceData data) { relogger.WriteEvent(data); }; // Keep GC Start and stop events. This can be done more efficiently if you // use multiple callbacks, but this technique may be easier if the events are // not known at compile time. relogger.Clr.All += delegate(TraceEvent data) { if (data.EventName == "GC/Start" || data.EventName == "GC/Stop") relogger.WriteEvent(data); }; #if false // Turn on to get debugging on unhandled events. relogger.UnhandledEvents += delegate(TraceEvent data) { Console.WriteLine("Unknown Event " + data); }; #endif relogger.Process(); } }
public static void Run() { int monitoringTimeSec = 10; if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62) { Out.WriteLine("This demo only works on Win8 / Win 2012 an above)"); return; } // Today you have to be Admin to turn on ETW events (anyone can write ETW events). if (!(TraceEventSession.IsElevated() ?? false)) { Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process."); Debugger.Break(); return; } string outputFileName = "ReloggerMonitorOutput.etl"; if (File.Exists(outputFileName)) { File.Delete(outputFileName); } Out.WriteLine("******************** Simple Relogger DEMO ********************"); Out.WriteLine("This program shows how you can monitor an ETW stream in real time."); Out.WriteLine("And conditionally pass the events on to a ETL file"); Out.WriteLine("Ctrl-C will end earlier"); Out.WriteLine(); Out.WriteLine("Please run some managed code while collection is happening..."); Out.WriteLine(); // To listen to ETW events you need a session, which allows you to control which events will be produced // Note that it is the session and not the source that buffers events, and by default sessions will buffer // 64MB of events before dropping events. Thus even if you don't immediately connect up the source and // read the events you should not lose them. // // As mentioned below, sessions can outlive the process that created them. Thus you may need a way of // naming the session so that you can 'reconnect' to it from another process. This is what the name // is for. It can be anything, but it should be descriptive and unique. If you expect multiple versions // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix) // however this is dangerous because you can leave data collection on if the program ends unexpectedly. var sessionName = "SimpleMontitorSession"; Out.WriteLine("Creating a '{0}' session", sessionName); using (var session = new TraceEventSession(sessionName)) { // Enable the events we care about for the kernel in the kernel session // For this instant the session will buffer any incoming events. // This has to be first, and it will fail if you are not on Win8. session.EnableKernelProvider( KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread); // A relogger is a TraceEventSource and acts much like an ETWTraceEventSource, with extra Write APIS. // Thus you get a callback on any event you want. // Only things that you call 'WriteEvent' on will end up in the output file. var relogger = new ETWReloggerTraceEventSource(sessionName, TraceEventSourceType.Session, outputFileName); // Here we set up the callbacks we want in the output file. In this case all GC allocation Tick // events for 'String' as well as any ExceptionStart events. relogger.Clr.GCAllocationTick += delegate(GCAllocationTickTraceData data) { if (data.TypeName == "System.String") { relogger.WriteEvent(data); } }; relogger.Clr.ExceptionStart += delegate(ExceptionTraceData data) { relogger.WriteEvent(data); }; // We also keep the image load events for DLL with 'clr' in their name. relogger.Kernel.ImageGroup += delegate(ImageLoadTraceData data) { if (0 <= data.FileName.IndexOf("clr", StringComparison.OrdinalIgnoreCase)) { relogger.WriteEvent(data); } }; #if false // Turn on to get debugging on unhandled events. relogger.UnhandledEvents += delegate(TraceEvent data) { Console.WriteLine("Unknown Event " + data); }; #endif // Allow the test to be terminated with Ctrl-C cleanly. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); }; // Set up a timer to stop processing after monitoringTimeSec var timer = new Timer(delegate(object state) { Out.WriteLine("Stopped after {0} sec", monitoringTimeSec); session.Dispose(); }, null, monitoringTimeSec * 1000, Timeout.Infinite); // Turn on the events to the provider. In this case most CLR events Out.WriteLine("**** Turn on CLR Etw Providers. Run managed code to see events."); session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.Default); // go into a loop processing events can calling the callbacks. Because this is live data (not from a file) // processing never completes by itself, but only because someone called 'source.Dispose()'. Out.WriteLine("**** Start listening for events from the Microsoft-Demos-SimpleMonitor provider."); Out.WriteLine("The monitor will run for a maximum of {0} seconds. Run managed code for more output.", monitoringTimeSec); relogger.Process(); Out.WriteLine(); Out.WriteLine("Stopping the collection of events."); timer.Dispose(); // Turn off the timer. } Out.WriteLine("Monitoring complete, only certain CLR events put in the output file."); Out.WriteLine("The output ETL file: {0}", Path.GetFullPath(outputFileName)); Out.WriteLine(); if (!File.Exists(outputFileName)) { Out.WriteLine("Error: No output file was generated (did you run anything during the collection?"); return; } // Show what was actually produced in the filtered file. DataProcessing(outputFileName); }
public static void Run() { int monitoringTimeSec = 10; if (Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor < 62) { Out.WriteLine("This demo only works on Win8 / Win 2012 an above)"); return; } // Today you have to be Admin to turn on ETW events (anyone can write ETW events). if (!(TraceEventSession.IsElevated() ?? false)) { Out.WriteLine("To turn on ETW events you need to be Administrator, please run from an Admin process."); Debugger.Break(); return; } string outputFileName = "ReloggerMonitorOutput.etl"; if (File.Exists(outputFileName)) File.Delete(outputFileName); Out.WriteLine("******************** Simple Relogger DEMO ********************"); Out.WriteLine("This program shows how you can monitor an ETW stream in real time."); Out.WriteLine("And conditionally pass the events on to a ETL file"); Out.WriteLine("Ctrl-C will end earlier"); Out.WriteLine(); Out.WriteLine("Please run some managed code while collection is happening..."); Out.WriteLine(); // To listen to ETW events you need a session, which allows you to control which events will be produced // Note that it is the session and not the source that buffers events, and by default sessions will buffer // 64MB of events before dropping events. Thus even if you don't immediately connect up the source and // read the events you should not lose them. // // As mentioned below, sessions can outlive the process that created them. Thus you may need a way of // naming the session so that you can 'reconnect' to it from another process. This is what the name // is for. It can be anything, but it should be descriptive and unique. If you expect multiple versions // of your program to run simultaneously, you need to generate unique names (e.g. add a process ID suffix) // however this is dangerous because you can leave data collection on if the program ends unexpectedly. var sessionName = "SimpleMontitorSession"; Out.WriteLine("Creating a '{0}' session", sessionName); using (var session = new TraceEventSession(sessionName)) { // Enable the events we care about for the kernel in the kernel session // For this instant the session will buffer any incoming events. // This has to be first, and it will fail if you are not on Win8. session.EnableKernelProvider( KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread); // A relogger is a TraceEventSource and acts much like an ETWTraceEventSource, with extra Write APIS. // Thus you get a callback on any event you want. // Only things that you call 'WriteEvent' on will end up in the output file. var relogger = new ETWReloggerTraceEventSource(sessionName, TraceEventSourceType.Session, outputFileName); // Here we set up the callbacks we want in the output file. In this case all GC allocation Tick // events for 'String' as well as any ExceptionStart events. relogger.Clr.GCAllocationTick += delegate(GCAllocationTickTraceData data) { if (data.TypeName == "System.String") relogger.WriteEvent(data); }; relogger.Clr.ExceptionStart += delegate(ExceptionTraceData data) { relogger.WriteEvent(data); }; // We also keep the image load events for DLL with 'clr' in their name. relogger.Kernel.ImageGroup += delegate(ImageLoadTraceData data) { if (0 <= data.FileName.IndexOf("clr", StringComparison.OrdinalIgnoreCase)) relogger.WriteEvent(data); }; #if false // Turn on to get debugging on unhandled events. relogger.UnhandledEvents += delegate(TraceEvent data) { Console.WriteLine("Unknown Event " + data); }; #endif // Allow the test to be terminated with Ctrl-C cleanly. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { session.Dispose(); }; // Set up a timer to stop processing after monitoringTimeSec var timer = new Timer(delegate(object state) { Out.WriteLine("Stopped after {0} sec", monitoringTimeSec); session.Dispose(); }, null, monitoringTimeSec * 1000, Timeout.Infinite); // Turn on the events to the provider. In this case most CLR events Out.WriteLine("**** Turn on CLR Etw Providers. Run managed code to see events."); session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)ClrTraceEventParser.Keywords.Default); // go into a loop processing events can calling the callbacks. Because this is live data (not from a file) // processing never completes by itself, but only because someone called 'source.Dispose()'. Out.WriteLine("**** Start listening for events from the Microsoft-Demos-SimpleMonitor provider."); Out.WriteLine("The monitor will run for a maximum of {0} seconds. Run managed code for more output.", monitoringTimeSec); relogger.Process(); Out.WriteLine(); Out.WriteLine("Stopping the collection of events."); timer.Dispose(); // Turn off the timer. } Out.WriteLine("Monitoring complete, only certain CLR events put in the output file."); Out.WriteLine("The output ETL file: {0}", Path.GetFullPath(outputFileName)); Out.WriteLine(); if (!File.Exists(outputFileName)) { Out.WriteLine("Error: No output file was generated (did you run anything during the collection?"); return; } // Show what was actually produced in the filtered file. DataProcessing(outputFileName); }
static void Main(string[] args) { if (args.Count() < 3 || args.Count() > 4) { Console.WriteLine("\nUsage: ETWSplitter.exe <InputFile.etl> <OutputFile.etl> <#_of_Files> [compress]\n"); return; } string inputFileName = args[0]; string outFileName = args[1]; if (!File.Exists(inputFileName)) { Console.WriteLine("ERROR: Input file {0} was not found!", inputFileName); return; } if (inputFileName.Equals(outFileName, StringComparison.OrdinalIgnoreCase)) { Console.WriteLine("ERROR: Input file and output file have the same name!"); return; } if (outFileName.EndsWith(".etl", StringComparison.OrdinalIgnoreCase)) { outFileName = outFileName.Remove(outFileName.Length - 4); } if (!int.TryParse(args[2], out int numberOfFiles)) { Console.WriteLine("ERROR: {0} is not an integer!", args[2]); return; } if (numberOfFiles < 2 || numberOfFiles > 1024) { Console.WriteLine("ERROR: {0} is outside of range!", numberOfFiles); return; } bool compress = false; if (args.Count() > 3) { if (args[3].StartsWith("c", StringComparison.OrdinalIgnoreCase)) { compress = true; Console.WriteLine("Compression enabled."); } } if (compress == false) { Console.WriteLine("Compression disabled."); } Int64 totalNumberOfEvents = 0; using (var etwReader = new ETWTraceEventSource(inputFileName)) { etwReader.AllEvents += delegate(TraceEvent data) { Interlocked.Increment(ref totalNumberOfEvents); }; etwReader.Process(); } if (totalNumberOfEvents < 2) { Console.WriteLine("ERROR: Did not detect any ETW events in the input file!"); return; } Console.WriteLine("{0} total events found.", totalNumberOfEvents); Int64 numberOfEventsPerFile = totalNumberOfEvents / numberOfFiles; Console.WriteLine("Writing {0} files with {1} events each...", numberOfFiles, numberOfEventsPerFile); Int64 totalEventsWritten = 0; for (int fileNum = 0; fileNum < numberOfFiles; fileNum++) { Stopwatch fileTimer = new Stopwatch(); string splitFileName = outFileName + fileNum + ".etl"; Int64 thisFileStartIndex = numberOfEventsPerFile * fileNum; Int64 thisFileEventsWritten = 0; Int64 currentEvent = 0; fileTimer.Start(); Console.Write("{0}...", splitFileName); using (var relogger = new ETWReloggerTraceEventSource(inputFileName, splitFileName)) { if (compress) { relogger.OutputUsesCompressedFormat = true; } else { relogger.OutputUsesCompressedFormat = false; } relogger.AllEvents += delegate(TraceEvent data) { if ((currentEvent >= thisFileStartIndex) && (currentEvent < (thisFileStartIndex + numberOfEventsPerFile))) { relogger.WriteEvent(data); Interlocked.Increment(ref thisFileEventsWritten); Interlocked.Increment(ref totalEventsWritten); } Interlocked.Increment(ref currentEvent); }; relogger.Process(); }; fileTimer.Stop(); TimeSpan timeElapsed = fileTimer.Elapsed; Console.WriteLine(" Done in {0:00}h:{1:00}m:{2:00}s. Wrote: {3} Filesize: {4}MB", timeElapsed.Hours, timeElapsed.Minutes, timeElapsed.Seconds, thisFileEventsWritten, (new FileInfo(splitFileName).Length) / 1024 / 1024); } }
public override TestResult[] Execute(ITestMethod testMethod) { TestResult[] errorResults = ValidateElevated(testMethod); if (errorResults != null) { return(errorResults); } Exception signatureException = GetMethodSignatureException(testMethod); if (signatureException != null) { return(testMethod.CreateExceptionResult(signatureException)); } var runParameters = TestRunParameters.Read(); string logFolder = runParameters.LogFolder; bool shouldLog = !string.IsNullOrEmpty(logFolder); if (shouldLog) { try { logFolder = CreateLogFolder(logFolder, testMethod.TestMethodName); } catch (Exception e) { return(testMethod.CreateExceptionResult(e)); } } int iterations = runParameters.Iterations; var results = new TestResult[iterations]; for (int iteration = 1; iteration <= iterations; iteration++) { string sessionName = $"{testMethod.TestMethodName}-{iteration}"; using (var session = new TraceEventSession(sessionName)) { EnableKernelProviders(session, shouldLog); TraceEventDispatcher source; ZippedETLWriter writer = null; if (shouldLog) { string etlPath = Path.Combine(logFolder, $"Iteration{iteration}.etl"); source = new ETWReloggerTraceEventSource(sessionName, TraceEventSourceType.Session, etlPath); writer = new ZippedETLWriter(etlPath); } else { source = session.Source; } EnableProviders(session); PerformanceTestContext context = CreateContext(source); Task <TestResult> testTask = Task.Run(() => testMethod.Invoke(new object[] { context })); // This is a blocking call that in the case of ETWReloggerTraceEventSource, must be run on the same // thread as ETWReloggerTraceEventSource was created on. It will become unblocked when the // PerformanceTestContext calls StopProcessing on the source. source.Process(); TestResult result = testTask.Result; string displayName = testMethod.TestMethodName; if (iterations > 1) { displayName += $" [{iteration}/{iterations}]"; } result.DisplayName = displayName; session.Flush(); OnIterationEnded(context); context.LogScenarios(); context.LogMemoryDelta(); context.LogMessage($"{displayName} completed. {session.EventsLost} events lost."); context.WriteLogsToResult(result, writer); results[iteration - 1] = result; } } return(results); }