Ejemplo n.º 1
0
        public Task <Stream> StartCpuTrace(int pid, int durationSeconds, CancellationToken cancellationToken)
        {
            if ((durationSeconds < 1) || (durationSeconds > MaxTraceSeconds))
            {
                throw new InvalidOperationException("Invalid duration");
            }

            //TODO Should we limit only 1 trace per file?
            var client = new DiagnosticsClient(pid);

            //TODO Pull event providers from the configuration.
            var cpuProviders = new EventPipeProvider[] {
                new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", System.Diagnostics.Tracing.EventLevel.Informational),
                new EventPipeProvider("Microsoft-Windows-DotNETRuntime", System.Diagnostics.Tracing.EventLevel.Informational, (long)Tracing.Parsers.ClrTraceEventParser.Keywords.Default)
            };

            EventPipeSession session = client.StartEventPipeSession(cpuProviders, requestRundown: true);

            CancellationTokenSource linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_tokenSource.Token, cancellationToken);
            Task traceTask = Task.Run(async() =>
            {
                try
                {
                    await Task.Delay(TimeSpan.FromSeconds(durationSeconds), linkedTokenSource.Token);
                }
                finally
                {
                    session.Stop();
                    linkedTokenSource.Dispose();
                    //We rely on the caller to Dispose the EventStream file.
                }
            }, CancellationToken.None);

            return(Task.FromResult(session.EventStream));
        }
        public EventPipeListener(int targetProcessId, IEnumerable <EventPipeProvider> providers)
        {
            var client = new DiagnosticsClient(targetProcessId);

            _listeningSession = client.StartEventPipeSession(providers);

            _eventSource = new EventPipeEventSource(_listeningSession.EventStream);

            _eventSource.Kernel.All  += (TraceEvent @event) => KernelEvents?.Invoke(@event);
            _eventSource.Clr.All     += (TraceEvent @event) => ClrEvents?.Invoke(@event);
            _eventSource.Dynamic.All += (TraceEvent @event) => CustomEvents?.Invoke(@event);
            Task.Factory.StartNew(() => _eventSource.Process(), _cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);

            //with a code like this we can output a memory dump depending on some threshold of CPU usage

            /*
             * _eventSource.Dynamic.All += (TraceEvent obj) =>
             *      {
             *          if (obj.EventName.Equals("EventCounters"))
             *          {
             *              IDictionary<string, object> payloadVal = (IDictionary<string, object>)(obj.PayloadValue(0));
             *              IDictionary<string, object> payloadFields = (IDictionary<string, object>)(payloadVal["Payload"]);
             *              if (payloadFields["Name"].ToString().Equals("cpu-usage"))
             *              {
             *                  double cpuUsage = Double.Parse(payloadFields["Mean"]);
             *                  if (cpuUsage > (double)threshold)
             *                  {
             *                      client.WriteDump(DumpType.Normal, "./minidump.dmp");
             *                  }
             *              }
             *          }
             *      }
             */
        }
Ejemplo n.º 3
0
        /// <summary>
        /// This uses CopyTo to copy the trace into a filesystem first, and then uses EventPipeEventSource
        /// on the file to post-process it and return the total # of events read.
        /// </summary>
        static Func <int, TestResult> UseFS(bool rundown, int bufferSize)
        {
            return((int pid) =>
            {
                int eventsRead = 0;
                var totalTimeSw = new Stopwatch();
                const string fileName = "./temp.nettrace";

                EventPipeSession session = GetSession(pid, rundown, bufferSize);
                Console.WriteLine("Session created.");

                using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                {
                    totalTimeSw.Start();
                    session.EventStream.CopyTo(fs);
                    totalTimeSw.Stop();
                }
                EventPipeEventSource epes = new EventPipeEventSource(fileName);
                epes.Dynamic.All += (TraceEvent data) => {
                    eventsRead += 1;
                };
                epes.Process();
                Console.WriteLine("Read total: " + eventsRead.ToString());
                Console.WriteLine("Dropped total: " + epes.EventsLost.ToString());

                return new TestResult(eventsRead, epes.EventsLost, totalTimeSw.Elapsed);
            });
        }
Ejemplo n.º 4
0
 private static void StopSession(EventPipeSession session)
 {
     try
     {
         session.Stop();
     }
     catch (EndOfStreamException)
     {
         // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully.
     }
     // We may time out if the process ended before we sent StopTracing command. We can just exit in that case.
     catch (TimeoutException)
     {
     }
     // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library
     // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited
     // before collection started and got rid of a pipe that once existed.
     // Since we are catching this at the end of a session we know that the pipe once existed (otherwise the exception would've
     // been thrown at the beginning directly)
     catch (PlatformNotSupportedException)
     {
     }
     // On non-abrupt exits, the socket may be already closed by the runtime and we won't be able to send a stop request through it.
     catch (ServerNotAvailableException)
     {
     }
 }
Ejemplo n.º 5
0
            public Task <Stream> ProcessEvents(DiagnosticsClient client, TimeSpan duration, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                EventPipeSession session = null;

                try
                {
                    session = client.StartEventPipeSession(_sourceConfig.GetProviders(), _sourceConfig.RequestRundown, _sourceConfig.BufferSizeInMB);
                }
                catch (EndOfStreamException e)
                {
                    throw new InvalidOperationException("End of stream", e);
                }
                catch (Exception ex) when(!(ex is OperationCanceledException))
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }

                _currentTask = Task.Run(async() =>
                {
                    using var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    linkedSource.CancelAfter(duration);
                    using var _ = linkedSource.Token.Register(() => _stopProcessingSource.TrySetResult(null));

                    // Use TaskCompletionSource instead of Task.Delay with cancellation to avoid
                    // using exceptions for normal termination of event stream.
                    await _stopProcessingSource.Task.ConfigureAwait(false);
                    StopSession(session);
                });

                return(Task.FromResult(session.EventStream));
            }
