public void EnableKernelProvider(params TraceSessionManager.KernelKeyword[] keywords) { // Create keyword flags for windows events KernelTraceEventParser.Keywords flags = 0; foreach (var keyword in keywords) { flags |= kernelKeywords[keyword]; } bool enabled = false; try { enabled = KernelSession.EnableKernelProvider(flags); } catch (System.Runtime.InteropServices.COMException) { } finally { if (!enabled) { Console.WriteLine("Unable to enable kernel provider. Try freeing some memory."); Environment.Exit(1); } } }
public ETWCollector(KernelTraceEventParser.Keywords flags = TraceProcessFlags) { Session = new TraceEventSession("Optick"); Session.BufferSizeMB = 256; Session.EnableKernelProvider(flags); // Processes Session.Source.Kernel.ProcessStart += Kernel_ProcessStart; Session.Source.Kernel.ProcessStop += Kernel_ProcessStop; // Image Session.Source.Kernel.ImageLoad += Kernel_ImageLoad; // Threads Session.Source.Kernel.ThreadStart += Kernel_ThreadStart; Session.Source.Kernel.ThreadStop += Kernel_ThreadStop; // IO Session.Source.Kernel.FileIORead += Kernel_FileIORead; Session.Source.Kernel.FileIOWrite += Kernel_FileIOWrite; Session.Source.Kernel.FileIOOperationEnd += Kernel_FileIOOperationEnd; // SysCalls Session.Source.Kernel.PerfInfoSysClEnter += Kernel_PerfInfoSysClEnter; Session.Source.Kernel.PerfInfoSysClExit += Kernel_PerfInfoSysClExit; // Switch Contexts Session.Source.Kernel.ThreadCSwitch += Kernel_ThreadCSwitch; // Samples Session.Source.Kernel.StackWalkStack += Kernel_StackWalkStack; }
private void ParseEvent(string[] parts) { if (_provider == "kernel") { string keyword = parts[0]; KernelTraceEventParser.Keywords parsedKeyword; if (!Enum.TryParse(keyword, true, out parsedKeyword)) { throw new ArgumentException("Unrecognized kernel keyword: '" + keyword + "'."); } _kernelKeyword = parsedKeyword; } else if (_provider == "clr") { if (parts.Length != 2) { throw new ArgumentException("CLR event specification must contain a keyword and an event name."); } string keyword = parts[0]; string eventName = parts[1]; ClrTraceEventParser.Keywords parsedKeyword; if (!Enum.TryParse(keyword, true, out parsedKeyword)) { throw new ArgumentException("Unrecognized CLR keyword: '" + keyword + "'."); } _clrKeyword = parsedKeyword; _clrEventName = eventName.ToLower(); } }
/// <summary> /// Interface to enable kernel providers. /// </summary> /// <param name="flags">Specifies the particular kernel events of interest.</param> /// <param name="stackCapture">Specifies which events should have their stack traces captured when an event is logged.</param> public void EnableKernelProvider(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture) { if (TraceEventSession.EnableKernelProvider(flags, stackCapture)) { Debug.WriteLine("The session existed before and needed to be restarted."); } }
/// <summary> /// Observe Out-of-Process ETW Kernel TraceEvent. /// </summary> public static IObservable <TData> FromKernelTraceEvent <TData>(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture = KernelTraceEventParser.Keywords.None) where TData : TraceEvent { IConnectableObservable <TData> source; var session = new TraceEventSession("ObservableEventListenerFromKernelTraceEventSession." + Guid.NewGuid().ToString()); try { session.EnableKernelProvider(flags, stackCapture); source = session.Source.Kernel.Observe <TData>().Finally(() => session.Dispose()).Publish(); } catch { session.Dispose(); throw; } Task.Factory.StartNew(state => { using (session) { session.Source.Process(); } }, TaskCreationOptions.LongRunning); return(source.RefCount()); }
/// <summary> /// Observe Out-of-Process ETW Kernel TraceEvent. /// </summary> public static IObservable <TraceEvent> FromKernelTraceEvent(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture = KernelTraceEventParser.Keywords.None) { IConnectableObservable <TraceEvent> source; var session = new TraceEventSession("ObservableEventListenerFromKernelTraceEventSession." + Guid.NewGuid().ToString()); try { var guid = KernelTraceEventParser.ProviderGuid; session.EnableKernelProvider(flags, stackCapture); // needs enable before observe source = session.Source.Kernel.Observe((pName, eName) => EventFilterResponse.AcceptEvent) .Where(x => x.ProviderGuid == guid && x.EventName != ManifestEventName && x.ID != ManifestEventID) .Finally(() => session.Dispose()) .Publish(); } catch { session.Dispose(); throw; } Task.Factory.StartNew(state => { using (session) { session.Source.Process(); } }, TaskCreationOptions.LongRunning); return(source.RefCount()); }
/// <summary> /// Wire up parsing of kernel event data from the specified ETWTraceEventSource. /// </summary> /// <param name="eventSource">The ETWTraceEventSource from which to parse the data.</param> private void ParseKernelTraceEvents(ETWTraceEventSource eventSource) { if (m_kernelEvents == KernelTraceEventParser.Keywords.None) { return; } var kernelParser = new KernelTraceEventParser(eventSource); // iterate over each set bit, wiring up a callback to parse the data uint eventBits = (uint)m_kernelEvents; int bitPos = 0; while (eventBits > 0) { // cycle through until a set bit is found while ((((uint)eventBits) & (uint)(1 << bitPos)) == 0) { ++bitPos; Debug.Assert(bitPos < 32); } var bitVal = (uint)(1 << bitPos); // now strip it from eventBits and covert it to its enum value eventBits ^= bitVal; KernelTraceEventParser.Keywords kernelEvent = (KernelTraceEventParser.Keywords)bitVal; if ((kernelEvent & KernelTraceEventParser.Keywords.ImageLoad) == KernelTraceEventParser.Keywords.ImageLoad) { var modLoads = new EventDataListString <KernelPerfEvents>(KernelPerfEvents.ModuleLoad); modLoads.Values = new HashSet <string>(StringComparer.OrdinalIgnoreCase); kernelParser.ImageLoad += delegate(ImageLoadTraceData data) { if (string.Compare(data.ProcessName, m_process, true) == 0) { var modName = Path.GetFileName(data.FileName); if (!modLoads.Values.Contains(modName)) { modLoads.Values.Add(modName); } m_processFound = true; } }; m_aed.AddData(modLoads); } else { Console.WriteLine("WARNING: Kernel event {0} NYI for reporting.", kernelEvent); } } }
public void EnableKernelProvider(params TraceSessionManager.KernelKeyword[] keywords) { // Create keyword flags for windows events KernelTraceEventParser.Keywords flags = 0; foreach (var keyword in keywords) { flags |= kernelKeywords[keyword]; } KernelSession.EnableKernelProvider(flags); }
public TraceEventsReportGenerator(CommandLineOptions commandLineOptions) { if (!File.Exists(commandLineOptions.DataFile)) throw new FileNotFoundException("Couldn't find the specified data file.", commandLineOptions.DataFile); m_testName = commandLineOptions.TestName; m_etlFile = commandLineOptions.DataFile; m_process = commandLineOptions.ProcessName; m_clrEvents = commandLineOptions.ClrEvents.Events; m_kernelEvents = commandLineOptions.KernelEvents; }
public TraceEventsReportGenerator(CommandLineOptions commandLineOptions) { if (!File.Exists(commandLineOptions.DataFile)) { throw new FileNotFoundException("Couldn't find the specified data file.", commandLineOptions.DataFile); } m_testName = commandLineOptions.TestName; m_etlFile = commandLineOptions.DataFile; m_process = commandLineOptions.ProcessName; m_clrEvents = commandLineOptions.ClrEvents.Events; m_kernelEvents = commandLineOptions.KernelEvents; }
public void AddHandler(ITraceEventHandler handler) { if (traceSession.IsActive) { // live handler adding handler.SubscribeToSession(traceSession); } else { kernelFlags |= handler.RequiredKernelFlags; } eventHandlers.Add(handler); }
/// <summary> /// #EnableKernelProvider /// Enable the kernel provider for the session. If the session name is 'NT Kernel Session' then it /// operates on that. This can be used to manipuate the kernel session. If the name is not 'NT /// Kernel Session' AND it is a moduleFile based session, then it tries to approximate attaching the /// kernel session by creating another session logs to [basename].kernel.etl. There is support in /// ETWTraceEventSource for looking for these files automatically, which give a good illusion that /// you can have a session that has both kernel and user events turned on. /// <param name="flags"> /// Specifies the particular kernel events of interest</param> /// <param name="stackCapture"> /// Specifies which events should have their eventToStack traces captured too (VISTA only)</param> /// <returns>Returns true if the session had existed before and is now restarted</returns> /// </summary> public unsafe bool EnableKernelProvider(KernelTraceEventParser.Keywords flags, KernelTraceEventParser.Keywords stackCapture) { if (sessionName != KernelTraceEventParser.KernelSessionName) { if (kernelSession != null) { throw new Exception("A kernel session is already active."); } if (string.IsNullOrEmpty(FileName)) { throw new Exception("Cannot enable kernel events to a real time session unless it is named " + KernelTraceEventParser.KernelSessionName); } string kernelFileName = System.IO.Path.ChangeExtension(FileName, ".kernel.etl"); kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, kernelFileName); return(kernelSession.EnableKernelProvider(flags, stackCapture)); } if (sessionHandle != TraceEventNativeMethods.INVALID_HANDLE_VALUE) { throw new Exception("The kernel provider must be enabled as the only provider."); } properties.Wnode.Guid = KernelTraceEventParser.ProviderGuid; if (stackCapture != KernelTraceEventParser.Keywords.None) { throw new Exception("Stack trace capture only available on Windows 6 (VISTA) and above."); } KernelTraceEventParser.Keywords vistaOnlyFlags = KernelTraceEventParser.Keywords.ProcessCounters | KernelTraceEventParser.Keywords.ContextSwitch | KernelTraceEventParser.Keywords.Interrupt | KernelTraceEventParser.Keywords.DiskIOInit | KernelTraceEventParser.Keywords.Driver | KernelTraceEventParser.Keywords.Profile | KernelTraceEventParser.Keywords.FileIO | KernelTraceEventParser.Keywords.FileIOInit | KernelTraceEventParser.Keywords.Dispatcher | KernelTraceEventParser.Keywords.VirtualAlloc; KernelTraceEventParser.Keywords setVistaFlags = flags & vistaOnlyFlags; if (setVistaFlags != KernelTraceEventParser.Keywords.None) { throw new Exception("A Kernel Event Flags {" + setVistaFlags.ToString() + "} w specified that is not supported on Pre-VISTA OSes."); } properties.EnableFlags = (uint)flags; return(StartTrace()); }
public KernelTraceSessionAttribute(KernelTraceEventParser.Keywords KernelSessionKeywords = KernelTraceEventParser.Keywords.All, string[] acceptedEventProviderNames = null, string[] rejectedEventProviderNames = null, string[] acceptedEventNames = null, string[] rejectedEventNames = null, string[] inclusiveProcessNames = null, int[] includedEventIds = null, int[] excludedEventIds = null, bool includeOwnProcess = false) : base("kernel", typeof(KernelTraceEventParser), KernelTraceEventParser.KernelSessionName, TraceEventLevel.Verbose, acceptedEventProviderNames, rejectedEventProviderNames, acceptedEventNames, rejectedEventNames, inclusiveProcessNames, includedEventIds, excludedEventIds, includeOwnProcess) { this.KernelSessionKeywords = KernelSessionKeywords; }
private void SetupCommandLine(CommandLineParser parser) { // #CommandLineDefinitions parser.ParameterSetsWhereQualifiersMustBeFirst = new string[] { "run", "UserCommand" }; parser.NoDashOnParameterSets = true; parser.DefineOptionalQualifier("LogFile", ref LogFile, "Send messages to this file instead launching the GUI. Intended for batch scripts and other automation."); // These apply to start, collect and run parser.DefineOptionalQualifier("BufferSize", ref BufferSizeMB, "The size the buffers (in MB) the OS should use to store events waiting to be written to disk."); // TODO remove eventually. parser.DefineOptionalQualifier("Circular", ref CircularMB, "Do Circular logging with a file size in MB. Zero means non-circular."); // TODO remove eventually. parser.DefineOptionalQualifier("BufferSizeMB", ref BufferSizeMB, "The size the buffers (in MB) the OS should use to store events waiting to be written to disk."); parser.DefineOptionalQualifier("CircularMB", ref CircularMB, "Do Circular logging with a file size in MB. Zero means non-circular."); parser.DefineOptionalQualifier("InMemoryCircularBuffer", ref InMemoryCircularBuffer, "Keeps the circular buffer in memory until the session is stopped."); parser.DefineOptionalQualifier("StackCompression", ref StackCompression, "Use stack compression (only on Win 8+) to make collected file smaller."); parser.DefineOptionalQualifier("MaxCollectSec", ref MaxCollectSec, "Turn off collection (and kill the program if perfView started it) after this many seconds. Zero means no timeout."); parser.DefineOptionalQualifier("StopOnPerfCounter", ref StopOnPerfCounter, "This is of the form CATEGORY:COUNTERNAME:INSTANCE OP NUM where CATEGORY:COUNTERNAME:INSTANCE, identify " + "a performance counter (same as PerfMon), OP is either < or >, and NUM is a number. " + "When that condition is true then collection will stop. You can specify this qualifier more than once (logical OR). See 'Stop Trigger' in the users guide for more."); parser.DefineOptionalQualifier("StopOnEventLogMessage", ref StopOnEventLogMessage, "Stop when an event log message that matches the given (ignore case) regular expression is written to the Windows 'Application' event log. " + "You can specify a particular event log with the syntax eventLogName@RegExp. Can be specified more than once (logical OR)."); parser.DefineOptionalQualifier("StopOnEtwEvent", ref StopOnEtwEvent, "This is of the form PROVIDER/EVENTNAME;key1=value1;key2=value2... " + "This option is quite powerful, See the users guide for more details."); int StopOnRequestOverMsec = 0; int StopOnGCSuspendOverMSec = 0; // These are basically special cases of the /StopOnEtwEvent parser.DefineOptionalQualifier("StopOnRequestOverMsec", ref StopOnRequestOverMsec, "Trigger a stop of a collect command if there is any IIS request that is longer than the given number of MSec."); parser.DefineOptionalQualifier("StopOnGCOverMsec", ref StopOnGCOverMsec, "Trigger a stop of a collect command if there is a .NET Garbage Collection (GC) is longer than the given number of MSec."); parser.DefineOptionalQualifier("StopOnGCSuspendOverMSec", ref StopOnGCSuspendOverMSec, "Trigger a stop of a collect command if there is a .NET Garbage Collection (GC) where suspending for the GC took over the given number of MSec."); parser.DefineOptionalQualifier("StopOnBGCFinalPauseOverMsec", ref StopOnBGCFinalPauseOverMsec, "Trigger a stop of a collect command if there is a background .NET Garbage Collection (GC) whose final pause is longer than the given number of MSec. To work correctly, " + "this requires that heap survival and movement tracking is not enabled."); parser.DefineOptionalQualifier("StopOnAppFabricOverMsec", ref StopOnAppFabricOverMsec, "Trigger a stop of a collect command if there is a AppFabric request is longer than the given number of MSec."); parser.DefineOptionalQualifier("StopOnException", ref StopOnException, "Where the text is a regular expression that will be used to match the full name and message of the .NET Exception thrown." + "The empty string represents any exception."); parser.DefineOptionalQualifier("StopOnGen2GC", ref StopOnGen2GC, "This will stop on any non-background Gen2 GC from the given process (can be a process ID or a process Name (exe file name without path or extension) or * (any process)"); parser.DefineOptionalQualifier("Process", ref Process, "A process name (exe file name without directory or extension) or the Decimal Process ID. " + "If used with the /StopOn* qualifiers using ETW events, will restrict events to only that process."); parser.DefineOptionalQualifier("DecayToZeroHours", ref DecayToZeroHours, "The trigger value used in StopOnPerfCounter or StopOn*OverMSec will decay to zero in this interval of time."); parser.DefineOptionalQualifier("MinSecForTrigger", ref MinSecForTrigger, "The number of seconds a perf Counter has to be above threshold before it is considered triggered."); parser.DefineOptionalQualifier("DelayAfterTriggerSec", ref DelayAfterTriggerSec, "Wait this number of seconds after a trigger before actually stopping the trace."); parser.DefineOptionalQualifier("CollectMultiple", ref CollectMultiple, "Collect Multiple instance (used in conjunction with StopTrigger)."); parser.DefineOptionalQualifier("StartOnPerfCounter", ref StartOnPerfCounter, "This is of the form CATEGORY:COUNTERNAME:INSTANCE OP NUM where CATEGORY:COUNTERNAME:INSTANCE, identify " + "a performance counter (same as PerfMon), OP is either < or >, and NUM is a number. " + "When that condition is true then collection will start. You can specify this qualifier more than once. Search for 'MonitorPerfCounter' in the users guide for more."); parser.DefineOptionalQualifier("StopCommand", ref StopCommand, "If present this command is executed when a PerfView stops. It is useful to stopping other tracing logic external to PerfView."); List <string> etwStopEvents = new List <string>(); if (StopOnRequestOverMsec != 0) { etwStopEvents.Add("Microsoft-Windows-IIS/EventID(1);Level=Critical;TriggerMSec=" + StopOnRequestOverMsec); } if (StopOnGCSuspendOverMSec != 0) { etwStopEvents.Add("E13C0D23-CCBC-4E12-931B-D9CC2EEE27E4/GC/SuspendEEStart;StopEvent=GC/SuspendEEStop;StartStopID=ThreadID;Keywords=0x1;TriggerMSec=" + StopOnGCSuspendOverMSec); } if (0 < etwStopEvents.Count) { if (StopOnEtwEvent != null) { etwStopEvents.AddRange(StopOnEtwEvent); } StopOnEtwEvent = etwStopEvents.ToArray(); } // Respect the /Process and /DecayToZeroHours options by tacking them on the end if they are not already present. if (StopOnEtwEvent != null && (Process != null || DecayToZeroHours != 0)) { etwStopEvents.Clear(); foreach (var stopEtwEvent in StopOnEtwEvent) { var newStopEtwEvent = stopEtwEvent; if (Process != null && !stopEtwEvent.Contains(";Process=")) { newStopEtwEvent += ";Process=" + Process; } if (DecayToZeroHours != 0 && !stopEtwEvent.Contains(";DecayToZeroHours=")) { newStopEtwEvent += ";DecayToZeroHours=" + DecayToZeroHours; } etwStopEvents.Add(newStopEtwEvent); } StopOnEtwEvent = etwStopEvents.ToArray(); } parser.DefineOptionalQualifier("MonitorPerfCounter", ref MonitorPerfCounter, "This is of the form CATEGORY:COUNTERNAME:INSTANCE@NUM where CATEGORY:COUNTERNAME:INSTANCE, identify " + "a performance counter (same as PerfMon), and NUM is a number representing seconds. The @NUM part is " + "optional and defaults to 2. The value of the performance counter is logged to the ETL file as an " + "event ever NUM seconds"); parser.DefineOptionalQualifier("CpuSampleMSec", ref CpuSampleMSec, "The interval (MSec) between CPU samples (.125Msec min)."); // These apply to Stop Collect and Run parser.DefineOptionalQualifier("Merge", ref Merge, "Do a merge after stopping collection."); parser.DefineOptionalQualifier("Zip", ref Zip, "Zip the ETL file (implies /Merge)."); parser.DefineOptionalQualifier("Wpr", ref Wpr, "Make output mimic WPR (Windows Performance Recorder). Don't ZIP, make a .ngenpdbs directory. " + "This also enables threadTime as well as user mode providers WPR would normally collect by default. This option can also be used " + "On the unzip command. See 'Working with WPA' in the help for more."); parser.DefineOptionalQualifier("NoRundown", ref NoRundown, "Don't request CLR Rundown events."); parser.DefineOptionalQualifier("NoNGenRundown", ref NoNGenRundown, "Don't do rundown of symbolic information in NGEN images (only needed pre V4.5)."); parser.DefineOptionalQualifier("NoClrRundown", ref NoClrRundown, "Don't do rundown .NET (CLR) rundown information )(for symbolic name lookup)."); parser.DefineOptionalQualifier("RundownTimeout", ref RundownTimeout, "Maximum number of seconds to wait for CLR rundown to complete."); parser.DefineOptionalQualifier("MinRundownTime", ref MinRundownTime, "Minimum number of seconds to wait for CLR rundown to complete."); parser.DefineOptionalQualifier("KeepAllEvents", ref KeepAllEvents, "A debug option to keep all events, even symbolic rundown events."); parser.DefineOptionalQualifier("MaxEventCount", ref MaxEventCount, "Limits the total number of events. " + "Useful for trimming large ETL files. 1M typically yields 300-400 Meg of data considered."); parser.DefineOptionalQualifier("SkipMSec", ref SkipMSec, "Skips the first N MSec of the trace. " + "Useful for trimming large ETL files in conjunction with the /MaxEventCount qualifier."); parser.DefineOptionalQualifier("CpuCounters", ref CpuCounters, "A comma separated list of hardware CPU counters specifications NAME:COUNT to turn on. " + "See Users guide for details. See ListCpuCounters for available sources (Win8 only)"); parser.DefineOptionalQualifier("Providers", ref Providers, "Additional providers. This is comma separated list of ProviderGuid:Keywords:Level:Stack specs. " + "This qualifier has the same syntax as the Additional Providers TextBox in the collection window. " + " See help on that for more."); string[] onlyProviders = null; parser.DefineOptionalQualifier("OnlyProviders", ref onlyProviders, "Like the Providers qualifier, but also turns off the default Kernel and CLR providers."); if (onlyProviders != null) { // Allow stack traces to work if 'stacks' was specified. bool hasStacks = false; bool hasTpl = false; foreach (var provider in onlyProviders) { if (0 <= provider.IndexOf(":stack", StringComparison.OrdinalIgnoreCase)) { hasStacks = true; } if (provider.StartsWith(".NETTasks", StringComparison.OrdinalIgnoreCase)) { hasTpl = true; } } if (hasStacks) { KernelEvents = KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread | KernelTraceEventParser.Keywords.ImageLoad; ClrEvents = ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.Loader; } else { KernelEvents = KernelTraceEventParser.Keywords.None; ClrEvents = ClrTraceEventParser.Keywords.None; NoNGenRundown = true; // We still do normal rundown because EventSource rundown is done there. NoClrRundown = true; } Providers = onlyProviders; if (!hasTpl) { Providers = new string[onlyProviders.Length + 1]; Array.Copy(onlyProviders, Providers, onlyProviders.Length); Providers[onlyProviders.Length] = ".NETTasks:0x80"; // Turn on causality tracking. } } parser.DefineOptionalQualifier("ThreadTime", ref ThreadTime, "Shortcut for turning on context switch and readyThread events"); if (ThreadTime) { KernelEvents = KernelTraceEventParser.Keywords.ThreadTime; } parser.DefineOptionalQualifier("GCOnly", ref GCOnly, "Turns on JUST GC collections an allocation sampling."); if (GCOnly) { // TODO this logic is cloned. We need it in only one place. If you update it do the other location as well // For stack parsing. KernelEvents = KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread | KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.VirtualAlloc; ClrEvents = ClrTraceEventParser.Keywords.GC | ClrTraceEventParser.Keywords.GCHeapSurvivalAndMovement | ClrTraceEventParser.Keywords.Stack | ClrTraceEventParser.Keywords.Jit | ClrTraceEventParser.Keywords.StopEnumeration | ClrTraceEventParser.Keywords.SupressNGen | ClrTraceEventParser.Keywords.Loader | ClrTraceEventParser.Keywords.Exception; // This is not quite correct if you have providers of your own, but this covers the most important case. if (Providers == null) { Providers = new string[] { "Microsoft-Windows-Kernel-Memory:0x60" } } ; CommandProcessor.s_UserModeSessionName = "PerfViewGCSession"; DataFile = "PerfViewGCOnly.etl"; } parser.DefineOptionalQualifier("GCCollectOnly", ref GCCollectOnly, "Turns on GC collections (no allocation sampling)."); if (GCCollectOnly) { // TODO this logic is cloned. We need it in only one place. If you update it do the other location as well KernelEvents = KernelTraceEventParser.Keywords.Process; // For process names ClrEvents = ClrTraceEventParser.Keywords.GC | ClrTraceEventParser.Keywords.Exception; ClrEventLevel = TraceEventLevel.Informational; NoRundown = true; CommandProcessor.s_UserModeSessionName = "PerfViewGCSession"; DataFile = "PerfViewGCCollectOnly.etl"; } // WPR option implies a bunch of kernel events. if (Wpr) { KernelEvents = KernelTraceEventParser.Keywords.ThreadTime | KernelTraceEventParser.Keywords.DeferedProcedureCalls | KernelTraceEventParser.Keywords.Driver | KernelTraceEventParser.Keywords.Interrupt; } parser.DefineOptionalQualifier("DumpHeap", ref DumpHeap, "Capture a heap snapshot on profile stop"); parser.DefineOptionalQualifier("Finalizers", ref Finalizers, "Track the number of objects of each type finalized."); parser.DefineOptionalQualifier("ClrEventLevel", ref ClrEventLevel, "The verbosity for CLR events"); parser.DefineOptionalQualifier("ClrEvents", ref ClrEvents, "A comma separated list of .NET CLR events to turn on. See Users guide for details."); parser.DefineOptionalQualifier("KernelEvents", ref KernelEvents, "A comma separated list of windows OS kernel events to turn on. See Users guide for details."); parser.DefineOptionalQualifier("DotNetAlloc", ref DotNetAlloc, "Turns on per-allocation .NET profiling."); parser.DefineOptionalQualifier("DotNetAllocSampled", ref DotNetAllocSampled, "Turns on per-allocation .NET profiling, sampling types in a smart way to keep overhead low."); parser.DefineOptionalQualifier("DotNetCalls", ref DotNetCalls, "Turns on per-call .NET profiling."); parser.DefineOptionalQualifier("DotNetCallsSampled", ref DotNetCallsSampled, "Turns on per-call .NET profiling, sampling types in a smart way to keep overhead low."); parser.DefineOptionalQualifier("JITInlining", ref JITInlining, "Turns on logging of successful and failed JIT inlining attempts."); parser.DefineOptionalQualifier("OSHeapProcess", ref OSHeapProcess, "Turn on per-allocation profiling of allocation from the OS heap for the process with the given process ID."); parser.DefineOptionalQualifier("OSHeapExe", ref OSHeapExe, "Turn on per-allocation profiling of allocation from the OS heap for the process with the given EXE (only filename WITH extension)."); parser.DefineOptionalQualifier("NetworkCapture", ref NetworkCapture, "Captures the full data of every network packet entering or leaving the OS."); parser.DefineOptionalQualifier("NetMonCapture", ref NetMonCapture, "Create _netmon.etl file that NetMon.exe can read, along with the standard ETL file. Implies /NetworkCapture."); parser.DefineOptionalQualifier("ForceNgenRundown", ref ForceNgenRundown, "By default on a V4.0 runtime NGEN rundown is suppressed, because NGEN PDB are a less expensive way of getting symbolic " + "information for NGEN images. This option forces NGEN rundown, so NGEN PDBs are not needed. This can be useful " + "in some scenarios where NGEN PDB are not working properly."); parser.DefineOptionalQualifier("NoV2Rundown", ref NoV2Rundown, "Don't do rundown for .NET (CLR) V2 processes."); parser.DefineOptionalQualifier("TrustPdbs", ref TrustPdbs, "Normally PerfView does not trust PDBs outside the _NT_SYMBOL_PATH and pops a dialog box. Suppress this."); parser.DefineOptionalQualifier("AcceptEULA", ref AcceptEULA, "Accepts the EULA associated with PerfView."); parser.DefineOptionalQualifier("DataFile", ref DataFile, "FileName of the profile data to generate."); parser.DefineOptionalQualifier("NoView", ref NoView, "Normally after collecting data the data is viewed. This suppresses that."); parser.DefineOptionalQualifier("UnsafePDBMatch", ref UnsafePDBMatch, "Allow the use of PDBs even when the trace does not contain PDB signatures."); parser.DefineOptionalQualifier("ShowUnknownAddresses", ref ShowUnknownAddresses, "Displays the hexadecimal address rather than ? when the address is unknown."); parser.DefineOptionalQualifier("NoGui", ref NoGui, "Use the Command line version of the command (like on ARM). Brings up a console window. For batch scripts/automation use /LogFile instead (see users guide under 'Scripting' for more)."); parser.DefineOptionalQualifier("SafeMode", ref SafeMode, "Turn off parallelism and other risky features."); parser.DefineOptionalQualifier("RestartingToElevelate", ref RestartingToElevelate, "Internal: indicates that perfView is restarting to get Admin privileges."); // TODO FIX NOW this is a hack, does not handle kernel mode ... parser.DefineOptionalQualifier("SessionName", ref CommandProcessor.s_UserModeSessionName, "Define the name for the user mode session, if kernel events are off."); parser.DefineOptionalQualifier("MaxNodeCountK", ref MaxNodeCountK, "The maximum number of objects (in K or thousands) that will even be examined when dumping the heap. Avoids memory use at collection time. " + "This is useful if heap dumping causes out of memory exceptions."); /* end of qualifier that apply to more than one parameter set (command) */ /****************************************************************************************/ /* Parameter set (command) definitions */ parser.DefineParameterSet("run", ref DoCommand, App.CommandProcessor.Run, "Starts data collection, runs a command and stops."); parser.DefineParameter("CommandAndArgs", ref CommandAndArgs, "Command to run and arguments (PerfView options must come before run command)."); parser.DefineParameterSet("collect", ref DoCommand, App.CommandProcessor.Collect, "Starts data collection, wait for user input, then stops."); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data."); parser.DefineParameterSet("start", ref DoCommand, App.CommandProcessor.Start, "Starts machine wide profile data collection."); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data."); parser.DefineParameterSet("stop", ref DoCommand, App.CommandProcessor.Stop, "Stop collecting profile data (machine wide). If you specified EventSources with the /Providers qualifier on start you should repeat them here to insure manifest rundown."); parser.DefineParameterSet("mark", ref DoCommand, App.CommandProcessor.Mark, "Add a PerfView 'Mark' event to the event stream with a optional string message"); parser.DefineOptionalParameter("Message", ref Message, "The string message to attach to the PerfView Mark event."); parser.DefineParameterSet("abort", ref DoCommand, App.CommandProcessor.Abort, "Insures that any active PerfView sessions are stopped."); parser.DefineParameterSet("merge", ref DoCommand, App.CommandProcessor.Merge, "Combine separate ETL files into a single ETL file (that can be decoded on another machine)."); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data."); parser.DefineParameterSet("unzip", ref DoCommand, App.CommandProcessor.Unzip, "Unpack a ZIP file into its ETL file (and possibly its NGEN PDBS) /WPR option can be specified."); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data."); parser.DefineParameterSet("listSessions", ref DoCommand, App.CommandProcessor.ListSessions, "Lists active ETW sessions."); parser.DefineParameterSet("ListCpuCounters", ref DoCommand, App.CommandProcessor.ListCpuCounters, "Lists the ListCpuCounters CPU counters available on the system (win8+ only)."); parser.DefineParameterSet("EnableKernelStacks", ref DoCommand, App.CommandProcessor.EnableKernelStacks, "On X64 machines if you have problems with broken stacks when the code is executing in the kernel," + " setting this option and rebooting may improve things"); parser.DefineParameterSet("DisableKernelStacks", ref DoCommand, App.CommandProcessor.DisableKernelStacks, "Resets the registry keys set by EnableKernelStack."); string ProcessParam = null; parser.DefineParameterSet("HeapSnapshot", ref DoCommand, App.CommandProcessor.HeapSnapshot, "Take a snapshot of the CLR GC heap of a process."); parser.DefineParameter("Process", ref ProcessParam, "The process ID or Process Name (Exe without extension) of the process take a heap snapshot."); parser.DefineOptionalParameter("DataFile", ref DataFile, "The name of the file to place the heap snapshot."); parser.DefineOptionalQualifier("SaveETL", ref SaveETL, "Save an ETL file along with the GCDump file when dumping the JS Heap."); parser.DefineOptionalQualifier("MaxDumpCountK", ref MaxDumpCountK, "The maximum number of objects (in K or thousands) to place int the .gcDump file. Sample sufficiently to hit this metric."); parser.DefineOptionalQualifier("Freeze", ref Freeze, "Freeze the dump while data is taken."); parser.DefineParameterSet("ForceGC", ref DoCommand, App.CommandProcessor.ForceGC, "Forces a GC on the specified process"); parser.DefineParameter("Process", ref ProcessParam, "The process ID or Process Name (Exe without extension) of the process to force a GC."); // We have both a qualifier and a parameter named Process. It is OK that they use the same variable, but the parameter should not // overwrite the qualifier if it is null. if (ProcessParam != null) { Process = ProcessParam; } parser.DefineParameterSet("HeapSnapshotFromProcessDump", ref DoCommand, App.CommandProcessor.HeapSnapshotFromProcessDump, "Extract the CLR GC heap from a process dump file specified."); parser.DefineParameter("ProcessDumpFile", ref ProcessDumpFile, "The name of the input process dump file."); parser.DefineOptionalParameter("DataFile", ref DataFile, "The name of the file to place the heap snapshot."); // TODO FIX NOW parser.DefineOptionalQualifier("DumpData", ref DumpData, "Dump the data as well as the connectivity information."); parser.DefineParameterSet("GuiRun", ref DoCommand, App.CommandProcessor.GuiRun, "Opens the 'Run' dialog box."); parser.DefineParameterSet("GuiCollect", ref DoCommand, App.CommandProcessor.GuiCollect, "Opens the 'Collect' dialog box."); parser.DefineParameterSet("GuiHeapSnapshot", ref DoCommand, App.CommandProcessor.GuiHeapSnapshot, "Opens the 'TakeHeapSnapshot' dialog box."); parser.DefineParameterSet("UserCommand", ref DoCommand, App.CommandProcessor.UserCommand, "Runs a user defined command. Type 'PerfView UserCommandHelp' to see the help for all the user commands. " + "See PerfView Extensions in the users guide for more on creating user commands."); parser.DefineParameter("CommandAndArgs", ref CommandAndArgs, "User command to run and any arguments."); parser.DefineParameterSet("UserCommandHelp", ref DoCommand, App.CommandProcessor.UserCommandHelp, "Displays help for user commands. Also see Help->User Command Help in the GUI."); parser.DefineParameterSet("CreateExtensionProject", ref DoCommand, App.CommandProcessor.CreateExtensionProject, "Creates a VS project for creates a perfView extension."); parser.DefineOptionalParameter("ExtensionName", ref ExtensionName, "The name of the extension (no .DLL)"); // TODO FIX NOW, this should be a user command parser.DefineParameterSet("FetchSymbolsForProcess", ref DoCommand, App.CommandProcessor.FetchSymbolsForProcess, "Fetch all the PDBs files needed for viewing locally. "); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL file containing profile data."); #if CROSS_GENERATION_LIVENESS parser.DefineParameterSet("CollectCrossGenerationLiveness", ref DoCommand, App.CommandProcessor.CollectCrossGenerationLiveness, "Collect a heap snapshot that can be used to do cross-generation liveness analysis."); parser.DefineQualifier("PID", ref CGL_PID, "The process ID of the process to snapshot."); parser.DefineQualifier("Generation", ref CGL_Generation, "The generation of the GC to collect."); parser.DefineQualifier("PromotedBytesThreshold", ref CGL_PromotedBytesThreshold, "The threshold of promoted bytes after which a snapshot of the heap should be collected."); parser.DefineQualifier("OutputFile", ref CGL_PathToOutputFile, "The full path including filename where the resulting gcdump file should be stored."); #endif parser.DefineDefaultParameterSet(ref DoCommand, App.CommandProcessor.View, "View profile data."); parser.DefineOptionalParameter("DataFile", ref DataFile, "ETL or ETLX file containing profile data."); } #endregion };
public void KernelEnableParameters(KernelTraceEventParser.Keywords keywords, KernelTraceEventParser.Keywords stacks) { WriteEvent(12, (int)keywords, (int)stacks); }
private void collectCpuStacks(string dataFileName, int bufferSizeMb) { const KernelTraceEventParser.Keywords kernelKeywords = KernelTraceEventParser.Keywords.ImageLoad | KernelTraceEventParser.Keywords.Process | KernelTraceEventParser.Keywords.Thread | KernelTraceEventParser.Keywords.Profile; // To support Windows 7 and earlier, we need a separate session for kernel and CLR events string sessionName = "CPUStacksSession"; string kernelDataFileName = Path.ChangeExtension(dataFileName, ".kernel.etl"); using (var session = new TraceEventSession(sessionName, dataFileName) { BufferSizeMB = bufferSizeMb }) { using (var kernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, kernelDataFileName)) { kernelSession.EnableKernelProvider(kernelKeywords, KernelTraceEventParser.Keywords.Profile); session.EnableProvider(ClrTraceEventParser.ProviderGuid, TraceEventLevel.Verbose, (ulong)(ClrTraceEventParser.Keywords.Default | ClrTraceEventParser.Keywords.StartEnumeration)); m_collectionToken.WaitHandle.WaitOne(); generateJitRundownEvents(dataFileName, sessionName, bufferSizeMb); var kernelEventsLost = kernelSession.EventsLost; Dispatcher.BeginInvoke( new Action(() => { EventsLostKernelLabel.Content = kernelEventsLost; })); } var sessionEventsLost = session.EventsLost; Dispatcher.BeginInvoke( new Action(() => { EventsLostTraceLabel.Content = sessionEventsLost; })); } var p = new Process { StartInfo = new ProcessStartInfo("xperf") { Arguments = string.Format("-merge {0}.etl {0}.clrRundown.etl {0}.kernel.etl {0}_merged.etl", Path.GetFileNameWithoutExtension(dataFileName)), CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, WorkingDirectory = Environment.CurrentDirectory } }; try { p.Start(); } catch (Exception) { } p.WaitForExit(); using (var zipped = new ZipFile(Path.ChangeExtension(dataFileName, ".zip")) { CompressionLevel = CompressionLevel.BestCompression }) { zipped.AddSelectedFiles(string.Format("name = {0}*.etl", Path.GetFileNameWithoutExtension(dataFileName))); zipped.Save(); } }
/// <summary> /// Shortcut that enables the kernel provider with no eventToStack trace capturing. /// See code:#EnableKernelProvider (flags, stackCapture) /// </summary> public bool EnableKernelProvider(KernelTraceEventParser.Keywords flags) { return(EnableKernelProvider(flags, KernelTraceEventParser.Keywords.None)); }