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);
                }
            }
        }
예제 #2
0
        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();
            }
        }
예제 #4
0
 /// <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.");
     }
 }
예제 #5
0
        /// <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());
        }
예제 #6
0
        /// <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());
        }
예제 #7
0
        /// <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);
                }
            }
        }
예제 #8
0
 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);
 }
예제 #9
0
        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;
        }
예제 #10
0
        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;
        }
예제 #11
0
 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());
        }
예제 #13
0
 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;
 }
예제 #14
0
        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
    };
예제 #15
0
 public void KernelEnableParameters(KernelTraceEventParser.Keywords keywords, KernelTraceEventParser.Keywords stacks)
 {
     WriteEvent(12, (int)keywords, (int)stacks);
 }
예제 #16
0
        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));
 }