Ejemplo n.º 6
0
        public void StartListeningToCounters(string providerName)
        {
            var provider = new EventPipeProvider(providerName, EventLevel.Informational, (long)0, new Dictionary <string, string>()
            {
                { "EventCounterInterval", "1" }
            });

            m_session = m_client.StartEventPipeSession(new List <EventPipeProvider>()
            {
                provider
            });
            Task streamTask = Task.Run(() =>
            {
                var buffer = new byte[1000];
                while (true)
                {
                    try
                    {
                        m_session.EventStream.Read(buffer, 0, 1000);
                    }
                    catch (Exception e)
                    {
                    }
                }
            });
        }
Ejemplo n.º 7
0
 private static async Task StopSessionAsync(EventPipeSession session)
 {
     // Cancel after a generous amount of time if process ended before command is sent.
     using CancellationTokenSource cancellationSource = new(IpcClient.ConnectTimeout);
     try
     {
         await session.StopAsync(cancellationSource.Token).ConfigureAwait(false);
     }
     catch (EndOfStreamException)
     {
         // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully.
     }
     // We may time out if the process ended before we sent StopTracing command. We can just exit in that case.
     catch (TimeoutException)
     {
     }
     // We may time out if the process ended before we sent StopTracing command. We can just exit in that case.
     catch (OperationCanceledException)
     {
     }
     // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library
     // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited
     // before collection started and got rid of a pipe that once existed.
     // Since we are catching this at the end of a session we know that the pipe once existed (otherwise the exception would've
     // been thrown at the beginning directly)
     catch (PlatformNotSupportedException)
     {
     }
     // On non-abrupt exits, the socket may be already closed by the runtime and we won't be able to send a stop request through it.
     catch (ServerNotAvailableException)
     {
     }
 }
Ejemplo n.º 8
0
        /// <summary>
        /// This uses CopyToAsync to copy the trace into a filesystem first, and then uses EventPipeEventSource
        /// on the file to post-process it and return the total # of events read.
        /// </summary>
        static void UseFS(int pid)
        {
            int               eventsRead = 0;
            const string      fileName   = "./temp.nettrace";
            DiagnosticsClient client     = new DiagnosticsClient(pid);
            EventPipeSession  session    = client.StartEventPipeSession(new EventPipeProvider("MySource", EventLevel.Verbose));

            Console.WriteLine("session open");

            using (FileStream fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
            {
                Task copyTask = session.EventStream.CopyToAsync(fs);
                while (!copyTask.Wait(100))
                {
                    ;
                }
            }
            EventPipeEventSource epes = new EventPipeEventSource(fileName);

            epes.Dynamic.All += (TraceEvent data) => {
                eventsRead += 1;
            };
            epes.Process();
            Console.WriteLine("Used post processing.");
            Console.WriteLine("Read total: " + eventsRead.ToString());
            Console.WriteLine("Dropped total: " + epes.EventsLost.ToString());
        }
Ejemplo n.º 9
0
    public static void PrintRuntimeGCEvents(int processId)
    {
        var providers = new List <EventPipeProvider>()
        {
            new EventPipeProvider("Microsoft-Windows-DotNETRuntime",
                                  EventLevel.Informational, (long)ClrTraceEventParser.Keywords.GC)
        };

        var client = new DiagnosticsClient(processId);

        using (EventPipeSession session = client.StartEventPipeSession(providers, false))
        {
            var source = new EventPipeEventSource(session.EventStream);

            source.Clr.All += (TraceEvent obj) => Console.WriteLine(obj.ToString());

            try
            {
                source.Process();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error encountered while processing events");
                Console.WriteLine(e.ToString());
            }
        }
    }
Ejemplo n.º 10
0
        public void Start(Process process)
        {
            _process  = process;
            _counters = new SortedDictionary <string, string>();
            _task     = new Task(() =>
            {
                var diagnosticsClient = new DiagnosticsClient(_process.Id);
                var providerList      = new List <EventPipeProvider>()
                {
                    new EventPipeProvider(name: "System.Runtime",
                                          keywords: long.MaxValue,
                                          eventLevel: EventLevel.Verbose,
                                          arguments: new Dictionary <string, string>()
                    {
                        { "EventCounterIntervalSec", "1" }
                    })
                };

                _session = diagnosticsClient.StartEventPipeSession(
                    providers: providerList,
                    requestRundown: false);

                var source = new EventPipeEventSource(_session.EventStream);

                source.Dynamic.AddCallbackForProviderEvent("System.Runtime", "EventCounters", CounterEvent);
                source.Process();
            });

            _task.Start();
        }
Ejemplo n.º 11
0
        public bool Start(Action <TraceEvent> trigger, Func <TraceEvent, bool> filter = null)
        {
            if (IsStarted || Providers.Count == 0)
            {
                return(false);
            }

            this.Trigger = trigger ?? throw new ArgumentNullException(nameof(trigger));
            this.Filter  = filter;

            //foreach (var provider in Providers)
            //{
            //    var listener = new EventListener();
            //    EventListener.EnableEvents()
            //}

            Task.Run(() =>
            {
                _session = _client.StartEventPipeSession(Providers, false);
                _source  = new EventPipeEventSource(_session.EventStream);
                OnSubscribe(_source);
                _source.Dynamic.All += Dynamic_All;
                _source.Process();
            });

            IsStarted = true;
            return(true);
        }
Ejemplo n.º 12
0
        public void Start()
        {
            Task.Run(() => {
                try {
                    var client       = new DiagnosticsClient(_pid);
                    _session         = client.StartEventPipeSession(_providers, false);
                    using var source = new EventPipeEventSource(_session.EventStream);

                    source.NeedLoadedDotNetRuntimes();
                    source.AddCallbackOnProcessStart(proc => {
                        if (proc.ProcessID != _pid)
                        {
                            return;
                        }

                        proc.AddCallbackOnDotNetRuntimeLoad(runtime => {
                            runtime.GCEnd += (process, gc) => {
                                var key = $"gen-{gc.Generation}-gc-collection-count";
                                _collectedStats.TryGetValue(key, out var collected);
                                _collectedStats[key] = ++collected;
                            };
                        });
                    });

                    source.Dynamic.All += obj => {
                        if (obj.EventName.Equals("EventCounters"))
                        {
                            var payload = (IDictionary <string, object>)obj.PayloadValue(0);
                            var pairs   = (IDictionary <string, object>)(payload["Payload"]);

                            var name = string.Intern(pairs["Name"].ToString());

                            var counterType = pairs["CounterType"];
                            if (counterType.Equals("Sum"))
                            {
                                _collectedStats[name] = double.Parse(pairs["Increment"].ToString());
                            }

                            if (counterType.Equals("Mean"))
                            {
                                _collectedStats[name] = double.Parse(pairs["Mean"].ToString());
                            }
                        }
                    };

                    source.Process();
                } catch (ObjectDisposedException) {
                    // ignore exception on shutdown
                } catch (Exception exception) {
                    Log.Warning(exception, "Error encountered while processing events");
                }
            });
        }
Ejemplo n.º 13
0
        public Task <Stream> ProcessEvents(int processId, TimeSpan duration, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            lock (_lock)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(nameof(DiagnosticsMonitor));
                }

                if (_currentTask != null)
                {
                    throw new InvalidOperationException("Only one stream processing is allowed");
                }

                EventPipeSession session = null;
                var client = new DiagnosticsClient(processId);

                try
                {
                    session = client.StartEventPipeSession(_sourceConfig.GetProviders(), _sourceConfig.RequestRundown, _sourceConfig.BufferSizeInMB);
                }
                catch (EndOfStreamException e)
                {
                    throw new InvalidOperationException("End of stream", e);
                }
                catch (Exception ex) when(!(ex is OperationCanceledException))
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }

                CancellationTokenSource linkedSource = CancellationTokenSource.CreateLinkedTokenSource(_stopProcessingSource.Token, cancellationToken);

                _currentTask = Task.Run(async() =>
                {
                    try
                    {
                        await Task.Delay(duration, linkedSource.Token);
                    }
                    finally
                    {
                        linkedSource.Dispose();
                        StopSession(session);
                    }
                });

                return(Task.FromResult(session.EventStream));
            }
        }
Ejemplo n.º 14
0
        public void Start()
        {
            using (var session = client.StartEventPipeSession(providers, false))
                using (var source = new EventPipeEventSource(session.EventStream))
                {
                    _session         = session;
                    _source          = source;
                    _source.Clr.All += Trigger;

                    try
                    {
                        _source?.Process();
                    }
                    catch (DiagnosticsClientException) { }
                }
        }
Ejemplo n.º 15
0
        public void Handle(HostSignal signal, DiagnoserActionParameters parameters)
        {
            if (signal != HostSignal.BeforeAnythingElse)
            {
                return;
            }

            var diagnosticsClient = new DiagnosticsClient(parameters.Process.Id);

            EventPipeSession session = diagnosticsClient.StartEventPipeSession(eventPipeProviders, true);

            var fileName = ArtifactFileNameHelper.GetTraceFilePath(parameters, DateTime.Now, "nettrace").EnsureFolderExists();

            benchmarkToTraceFile[parameters.BenchmarkCase] = fileName;

            collectingTask = Task.Run(() => CopyEventStreamToFile(session, fileName, parameters.Config.GetCompositeLogger()));
        }
Ejemplo n.º 16
0
        static void ThreadProc(Object arg)
        {
            Process eventWritingProc = (Process)arg;

            eventCounts[cur_core_count] = 0;
            DiagnosticsClient    client  = new DiagnosticsClient(eventWritingProc.Id);
            EventPipeSession     session = client.StartEventPipeSession(new EventPipeProvider("MySource", EventLevel.Verbose, (long)-1, null));
            EventPipeEventSource source  = new EventPipeEventSource(session.EventStream);

            source.Dynamic.All += (TraceEvent data) => {
                if (data.EventName == "FireSmallEvent")
                {
                    eventCounts[cur_core_count] += 1;
                }
            };
            source.Process();
        }
Ejemplo n.º 17
0
        /// <summary>
        /// This uses EventPipeEventSource's Stream constructor to parse the events real-time.
        /// It then returns the number of events read.
        /// </summary>
        static void UseEPES(int pid)
        {
            int eventsRead            = 0;
            DiagnosticsClient client  = new DiagnosticsClient(pid);
            EventPipeSession  session = client.StartEventPipeSession(new EventPipeProvider("MySource", EventLevel.Verbose));

            Console.WriteLine("session open");
            EventPipeEventSource epes = new EventPipeEventSource(session.EventStream);

            epes.Dynamic.All += (TraceEvent data) => {
                eventsRead += 1;
            };
            epes.Process();
            Console.WriteLine("Used realtime.");
            Console.WriteLine("Read total: " + eventsRead.ToString());
            Console.WriteLine("Dropped total: " + epes.EventsLost.ToString());
        }
Ejemplo n.º 18
0
        public bool Stop()
        {
            if (!IsStarted)
            {
                return(false);
            }

            if (_source != null)
            {
                _source.Dispose(); _source = null;
            }
            if (_session != null)
            {
                _session.Dispose(); _session = null;
            }

            IsStarted = false;
            return(true);
        }
Ejemplo n.º 19
0
        public bool Start()
        {
            if (IsStarted || Providers.Count == 0)
            {
                return(false);
            }

            Task.Run(() =>
            {
                _session = _client.StartEventPipeSession(Providers, false);
                _source  = new EventPipeEventSource(_session.EventStream);
                OnSubscribe(_source);
                _source.Dynamic.All += Dynamic_All;
                _source.Process();
            });

            IsStarted = true;
            return(true);
        }
Ejemplo n.º 20
0
        /// <summary>
        /// This uses EventPipeEventSource's Stream constructor to parse the events real-time.
        /// It then returns the number of events read.
        /// </summary>
        private static Func <int, TestResult> UseEPES(bool rundown, int bufferSize, int slowReader)
        {
            return((int pid) =>
            {
                int eventsRead = 0;
                var slowReadSw = new Stopwatch();
                var totalTimeSw = new Stopwatch();
                var interval = TimeSpan.FromSeconds(0.75);

                EventPipeSession session = GetSession(pid, rundown, bufferSize);
                Console.WriteLine("Session created.");

                EventPipeEventSource epes = new EventPipeEventSource(session.EventStream);
                epes.Dynamic.All += (TraceEvent data) => {
                    eventsRead += 1;
                    if (slowReader > 0)
                    {
                        if (slowReadSw.Elapsed > interval)
                        {
                            Thread.Sleep(slowReader);
                            slowReadSw.Reset();
                        }
                    }
                };
                if (slowReader > 0)
                {
                    slowReadSw.Start();
                }
                totalTimeSw.Start();
                epes.Process();
                totalTimeSw.Stop();
                if (slowReader > 0)
                {
                    slowReadSw.Stop();
                }
                Console.WriteLine("Read total: " + eventsRead.ToString());
                Console.WriteLine("Dropped total: " + epes.EventsLost.ToString());

                return new TestResult(eventsRead, epes.EventsLost, totalTimeSw.Elapsed);
            });
        }
Ejemplo n.º 21
0
        private bool StartSession()
        {
            int retries = 20;

            while (retries > 0 && _session == null)
            {
                try
                {
                    _session = _client.StartEventPipeSession(Providers, false);
                }
                catch (ServerNotAvailableException)
                {
                }
                catch (Exception err)
                {
                    Console.WriteLine(err.Message);
                }

                retries--;
            }

            return(_session != null);
        }
Ejemplo n.º 22
0
 private static void StopSession(EventPipeSession session)
 {
     try
     {
         session.Stop();
     }
     catch (EndOfStreamException)
     {
         // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully.
     }
     // We may time out if the process ended before we sent StopTracing command. We can just exit in that case.
     catch (TimeoutException)
     {
     }
     // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library
     // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited
     // before dotnet-counters and got rid of a pipe that once existed.
     // Since we are catching this in StopMonitor() we know that the pipe once existed (otherwise the exception would've
     // been thrown in StartMonitor directly)
     catch (PlatformNotSupportedException)
     {
     }
 }
Ejemplo n.º 23
0
        private static void CopyEventStreamToFile(EventPipeSession session, string fileName, ILogger logger)
        {
            try
            {
                using (session)
                    using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write))
                    {
                        byte[] buffer    = new byte[16 * 1024];
                        int    bytesRead = 0;

                        while ((bytesRead = session.EventStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fs.Write(buffer, 0, bytesRead);
                        }

                        fs.Flush();
                    }
            }
            catch (Exception ex)
            {
                logger.WriteLine(LogKind.Error, $"An exception occurred during reading trace stream: {ex}");
            }
        }
Ejemplo n.º 24
0
        public void Start(string providerName, EventLevel level, long keywords)
        {
            var provider = new EventPipeProvider(providerName, level, keywords);

            m_session = m_client.StartEventPipeSession(new List <EventPipeProvider>()
            {
                provider
            });
            // Task that reads and does nothing
            Task streamTask = Task.Run(() =>
            {
                var buffer = new byte[1000];
                while (true)
                {
                    try
                    {
                        m_session.EventStream.Read(buffer, 0, 1000);
                    }
                    catch (Exception e)
                    {
                    }
                }
            });
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Collects a diagnostic trace from a currently running process.
        /// </summary>
        /// <param name="ct">The cancellation token</param>
        /// <param name="console"></param>
        /// <param name="processId">The process to collect the trace from.</param>
        /// <param name="name">The name of process to collect the trace from.</param>
        /// <param name="output">The output path for the collected trace data.</param>
        /// <param name="buffersize">Sets the size of the in-memory circular buffer in megabytes.</param>
        /// <param name="providers">A list of EventPipe providers to be enabled. This is in the form 'Provider[,Provider]', where Provider is in the form: 'KnownProviderName[:Flags[:Level][:KeyValueArgs]]', and KeyValueArgs is in the form: '[key1=value1][;key2=value2]'</param>
        /// <param name="profile">A named pre-defined set of provider configurations that allows common tracing scenarios to be specified succinctly.</param>
        /// <param name="format">The desired format of the created trace file.</param>
        /// <param name="duration">The duration of trace to be taken. </param>
        /// <param name="clrevents">A list of CLR events to be emitted.</param>
        /// <param name="clreventlevel">The verbosity level of CLR events</param>
        /// <returns></returns>
        private static async Task <int> Collect(CancellationToken ct, IConsole console, int processId, FileInfo output, uint buffersize, string providers, string profile, TraceFileFormat format, TimeSpan duration, string clrevents, string clreventlevel, string name)
        {
            try
            {
                Debug.Assert(output != null);
                Debug.Assert(profile != null);

                // Either processName or processId has to be specified.
                if (name != null)
                {
                    if (processId != 0)
                    {
                        Console.WriteLine("Can only specify either --name or --process-id option.");
                        return(ErrorCodes.ArgumentError);
                    }
                    processId = CommandUtils.FindProcessIdWithName(name);
                    if (processId < 0)
                    {
                        return(ErrorCodes.ArgumentError);
                    }
                }

                if (processId < 0)
                {
                    Console.Error.WriteLine("Process ID should not be negative.");
                    return(ErrorCodes.ArgumentError);
                }
                else if (processId == 0)
                {
                    Console.Error.WriteLine("--process-id is required");
                    return(ErrorCodes.ArgumentError);
                }

                if (profile.Length == 0 && providers.Length == 0 && clrevents.Length == 0)
                {
                    Console.Out.WriteLine("No profile or providers specified, defaulting to trace profile 'cpu-sampling'");
                    profile = "cpu-sampling";
                }

                Dictionary <string, string> enabledBy = new Dictionary <string, string>();

                var providerCollection = Extensions.ToProviders(providers);
                foreach (EventPipeProvider providerCollectionProvider in providerCollection)
                {
                    enabledBy[providerCollectionProvider.Name] = "--providers ";
                }

                if (profile.Length != 0)
                {
                    var selectedProfile = ListProfilesCommandHandler.DotNETRuntimeProfiles
                                          .FirstOrDefault(p => p.Name.Equals(profile, StringComparison.OrdinalIgnoreCase));
                    if (selectedProfile == null)
                    {
                        Console.Error.WriteLine($"Invalid profile name: {profile}");
                        return(ErrorCodes.ArgumentError);
                    }

                    Profile.MergeProfileAndProviders(selectedProfile, providerCollection, enabledBy);
                }

                // Parse --clrevents parameter
                if (clrevents.Length != 0)
                {
                    // Ignore --clrevents if CLR event provider was already specified via --profile or --providers command.
                    if (enabledBy.ContainsKey(Extensions.CLREventProviderName))
                    {
                        Console.WriteLine($"The argument --clrevents {clrevents} will be ignored because the CLR provider was configured via either --profile or --providers command.");
                    }
                    else
                    {
                        var clrProvider = Extensions.ToCLREventPipeProvider(clrevents, clreventlevel);
                        providerCollection.Add(clrProvider);
                        enabledBy[Extensions.CLREventProviderName] = "--clrevents";
                    }
                }


                if (providerCollection.Count <= 0)
                {
                    Console.Error.WriteLine("No providers were specified to start a trace.");
                    return(ErrorCodes.ArgumentError);
                }

                PrintProviders(providerCollection, enabledBy);

                var process    = Process.GetProcessById(processId);
                var shouldExit = new ManualResetEvent(false);
                var shouldStopAfterDuration       = duration != default(TimeSpan);
                var rundownRequested              = false;
                System.Timers.Timer durationTimer = null;

                ct.Register(() => shouldExit.Set());

                var diagnosticsClient = new DiagnosticsClient(processId);
                using (VirtualTerminalMode vTermMode = VirtualTerminalMode.TryEnable())
                {
                    EventPipeSession session = null;
                    try
                    {
                        session = diagnosticsClient.StartEventPipeSession(providerCollection, true, (int)buffersize);
                    }
                    catch (DiagnosticsClientException e)
                    {
                        Console.Error.WriteLine($"Unable to start a tracing session: {e.ToString()}");
                    }

                    if (session == null)
                    {
                        Console.Error.WriteLine("Unable to create session.");
                        return(ErrorCodes.SessionCreationError);
                    }

                    if (shouldStopAfterDuration)
                    {
                        durationTimer           = new System.Timers.Timer(duration.TotalMilliseconds);
                        durationTimer.Elapsed  += (s, e) => shouldExit.Set();
                        durationTimer.AutoReset = false;
                    }

                    var stopwatch = new Stopwatch();
                    durationTimer?.Start();
                    stopwatch.Start();

                    LineRewriter rewriter = null;

                    using (var fs = new FileStream(output.FullName, FileMode.Create, FileAccess.Write))
                    {
                        Console.Out.WriteLine($"Process        : {process.MainModule.FileName}");
                        Console.Out.WriteLine($"Output File    : {fs.Name}");
                        if (shouldStopAfterDuration)
                        {
                            Console.Out.WriteLine($"Trace Duration : {duration.ToString(@"dd\:hh\:mm\:ss")}");
                        }
                        Console.Out.WriteLine("\n\n");

                        var  fileInfo = new FileInfo(output.FullName);
                        Task copyTask = session.EventStream.CopyToAsync(fs);

                        if (!Console.IsOutputRedirected)
                        {
                            rewriter = new LineRewriter {
                                LineToClear = Console.CursorTop - 1
                            };
                            Console.CursorVisible = false;
                        }

                        Action printStatus = () =>
                        {
                            if (!Console.IsOutputRedirected)
                            {
                                rewriter?.RewriteConsoleLine();
                            }

                            fileInfo.Refresh();
                            Console.Out.WriteLine($"[{stopwatch.Elapsed.ToString(@"dd\:hh\:mm\:ss")}]\tRecording trace {GetSize(fileInfo.Length)}");
                            Console.Out.WriteLine("Press <Enter> or <Ctrl+C> to exit...");
                            if (rundownRequested)
                            {
                                Console.Out.WriteLine("Stopping the trace. This may take up to minutes depending on the application being traced.");
                            }
                        };

                        while (!shouldExit.WaitOne(100) && !(!Console.IsInputRedirected && Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Enter))
                        {
                            printStatus();
                        }

                        // Behavior concerning Enter moving text in the terminal buffer when at the bottom of the buffer
                        // is different between Console/Terminals on Windows and Mac/Linux
                        if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
                            !Console.IsOutputRedirected &&
                            rewriter != null &&
                            Math.Abs(Console.CursorTop - Console.BufferHeight) == 1)
                        {
                            rewriter.LineToClear--;
                        }
                        durationTimer?.Stop();
                        rundownRequested = true;
                        session.Stop();

                        do
                        {
                            printStatus();
                        } while (!copyTask.Wait(100));
                    }

                    Console.Out.WriteLine("\nTrace completed.");

                    if (format != TraceFileFormat.NetTrace)
                    {
                        TraceFileFormatConverter.ConvertToFormat(format, output.FullName);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
                return(ErrorCodes.TracingError);
            }
            finally
            {
                if (console.GetTerminal() != null)
                {
                    Console.CursorVisible = true;
                }
            }

            return(await Task.FromResult(0));
        }
Ejemplo n.º 26
0
        public static async Task <int> Collect(ICollection <Action <long> > sizeChangeCallbacks, CollectTrace.Tracing tracing, FileInfo output, TraceFileFormat format = TraceFileFormat.NetTrace)
        {
            var processId = Process.GetCurrentProcess().Id;

            var providerCollection = CreateProviderCollection();

            var diagnosticsClient    = new DiagnosticsClient(processId);
            EventPipeSession session = null;

            try
            {
                session = diagnosticsClient.StartEventPipeSession(providerCollection, true);
            }
            catch (DiagnosticsClientException e)
            {
                Console.Error.WriteLine($"Unable to start a tracing session: {e.ToString()}");
            }

            if (session == null)
            {
                Console.Error.WriteLine("Unable to create session.");
                return(ErrorCodes.SessionCreationError);
            }

            var failed     = false;
            var terminated = false;

            try
            {
                var collectingTask = new Task(() =>
                {
                    try
                    {
                        using (var fs = new FileStream(output.FullName, FileMode.Create, FileAccess.Write))
                        {
                            var buffer = new byte[16 * 1024];

                            while (true)
                            {
                                int nBytesRead = session.EventStream.Read(buffer, 0, buffer.Length);
                                if (nBytesRead <= 0)
                                {
                                    break;
                                }
                                fs.Write(buffer, 0, nBytesRead);
                                foreach (var sizeChangeCallback in sizeChangeCallbacks)
                                {
                                    sizeChangeCallback(fs.Length);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        failed = true;
                        Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
                    }
                    finally
                    {
                        terminated = true;
                    }
                });
                collectingTask.Start();

                tracing.Wait();

                session.Stop();

                await collectingTask;

                //if (format != TraceFileFormat.NetTrace)
                //    TraceFileFormatConverter.ConvertToFormat(format, output.FullName);

                return(failed ? ErrorCodes.TracingError : 0);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
                return(ErrorCodes.UnknownError);
            }
        }
        private async Task StartTracing(Action <string> log)
        {
            var providers = new List <EventPipeProvider>()
            {
                // Runtime Metrics
                new EventPipeProvider(
                    "System.Runtime",
                    EventLevel.Informational,
                    0,
                    new Dictionary <string, string>()
                {
                    { "EventCounterIntervalSec", "1" }
                }
                    ),

                // new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", EventLevel.Informational),
                new EventPipeProvider("Microsoft-Windows-DotNETRuntime", EventLevel.Informational, 65536 | 32768),//ClrTraceEventParser.Keywords.Default)

                // Activity correlation
                new EventPipeProvider("System.Threading.Tasks.TplEventSource",
                                      keywords: 511,
                                      eventLevel: EventLevel.LogAlways),
            };

            log($"Starting event pipe session for pid {Process.GetCurrentProcess().Id}");

            EventPipeSession session = null;
            var client = new DiagnosticsClient(Process.GetCurrentProcess().Id);

            try
            {
                session = client.StartEventPipeSession(providers);
            }
            catch (EndOfStreamException)
            {
            }
            // If the process has already exited, a ServerNotAvailableException will be thrown.
            catch (ServerNotAvailableException)
            {
            }
            catch (Exception)
            {
                // We can't even start the session, wait until the process boots up again to start another metrics thread
            }

            void StopSession()
            {
                try
                {
                    session.Stop();
                }
                catch (EndOfStreamException)
                {
                    // If the app we're monitoring exits abruptly, this may throw in which case we just swallow the exception and exit gracefully.
                }
                // We may time out if the process ended before we sent StopTracing command. We can just exit in that case.
                catch (TimeoutException)
                {
                }
                // On Unix platforms, we may actually get a PNSE since the pipe is gone with the process, and Runtime Client Library
                // does not know how to distinguish a situation where there is no pipe to begin with, or where the process has exited
                // before dotnet-counters and got rid of a pipe that once existed.
                // Since we are catching this in StopMonitor() we know that the pipe once existed (otherwise the exception would've
                // been thrown in StartMonitor directly)
                catch (PlatformNotSupportedException)
                {
                }
                // If the process has already exited, a ServerNotAvailableException will be thrown.
                // This can always race with tye shutting down and a process being restarted on exiting.
                catch (ServerNotAvailableException)
                {
                }
            }

            var _ = _cts.Token.Register(() => StopSession());

            try
            {
                using var traceOutput = File.Create("trace.nettrace");

                await session.EventStream.CopyToAsync(traceOutput);
            }
            catch (DiagnosticsClientException)
            {
            }
            catch (Exception)
            {
                // This fails if stop is called or if the process dies
            }
            finally
            {
                session?.Dispose();
            }
        }
Ejemplo n.º 28
0
        public static int RunTest()
        {
            bool success             = true;
            int  allTypesEventCount  = 0;
            int  arrayTypeEventCount = 0;
            int  emptyEventCount     = 0;
            int  simpleEventCount    = 0;

            try
            {
                List <EventPipeProvider> providers = new List <EventPipeProvider>
                {
                    new EventPipeProvider("MySuperAwesomeEventPipeProvider", EventLevel.Verbose)
                };

                using (EventPipeSession session = ProfilerControlHelpers.AttachEventPipeSessionToSelf(providers))
                {
                    TriggerMethod();

                    ManualResetEvent allEventsReceivedEvent = new ManualResetEvent(false);

                    var source = new EventPipeEventSource(session.EventStream);
                    source.Dynamic.All += (TraceEvent traceEvent) =>
                    {
                        if (traceEvent.ProviderName != "MySuperAwesomeEventPipeProvider")
                        {
                            return;
                        }

                        if (traceEvent.EventName == "AllTypesEvent")
                        {
                            success &= ValidateAllTypesEvent(traceEvent);
                            ++allTypesEventCount;
                        }
                        else if (traceEvent.EventName == "EmptyEvent")
                        {
                            success &= ValidateEmptyEvent(traceEvent);
                            ++emptyEventCount;
                        }
                        else if (traceEvent.EventName == "SimpleEvent")
                        {
                            success &= ValidateSimpleEvent(traceEvent, simpleEventCount);
                            ++simpleEventCount;
                        }
                        else if (traceEvent.EventName == "ArrayTypeEvent")
                        {
                            success &= ValidateArrayTypeEvent(traceEvent);
                            ++arrayTypeEventCount;
                        }

                        if (AllEventsReceived(allTypesEventCount, arrayTypeEventCount, emptyEventCount, simpleEventCount))
                        {
                            allEventsReceivedEvent.Set();
                        }
                    };

                    Thread processingThread = new Thread(new ThreadStart(() =>
                    {
                        source.Process();
                    }));
                    processingThread.Start();

                    // The events are fired in the JITCompilationStarted callback for TriggerMethod,
                    // so by the time we are here, all events should be fired.
                    session.Stop();

                    allEventsReceivedEvent.WaitOne(TimeSpan.FromSeconds(90));
                    processingThread.Join();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine($"Exception {e.Message} when trying to attach");
                success = false;
            }

            if (success && AllEventsReceived(allTypesEventCount, arrayTypeEventCount, emptyEventCount, simpleEventCount))
            {
                return(100);
            }
            else
            {
                Console.WriteLine("Test validation failed (EventPipeClient.exe)");
                Console.WriteLine($"    success={success}");
                Console.WriteLine($"    allTypesEventCount={allTypesEventCount} ");
                Console.WriteLine($"    arrayTypeEventCount={arrayTypeEventCount} ");
                Console.WriteLine($"    emptyEventCount={emptyEventCount}");
                Console.WriteLine($"    simpleEventCount={simpleEventCount}");
                return(-1);
            }
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Reports a stack trace
        /// </summary>
        /// <param name="ct">The cancellation token</param>
        /// <param name="console"></param>
        /// <param name="processId">The process to report the stack from.</param>
        /// <param name="name">The name of process to report the stack from.</param>
        /// <param name="output">The output path for the collected trace data.</param>
        /// <param name="duration">The duration of to trace the target for. </param>
        /// <returns></returns>
        private static async Task <int> Report(CancellationToken ct, IConsole console, int processId, string name, TimeSpan duration)
        {
            string tempNetTraceFilename = Path.GetRandomFileName() + ".nettrace";
            string tempEtlxFilename     = "";

            try
            {
                // Either processName or processId has to be specified.
                if (!string.IsNullOrEmpty(name))
                {
                    if (processId != 0)
                    {
                        Console.WriteLine("Can only specify either --name or --process-id option.");
                        return(-1);
                    }
                    processId = CommandUtils.FindProcessIdWithName(name);
                    if (processId < 0)
                    {
                        return(-1);
                    }
                }

                if (processId < 0)
                {
                    console.Error.WriteLine("Process ID should not be negative.");
                    return(-1);
                }
                else if (processId == 0)
                {
                    console.Error.WriteLine("--process-id is required");
                    return(-1);
                }


                var client    = new DiagnosticsClient(processId);
                var providers = new List <EventPipeProvider>()
                {
                    new EventPipeProvider("Microsoft-DotNETCore-SampleProfiler", EventLevel.Informational)
                };

                // collect a *short* trace with stack samples
                // the hidden '--duration' flag can increase the time of this trace in case 10ms
                // is too short in a given environment, e.g., resource constrained systems
                // N.B. - This trace INCLUDES rundown.  For sufficiently large applications, it may take non-trivial time to collect
                //        the symbol data in rundown.
                using (EventPipeSession session = client.StartEventPipeSession(providers))
                    using (FileStream fs = File.OpenWrite(tempNetTraceFilename))
                    {
                        Task copyTask = session.EventStream.CopyToAsync(fs);
                        await Task.Delay(duration);

                        session.Stop();

                        // check if rundown is taking more than 5 seconds and add comment to report
                        Task timeoutTask   = Task.Delay(TimeSpan.FromSeconds(5));
                        Task completedTask = await Task.WhenAny(copyTask, timeoutTask);

                        if (completedTask == timeoutTask)
                        {
                            console.Out.WriteLine($"# Sufficiently large applications can cause this command to take non-trivial amounts of time");
                        }
                        await copyTask;
                    }

                // using the generated trace file, symbolocate and compute stacks.
                tempEtlxFilename = TraceLog.CreateFromEventPipeDataFile(tempNetTraceFilename);
                using (var symbolReader = new SymbolReader(System.IO.TextWriter.Null)
                {
                    SymbolPath = SymbolPath.MicrosoftSymbolServerPath
                })
                    using (var eventLog = new TraceLog(tempEtlxFilename))
                    {
                        var stackSource = new MutableTraceEventStackSource(eventLog)
                        {
                            OnlyManagedCodeStacks = true
                        };

                        var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader);
                        computer.GenerateThreadTimeStacks(stackSource);

                        var samplesForThread = new Dictionary <int, List <StackSourceSample> >();

                        stackSource.ForEach((sample) =>
                        {
                            var stackIndex = sample.StackIndex;
                            while (!stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), false).StartsWith("Thread ("))
                            {
                                stackIndex = stackSource.GetCallerIndex(stackIndex);
                            }

                            // long form for: int.Parse(threadFrame["Thread (".Length..^1)])
                            // Thread id is in the frame name as "Thread (<ID>)"
                            string template    = "Thread (";
                            string threadFrame = stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), false);
                            int threadId       = int.Parse(threadFrame.Substring(template.Length, threadFrame.Length - (template.Length + 1)));

                            if (samplesForThread.TryGetValue(threadId, out var samples))
                            {
                                samples.Add(sample);
                            }
                            else
                            {
                                samplesForThread[threadId] = new List <StackSourceSample>()
                                {
                                    sample
                                };
                            }
                        });

                        // For every thread recorded in our trace, print the first stack
                        foreach (var(threadId, samples) in samplesForThread)
                        {
#if DEBUG
                            console.Out.WriteLine($"Found {samples.Count} stacks for thread 0x{threadId:X}");
#endif
                            PrintStack(console, threadId, samples[0], stackSource);
                        }
                    }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
                return(-1);
            }
            finally
            {
                if (File.Exists(tempNetTraceFilename))
                {
                    File.Delete(tempNetTraceFilename);
                }
                if (File.Exists(tempEtlxFilename))
                {
                    File.Delete(tempEtlxFilename);
                }
            }

            return(0);
        }
Ejemplo n.º 30
0
        private async Task <int> Start()
        {
            string providerString = BuildProviderString();

            if (providerString.Length == 0)
            {
                return(1);
            }

            _renderer.Initialize();

            Task monitorTask = new Task(() => {
                try
                {
                    _session = _diagnosticsClient.StartEventPipeSession(Trace.Extensions.ToProviders(providerString), false, 10);
                    if (shouldResumeRuntime)
                    {
                        _diagnosticsClient.ResumeRuntime();
                    }
                    var source          = new EventPipeEventSource(_session.EventStream);
                    source.Dynamic.All += DynamicAllMonitor;
                    _renderer.EventPipeSourceConnected();
                    source.Process();
                }
                catch (DiagnosticsClientException ex)
                {
                    Console.WriteLine($"Failed to start the counter session: {ex.ToString()}");
                }
                catch (Exception ex)
                {
                    Debug.WriteLine($"[ERROR] {ex.ToString()}");
                }
                finally
                {
                    shouldExit.Set();
                }
            });

            monitorTask.Start();

            while (!shouldExit.WaitOne(250))
            {
                while (true)
                {
                    if (shouldExit.WaitOne(250))
                    {
                        StopMonitor();
                        return(0);
                    }
                    if (Console.KeyAvailable)
                    {
                        break;
                    }
                }
                ConsoleKey cmd = Console.ReadKey(true).Key;
                if (cmd == ConsoleKey.Q)
                {
                    StopMonitor();
                    break;
                }
                else if (cmd == ConsoleKey.P)
                {
                    pauseCmdSet = true;
                }
                else if (cmd == ConsoleKey.R)
                {
                    pauseCmdSet = false;
                }
            }
            return(await Task.FromResult(0));
        }