示例#1
0
        // Method copied from https://github.com/dotnet/diagnostics/blob/2c23d3265dd8f642a8d6cf4bb8a135a5ff8b00c2/src/Tools/dotnet-trace/TraceFileFormatConverter.cs#L64
        private static void ConvertToSpeedscope(string fileToConvert, string outputFilename, bool continueOnError = false)
        {
            var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert, null, new TraceLogOptions()
            {
                ContinueOnError = continueOnError
            });

            using (var symbolReader = new SymbolReader(System.IO.TextWriter.Null)
            {
                SymbolPath = SymbolPath.MicrosoftSymbolServerPath
            })
                using (var eventLog = new TraceLog(etlxFilePath))
                {
                    var stackSource = new MutableTraceEventStackSource(eventLog)
                    {
                        OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks.
                    };

                    var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader)
                    {
                        IncludeEventSourceEvents = false // SpeedScope handles only CPU samples, events are not supported
                    };
                    computer.GenerateThreadTimeStacks(stackSource);

                    SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename);
                }

            if (File.Exists(etlxFilePath))
            {
                File.Delete(etlxFilePath);
            }
        }
示例#2
0
        private static void ConvertToSpeedscope(string fileToConvert, string outputFilename)
        {
            var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert);

            using (var symbolReader = new SymbolReader(System.IO.TextWriter.Null)
            {
                SymbolPath = SymbolPath.MicrosoftSymbolServerPath
            })
                using (var eventLog = new TraceLog(etlxFilePath))
                {
                    var stackSource = new MutableTraceEventStackSource(eventLog)
                    {
                        OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks.
                    };

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

                    SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename);
                }

            if (File.Exists(etlxFilePath))
            {
                File.Delete(etlxFilePath);
            }
        }
示例#3
0
        private static void ConvertToSpeedscope(string fileToConvert)
        {
            var symbolReader = new SymbolReader(System.IO.TextWriter.Null)
            {
                SymbolPath = SymbolPath.MicrosoftSymbolServerPath
            };
            var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert);

            var eventLog = new TraceLog(etlxFilePath);

            try
            {
                var stackSource = new MutableTraceEventStackSource(eventLog)
                {
                    OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks.
                };

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

                var speedScopeFilePath = Path.ChangeExtension(fileToConvert, "speedscope.json");

                SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, speedScopeFilePath);
            }
            finally
            {
                eventLog.Dispose();

                if (File.Exists(etlxFilePath))
                {
                    File.Delete(etlxFilePath);
                }
            }
        }
示例#4
0
        public void RunTests()
        {
            // Get the configuration and start tracing.
            TraceConfiguration traceConfig = GenerateConfiguration();

            TraceControl.Enable(traceConfig);

            // Run the tests.
            foreach (EventSourceTest test in m_tests)
            {
                test.LogEvent();
            }

            // Stop tracing.
            TraceControl.Disable();

            // Open the trace file.
            string traceLogPath = TraceLog.CreateFromEventPipeDataFile(m_file.Path);

            using (TraceLog traceLog = new TraceLog(traceLogPath))
            {
                TraceEventDispatcher dispatcher = traceLog.Events.GetSource();

                dispatcher.Dynamic.All += delegate(TraceEvent data)
                {
                    if (data.ProviderName.EndsWith("Rundown"))
                    {
                        return;
                    }

                    if (data.ProviderName.Equals("Microsoft-DotNETCore-EventPipe"))
                    {
                        return;
                    }

                    Assert.True($"m_nextTestVerificationIndex({m_nextTestVerificationIndex}) < m_tests.Count({m_tests.Count})", m_nextTestVerificationIndex < m_tests.Count);
                    try
                    {
                        Console.WriteLine($"Verifying Event: {data.ToString()}");
                        m_tests[m_nextTestVerificationIndex].VerifyEvent(data);
                    }
                    catch
                    {
                        Console.WriteLine($"Failure during test '{m_tests[m_nextTestVerificationIndex].Name}'.");
                        throw;
                    }

                    m_nextTestVerificationIndex++;
                };

                dispatcher.Process();
                Assert.Equal("Test Count", m_tests.Count, m_nextTestVerificationIndex);
            }
        }
示例#5
0
 private static void DumpNetTrace(string filePath)
 {
     using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(filePath)).Events.GetSource())
     {
         trace.Dynamic.All += (TraceEvent e) => {
             if (!string.IsNullOrWhiteSpace(e.ProviderName) && !string.IsNullOrWhiteSpace(e.EventName))
             {
                 Debug.WriteLine($"Event Provider: {e.ProviderName}");
                 Debug.WriteLine($"    Event Name: {e.EventName}");
             }
         };
         trace.Process();
     }
 }
示例#6
0
        private static void ValidateNetTrace(string filePath)
        {
            var nEventPipeResults = 0;

            using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(filePath)).Events.GetSource())
            {
                trace.Dynamic.All += (TraceEvent data) => {
                    ++nEventPipeResults;
                };
                trace.Process();
            }

            // Assert there were events in the file.
            Assert.NotEqual("Found events in trace file", nEventPipeResults, 0);
        }
        private static void Convert(TraceFileFormat format, string fileToConvert, string outputFilename, bool continueOnError = false)
        {
            var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(fileToConvert, null, new TraceLogOptions()
            {
                ContinueOnError = continueOnError
            });

            using (var symbolReader = new SymbolReader(TextWriter.Null)
            {
                SymbolPath = SymbolPath.MicrosoftSymbolServerPath
            })
                using (var eventLog = new TraceLog(etlxFilePath))
                {
                    var stackSource = new MutableTraceEventStackSource(eventLog)
                    {
                        OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks.
                    };

                    var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader)
                    {
                        IncludeEventSourceEvents = false // SpeedScope handles only CPU samples, events are not supported
                    };
                    computer.GenerateThreadTimeStacks(stackSource);

                    switch (format)
                    {
                    case TraceFileFormat.Speedscope:
                        SpeedScopeStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename);
                        break;

                    case TraceFileFormat.Chromium:
                        ChromiumStackSourceWriter.WriteStackViewAsJson(stackSource, outputFilename, compress: false);
                        break;

                    default:
                        // we should never get here
                        throw new ArgumentException($"Invalid TraceFileFormat \"{format}\"");
                    }
                }

            if (File.Exists(etlxFilePath))
            {
                File.Delete(etlxFilePath);
            }
        }
示例#8
0
        public void GuidsInMetadataAreSupported()
        {
            PrepareTestData();

            const string eventPipeFileName  = "eventpipe-dotnetcore2.1-linux-x64-objver3.netperf";
            Guid         ExpectedActivityId = new Guid("10000000-0000-0000-0000-000000000001");

            string eventPipeFilePath = Path.Combine(UnZippedDataDir, eventPipeFileName);

            bool activityIdHasBeenSet = false;

            using (var traceSource = new TraceLog(TraceLog.CreateFromEventPipeDataFile(eventPipeFilePath)).Events.GetSource())
            {
                traceSource.AllEvents += (TraceEvent @event) =>
                {
                    // before the activity Id is set, it's empty
                    // after the activity Id is set, all the events should have it (here we had only 1 thread)
                    Assert.Equal(activityIdHasBeenSet ? ExpectedActivityId : Guid.Empty, @event.ActivityID);

                    // the EVENTID for SetActivityId is 25 https://github.com/dotnet/coreclr/blob/c67c29d6e226e4cca1f1efb4d57b7f498d58b534/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs#L524
                    if (@event.ProviderName != TplEtwProviderTraceEventParser.ProviderName || @event.ID != (TraceEventID)25)
                    {
                        return;
                    }

                    Assert.False(activityIdHasBeenSet); // make sure the event comes only once

                    // Sneak in a test of the DLR support here (casting to 'dynamic'
                    // instead of using PayloadByName("NewId")):
                    if (((dynamic)@event).NewId.Equals(ExpectedActivityId))
                    {
                        activityIdHasBeenSet = true;
                    }
                };

                traceSource.Process();

                Assert.True(activityIdHasBeenSet);
            }
        }
示例#9
0
        public void Basic(string eventPipeFileName)
        {
            // Initialize
            PrepareTestData();

            string eventPipeFilePath = Path.Combine(UnZippedDataDir, eventPipeFileName);

            Output.WriteLine(string.Format("Processing the file {0}, Making ETLX and scanning.", Path.GetFullPath(eventPipeFilePath)));

            var eventStatistics = new SortedDictionary <string, EventRecord>(StringComparer.Ordinal);

            using (var traceLog = new TraceLog(TraceLog.CreateFromEventPipeDataFile(eventPipeFilePath)))
            {
                var traceSource = traceLog.Events.GetSource();

                traceSource.AllEvents += delegate(TraceEvent data)
                {
                    string eventName = data.ProviderName + "/" + data.EventName;

                    if (eventStatistics.ContainsKey(eventName))
                    {
                        eventStatistics[eventName].TotalCount++;
                    }
                    else
                    {
                        eventStatistics[eventName] = new EventRecord()
                        {
                            TotalCount            = 1,
                            FirstSeriazliedSample = new String(data.ToString().Replace("\n", "\\n").Replace("\r", "\\r").Take(1000).ToArray())
                        };
                    }
                };

                // Process
                traceSource.Process();
            }
            // Validate
            ValidateEventStatistics(eventStatistics, eventPipeFileName);
        }
示例#10
0
        public void AllEventsLeavesNoUnhandledEvents()
        {
            PrepareTestData();

            const string eventPipeFileName = "eventpipe-dotnetcore2.1-win-x86-objver3.netperf";

            string eventPipeFilePath = Path.Combine(UnZippedDataDir, eventPipeFileName);

            using (var traceSource = new TraceLog(TraceLog.CreateFromEventPipeDataFile(eventPipeFilePath)).Events.GetSource())
            {
                int dynamicAllInvocationCount = 0;
                int unhandledEvents           = 0;

                traceSource.AllEvents += _ => dynamicAllInvocationCount++;

                traceSource.UnhandledEvents += _ => unhandledEvents++;

                traceSource.Process();

                Assert.NotEqual(0, dynamicAllInvocationCount);
                Assert.Equal(0, unhandledEvents);
            }
        }
示例#11
0
        private static void RoundTwo(string[] args)
        {
            using (var netPerfFile = NetPerfFile.Create(args))
            {
                using (var etlFile = EtlFile.Create(args))
                {
                    Console.WriteLine("\tStart: Enable EventPipe.");
                    TraceControl.Enable(EventPipeGetConfig(EventPipeAndEtwEventSource.Log, EventPipeAndEtwEventSource.Keywords.EventPipeKeyword, netPerfFile.Path));
                    Console.WriteLine("\tEnd: Enable EventPipe.\n");

                    Console.WriteLine("\tStart: Enable ETW.");
                    TraceEventSession etwSession = EnableETW(EventPipeAndEtwEventSource.Log, EventPipeAndEtwEventSource.Keywords.EtwKeyword, etlFile.Path);
                    Console.WriteLine("\tEnd: Enable ETW.\n");

                    WriteAllEvents(EventPipeAndEtwEventSource.Log);

                    Console.WriteLine("\tStart: Disable EventPipe.");
                    TraceControl.Disable();
                    Console.WriteLine("\tEnd: Disable EventPipe.\n");

                    WriteAllEvents(EventPipeAndEtwEventSource.Log);

                    Console.WriteLine("\tStart: Disable ETW.");
                    DisableETW(etwSession);
                    Console.WriteLine("\tEnd: Disable ETW.\n");

                    Console.WriteLine("\tStart: Processing events from EventPipe file.");

                    EventResults eventPipeResults = new EventResults();
                    EventResults etwResults       = new EventResults();

                    using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(netPerfFile.Path)).Events.GetSource())
                    {
                        trace.Dynamic.All += delegate(TraceEvent data)
                        {
                            eventPipeResults.AddEvent(data);
                        };

                        trace.Process();
                    }

                    // Validate EventPipe results.
                    eventPipeResults.Print("EventPipe Results:");
                    Assert.Equal("EventPipeEvent1Count", eventPipeResults.Event1Count, 1);
                    Assert.Equal("EventPipeEvent2Count", eventPipeResults.Event2Count, 0);
                    Assert.Equal("EventPipeEvent3Count", eventPipeResults.Event3Count, 1);

                    Console.WriteLine("\tEnd: Processing events from EventPipe file.\n");

                    Console.WriteLine("\tStart: Processing events from ETW file.");

                    using (var trace = new ETWTraceEventSource(etlFile.Path))
                    {
                        trace.Dynamic.All += delegate(TraceEvent data)
                        {
                            etwResults.AddEvent(data);
                        };

                        trace.Process();
                    }

                    // Validate ETW results.
                    etwResults.Print("ETW Results:");
                    Assert.Equal("EventPipeEvent1Count", etwResults.Event1Count, 0);
                    Assert.Equal("EventPipeEvent2Count", etwResults.Event2Count, 2);
                    Assert.Equal("EventPipeEvent3Count", etwResults.Event3Count, 2);

                    Console.WriteLine("\tEnd: Processing events from ETW file.");
                }
            }
        }
示例#12
0
        static int Main(string[] args)
        {
            bool pass = true;

            using (SimpleEventSource eventSource = new SimpleEventSource())
            {
                using (var netPerfFile = NetPerfFile.Create(args))
                {
                    Console.WriteLine("\tStart: Enable tracing.");
                    TraceControl.Enable(GetConfig(eventSource, netPerfFile.Path));
                    Console.WriteLine("\tEnd: Enable tracing.\n");

                    Console.WriteLine("\tStart: Messaging.");
                    // Send messages
                    // Use random numbers and addition as a simple, human readble checksum
                    Random generator = new Random();
                    for (int i = 0; i < messageIterations; i++)
                    {
                        int    x       = generator.Next(1, 1000);
                        int    y       = generator.Next(1, 1000);
                        string formula = String.Format("{0} + {1} = {2}", x, y, x + y);

                        eventSource.MathResult(x, y, x + y, formula);
                    }
                    Console.WriteLine("\tEnd: Messaging.\n");

                    Console.WriteLine("\tStart: Disable tracing.");
                    TraceControl.Disable();
                    Console.WriteLine("\tEnd: Disable tracing.\n");

                    Console.WriteLine("\tStart: Processing events from file.");
                    int msgCount = 0;
                    using (var trace = new TraceLog(TraceLog.CreateFromEventPipeDataFile(netPerfFile.Path)).Events.GetSource())
                    {
                        var names = new HashSet <string>();

                        trace.Dynamic.All += delegate(TraceEvent data)
                        {
                            if (!names.Contains(data.ProviderName))
                            {
                                Console.WriteLine("\t{0}", data.ProviderName);
                                names.Add(data.ProviderName);
                            }

                            if (data.ProviderName == "SimpleEventSource")
                            {
                                msgCount += 1;
                            }
                        };

                        trace.Process();
                    }
                    Console.WriteLine("\tEnd: Processing events from file.\n");

                    Console.WriteLine("\tProcessed {0} events from EventSource", msgCount);

                    pass &= msgCount == messageIterations;
                }
            }

            return(pass ? 100 : 0);
        }
示例#13
0
        public void CanConvertProvidedTraceFiles(string zippedTraceFileName)
        {
            var debugListenersCopy = new TraceListener[Debug.Listeners.Count];

            Debug.Listeners.CopyTo(debugListenersCopy, index: 0);
            Debug.Listeners.Clear();

            string fileToUnzip  = Path.Combine("inputs", "speedscope", zippedTraceFileName);
            string unzippedFile = Path.ChangeExtension(fileToUnzip, string.Empty);

            if (File.Exists(unzippedFile))
            {
                File.Delete(unzippedFile);
            }
            ZipFile.ExtractToDirectory(fileToUnzip, Path.GetDirectoryName(fileToUnzip));
            var etlxFilePath = TraceLog.CreateFromEventPipeDataFile(unzippedFile, null, new TraceLogOptions()
            {
                ContinueOnError = true
            });

            try
            {
                using (var symbolReader = new SymbolReader(TextWriter.Null)
                {
                    SymbolPath = SymbolPath.MicrosoftSymbolServerPath
                })
                    using (var eventLog = new TraceLog(etlxFilePath))
                    {
                        var stackSource = new MutableTraceEventStackSource(eventLog)
                        {
                            OnlyManagedCodeStacks = true // EventPipe currently only has managed code stacks.
                        };

                        var computer = new SampleProfilerThreadTimeComputer(eventLog, symbolReader)
                        {
                            IncludeEventSourceEvents = false // SpeedScope handles only CPU samples, events are not supported
                        };
                        computer.GenerateThreadTimeStacks(stackSource);

                        var samplesPerThread = GetSortedSamplesPerThread(stackSource);

                        var exportedFrameNameToExportedFrameId = new Dictionary <string, int>();
                        var exportedFrameIdToFrameTuple        = new Dictionary <int, FrameInfo>();
                        var profileEventsPerThread             = new Dictionary <string, IReadOnlyList <ProfileEvent> >();

                        foreach (var pair in samplesPerThread)
                        {
                            var sortedProfileEvents = GetProfileEvents(stackSource, pair.Value, exportedFrameNameToExportedFrameId, exportedFrameIdToFrameTuple);

                            Assert.True(Validate(sortedProfileEvents), "The output should be always valid");

                            profileEventsPerThread.Add(pair.Key.Name, sortedProfileEvents);
                        }
                        ;
                    }
            }
            finally
            {
                if (File.Exists(etlxFilePath))
                {
                    File.Delete(etlxFilePath);
                }
                if (File.Exists(unzippedFile))
                {
                    File.Delete(unzippedFile);
                }
                if (debugListenersCopy.Length > 0)
                {
                    Debug.Listeners.AddRange(debugListenersCopy);
                }
            }
        }
示例#14
0
        static async Task <int> Main(string[] args)
        {
            if (args.Length == 0 || args.Length > 1 || (args.Length == 1 && _helpFlags.Contains(args[0])))
            {
                PrintUsage();
                return(-1);
            }

            var pid = int.Parse(args[0]);

            var tempNetTraceFilename = Path.GetRandomFileName() + ".nettrace";
            var tempEtlxFilename     = "";

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

                using (EventPipeSession session = client.StartEventPipeSession(providers))
                    using (FileStream fs = File.OpenWrite(tempNetTraceFilename))
                    {
                        Task copyTask = session.EventStream.CopyToAsync(fs);
                        await Task.Delay(10);

                        session.Stop();
                        await copyTask;
                    }

                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 <string, List <StackSourceSample> >();

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

                            var threadName = stackSource.GetFrameName(stackSource.GetFrameIndex(stackIndex), false);
                            if (samplesForThread.TryGetValue(threadName, out var samples))
                            {
                                samples.Add(sample);
                            }
                            else
                            {
                                samplesForThread[threadName] = new List <StackSourceSample>()
                                {
                                    sample
                                };
                            }
                        });

                        foreach (var(threadName, samples) in samplesForThread)
                        {
#if DEBUG
                            Console.WriteLine($"Found {samples.Count} stacks for thread {threadName}");
#endif
                            PrintStack(threadName, samples[0], stackSource);
                        }
                    }
                return(0);
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e);
                return(-1);
            }
            finally
            {
                if (File.Exists(tempNetTraceFilename))
                {
                    File.Delete(tempNetTraceFilename);
                }
                if (File.Exists(tempEtlxFilename))
                {
                    File.Delete(tempEtlxFilename);
                }
            }
        }
示例#15
0
        static int InnerMain(FileInfo traceFile,
                             FileInfo outputFileName,
                             int?pid,
                             string processName,
                             PgoFileType?pgoFileType,
                             IEnumerable <FileInfo> reference,
                             int?clrInstanceId               = null,
                             bool processJitEvents           = true,
                             bool processR2REvents           = true,
                             bool displayProcessedEvents     = false,
                             bool validateOutputFile         = true,
                             bool verboseWarnings            = false,
                             jittraceoptions jitTraceOptions = jittraceoptions.sorted,
                             double excludeEventsBefore      = 0,
                             double excludeEventsAfter       = Double.MaxValue,
                             bool warnings = true)
        {
            s_reachedInnerMain = true;

            if (traceFile == null)
            {
                PrintUsage("--trace-file must be specified");
                return(-8);
            }

            if (outputFileName != null)
            {
                if (!pgoFileType.HasValue)
                {
                    PrintUsage($"--pgo-file-type must be specified");
                    return(-9);
                }
                if ((pgoFileType.Value != PgoFileType.jittrace) && (pgoFileType != PgoFileType.mibc))
                {
                    PrintUsage($"Invalid output pgo type {pgoFileType} specified.");
                    return(-9);
                }
                if (pgoFileType == PgoFileType.jittrace)
                {
                    if (!outputFileName.Name.EndsWith(".jittrace"))
                    {
                        PrintUsage($"jittrace output file name must end with .jittrace");
                        return(-9);
                    }
                }
                if (pgoFileType == PgoFileType.mibc)
                {
                    if (!outputFileName.Name.EndsWith(".mibc"))
                    {
                        PrintUsage($"jittrace output file name must end with .mibc");
                        return(-9);
                    }
                }
            }

            string etlFileName = traceFile.FullName;

            foreach (string nettraceExtension in new string[] { ".netperf", ".netperf.zip", ".nettrace" })
            {
                if (traceFile.FullName.EndsWith(nettraceExtension))
                {
                    etlFileName = traceFile.FullName.Substring(0, traceFile.FullName.Length - nettraceExtension.Length) + ".etlx";
                    Console.WriteLine($"Creating ETLX file {etlFileName} from {traceFile.FullName}");
                    TraceLog.CreateFromEventPipeDataFile(traceFile.FullName, etlFileName);
                }
            }

            string lttngExtension = ".trace.zip";

            if (traceFile.FullName.EndsWith(lttngExtension))
            {
                etlFileName = traceFile.FullName.Substring(0, traceFile.FullName.Length - lttngExtension.Length) + ".etlx";
                Console.WriteLine($"Creating ETLX file {etlFileName} from {traceFile.FullName}");
                TraceLog.CreateFromLttngTextDataFile(traceFile.FullName, etlFileName);
            }

            using (var traceLog = TraceLog.OpenOrConvert(etlFileName))
            {
                if ((!pid.HasValue && processName == null) && traceLog.Processes.Count != 1)
                {
                    Console.WriteLine("Either a pid or process name from the following list must be specified");
                    foreach (TraceProcess proc in traceLog.Processes)
                    {
                        Console.WriteLine($"Procname = {proc.Name} Pid = {proc.ProcessID}");
                    }
                    return(0);
                }

                if (pid.HasValue && (processName != null))
                {
                    PrintError("--pid and --process-name cannot be specified together");
                    return(-1);
                }

                // For a particular process
                TraceProcess p;
                if (pid.HasValue)
                {
                    p = traceLog.Processes.LastProcessWithID(pid.Value);
                }
                else if (processName != null)
                {
                    List <TraceProcess> matchingProcesses = new List <TraceProcess>();
                    foreach (TraceProcess proc in traceLog.Processes)
                    {
                        if (String.Compare(proc.Name, processName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            matchingProcesses.Add(proc);
                        }
                    }

                    if (matchingProcesses.Count == 0)
                    {
                        PrintError("Unable to find matching process in trace");
                        return(-1);
                    }
                    if (matchingProcesses.Count > 1)
                    {
                        StringBuilder errorMessage = new StringBuilder();

                        errorMessage.AppendLine("Found multiple matching processes in trace");
                        foreach (TraceProcess proc in matchingProcesses)
                        {
                            errorMessage.AppendLine($"{proc.Name}\tpid={proc.ProcessID}\tCPUMSec={proc.CPUMSec}");
                        }
                        PrintError(errorMessage.ToString());
                        return(-2);
                    }
                    p = matchingProcesses[0];
                }
                else
                {
                    p = traceLog.Processes.First();
                }

                if (!p.EventsInProcess.ByEventType <MethodDetailsTraceData>().Any())
                {
                    PrintError($"No MethodDetails\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-3);
                }

                if (!p.EventsInProcess.ByEventType <GCBulkTypeTraceData>().Any())
                {
                    PrintError($"No BulkType data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-4);
                }

                if (!p.EventsInProcess.ByEventType <ModuleLoadUnloadTraceData>().Any())
                {
                    PrintError($"No managed module load data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-5);
                }

                if (!p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>().Any())
                {
                    PrintError($"No managed jit starting data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-5);
                }

                if (processR2REvents)
                {
                    if (!p.EventsInProcess.ByEventType <R2RGetEntryPointTraceData>().Any())
                    {
                        PrintError($"No r2r entrypoint data. This is not an error as in this case we can examine the jitted methods only\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x6000080018:5\"?");
                    }
                }

                PgoTraceProcess pgoProcess = new PgoTraceProcess(p);

                if (!clrInstanceId.HasValue)
                {
                    HashSet <int> clrInstanceIds         = new HashSet <int>();
                    HashSet <int> examinedClrInstanceIds = new HashSet <int>();
                    foreach (var assemblyLoadTrace in p.EventsInProcess.ByEventType <AssemblyLoadUnloadTraceData>())
                    {
                        if (examinedClrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID))
                        {
                            if (pgoProcess.ClrInstanceIsCoreCLRInstance(assemblyLoadTrace.ClrInstanceID))
                            {
                                clrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID);
                            }
                        }
                    }

                    if (clrInstanceIds.Count != 1)
                    {
                        if (clrInstanceIds.Count == 0)
                        {
                            PrintError($"No managed CLR in target process, or per module information could not be loaded from the trace.");
                        }
                        else
                        {
                            // There are multiple clr processes... search for the one that implements
                            int[] clrInstanceIdsArray = clrInstanceIds.ToArray();
                            Array.Sort(clrInstanceIdsArray);
                            StringBuilder errorMessage = new StringBuilder();
                            errorMessage.AppendLine("Multiple CLR instances used in process. Choose one to examine with -clrInstanceID:<id> Valid ids:");
                            foreach (int instanceID in clrInstanceIds)
                            {
                                errorMessage.AppendLine(instanceID.ToString());
                            }
                            PrintError(errorMessage.ToString());
                        }
                        return(-10);
                    }
                    else
                    {
                        clrInstanceId = clrInstanceIds.First();
                    }
                }

                var tsc = new TraceTypeSystemContext(pgoProcess, clrInstanceId.Value, s_logger);

                if (verboseWarnings)
                {
                    Console.WriteLine($"{traceLog.EventsLost} Lost events");
                }

                bool filePathError = false;
                if (reference != null)
                {
                    foreach (FileInfo fileReference in reference)
                    {
                        if (!File.Exists(fileReference.FullName))
                        {
                            PrintError($"Unable to find reference '{fileReference.FullName}'");
                            filePathError = true;
                        }
                        else
                        {
                            tsc.GetModuleFromPath(fileReference.FullName);
                        }
                    }
                }

                if (filePathError)
                {
                    return(-6);
                }

                if (!tsc.Initialize())
                {
                    return(-12);
                }

                TraceRuntimeDescToTypeSystemDesc idParser = new TraceRuntimeDescToTypeSystemDesc(p, tsc, clrInstanceId.Value);

                SortedDictionary <int, ProcessedMethodData> methodsToAttemptToPrepare = new SortedDictionary <int, ProcessedMethodData>();

                if (processR2REvents)
                {
                    foreach (var e in p.EventsInProcess.ByEventType <R2RGetEntryPointTraceData>())
                    {
                        int    parenIndex = e.MethodSignature.IndexOf('(');
                        string retArg     = e.MethodSignature.Substring(0, parenIndex);
                        string paramsArgs = e.MethodSignature.Substring(parenIndex);
                        string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs;
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            if (!warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Skipped R2REntryPoint {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}");
                            continue;
                        }
                        MethodDesc method           = null;
                        string     extraWarningText = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, verboseWarnings);
                        }
                        catch (Exception exception)
                        {
                            extraWarningText = exception.ToString();
                        }

                        if (method == null)
                        {
                            if ((e.MethodNamespace == "dynamicClass") || !warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Unable to parse {methodNameFromEventDirectly} when looking up R2R methods");
                            if (extraWarningText != null)
                            {
                                PrintWarning(extraWarningText);
                            }
                            continue;
                        }
                        if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
                        {
                            methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad"));
                        }
                    }
                }

                // Find all the jitStart events.
                if (processJitEvents)
                {
                    foreach (var e in p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>())
                    {
                        int    parenIndex = e.MethodSignature.IndexOf('(');
                        string retArg     = e.MethodSignature.Substring(0, parenIndex);
                        string paramsArgs = e.MethodSignature.Substring(parenIndex);
                        string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs;
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            if (!warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Skipped {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}");
                            continue;
                        }

                        MethodDesc method           = null;
                        string     extraWarningText = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, verboseWarnings);
                        }
                        catch (Exception exception)
                        {
                            extraWarningText = exception.ToString();
                        }

                        if (method == null)
                        {
                            if (!warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Unable to parse {methodNameFromEventDirectly}");
                            if (extraWarningText != null)
                            {
                                PrintWarning(extraWarningText);
                            }
                            continue;
                        }

                        if ((e.TimeStampRelativeMSec >= excludeEventsBefore) && (e.TimeStampRelativeMSec <= excludeEventsAfter))
                        {
                            methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart"));
                        }
                    }
                }

                if (displayProcessedEvents)
                {
                    foreach (var entry in methodsToAttemptToPrepare)
                    {
                        MethodDesc method = entry.Value.Method;
                        string     reason = entry.Value.Reason;
                        Console.WriteLine($"{entry.Value.Millisecond.ToString("F4")} {reason} {method}");
                    }
                }

                Console.WriteLine($"Done processing input file");

                if (outputFileName == null)
                {
                    return(0);
                }

                // Deduplicate entries
                HashSet <MethodDesc>       methodsInListAlready = new HashSet <MethodDesc>();
                List <ProcessedMethodData> methodsUsedInProcess = new List <ProcessedMethodData>();
                foreach (var entry in methodsToAttemptToPrepare)
                {
                    if (methodsInListAlready.Add(entry.Value.Method))
                    {
                        methodsUsedInProcess.Add(entry.Value);
                    }
                }

                if (pgoFileType.Value == PgoFileType.jittrace)
                {
                    GenerateJittraceFile(outputFileName, methodsUsedInProcess, jitTraceOptions);
                }
                else if (pgoFileType.Value == PgoFileType.mibc)
                {
                    return(GenerateMibcFile(tsc, outputFileName, methodsUsedInProcess, validateOutputFile));
                }
            }
            return(0);
        }
示例#16
0
        public async Task <int> OnExecuteAsync(IConsole console, CommandLineApplication app)
        {
            var cleanupFiles = new List <string>();

            MemoryDump dump  = null;
            TraceLog   trace = null;

            if (Files == null || Files.Count == 0)
            {
                console.Error.WriteLine("No files were provided!");
                return(1);
            }

            try
            {
                foreach (var file in Files)
                {
                    if (file.EndsWith(".netperf"))
                    {
                        console.WriteLine($"Loading trace: {file} ...");
                        var etlx = TraceLog.CreateFromEventPipeDataFile(file);
                        console.WriteLine($"Convert trace to: {etlx}.");
                        cleanupFiles.Add(etlx);
                        trace = TraceLog.OpenOrConvert(etlx);
                    }
                    else
                    {
                        console.WriteLine($"Loading crash dump: {file} ...");
                        var target = DataTarget.LoadCrashDump(file);
                        // Assume there's only one
                        if (target.ClrVersions.Count > 1)
                        {
                            console.Error.WriteLine("Multiple CLR versions are present!");
                            return(1);
                        }

                        var runtime = target.ClrVersions[0].CreateRuntime();
                        dump = new MemoryDump(target, runtime);
                    }
                }

                if (dump == null && trace == null)
                {
                    console.Error.WriteLine("A dump or trace could not be loaded from the provided files");
                    return(1);
                }
                var session = new AnalysisSession(dump, trace);
                await(new CommandProcessor()).RunAsync(console, session, console.GetCtrlCToken());
                return(0);
            }
            finally
            {
                dump?.Dispose();
                trace?.Dispose();

                foreach (var file in cleanupFiles)
                {
                    if (File.Exists(file))
                    {
                        File.Delete(file);
                    }
                }
            }
        }
示例#17
0
        private static async Task <int> TopNReport(CancellationToken ct, IConsole console, string traceFile, int number, bool inclusive, bool verbose)
        {
            try
            {
                string tempEtlxFilename = TraceLog.CreateFromEventPipeDataFile(traceFile);
                int    count            = 0;
                int    index            = 0;
                List <CallTreeNodeBase> nodesToReport = new List <CallTreeNodeBase>();
                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);

                        FilterParams filterParams = new FilterParams()
                        {
                            FoldRegExs = "CPU_TIME;UNMANAGED_CODE_TIME;{Thread (}",
                        };
                        FilterStackSource filterStack = new FilterStackSource(filterParams, stackSource, ScalingPolicyKind.ScaleToData);
                        CallTree          callTree    = new(ScalingPolicyKind.ScaleToData);
                        callTree.StackSource = filterStack;

                        List <CallTreeNodeBase> callTreeNodes = null;

                        if (!inclusive)
                        {
                            callTreeNodes = callTree.ByIDSortedExclusiveMetric();
                        }
                        else
                        {
                            callTreeNodes = callTree.ByIDSortedInclusiveMetric();
                        }

                        int totalElements = callTreeNodes.Count;
                        while (count < number && index < totalElements)
                        {
                            CallTreeNodeBase node = callTreeNodes[index];
                            index++;
                            if (!unwantedMethodNames.Any(node.Name.Contains))
                            {
                                nodesToReport.Add(node);
                                count++;
                            }
                        }

                        PrintReportHelper.TopNWriteToStdOut(nodesToReport, inclusive, verbose);
                    }
                return(await Task.FromResult(0));
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"[ERROR] {ex.ToString()}");
            }

            return(await Task.FromResult(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);
        }
示例#19
0
        static int InnerProcessTraceFileMain(CommandLineOptions commandLineOptions)
        {
            if (commandLineOptions.TraceFile == null)
            {
                PrintUsage(commandLineOptions, "--trace must be specified");
                return(-8);
            }

            if (commandLineOptions.OutputFileName == null)
            {
                PrintUsage(commandLineOptions, "--output must be specified");
                return(-8);
            }

            if (commandLineOptions.OutputFileName != null)
            {
                if (!commandLineOptions.FileType.HasValue)
                {
                    PrintUsage(commandLineOptions, $"--pgo-file-type must be specified");
                    return(-9);
                }
                if ((commandLineOptions.FileType.Value != PgoFileType.jittrace) && (commandLineOptions.FileType != PgoFileType.mibc))
                {
                    PrintUsage(commandLineOptions, $"Invalid output pgo type {commandLineOptions.FileType} specified.");
                    return(-9);
                }
                if (commandLineOptions.FileType == PgoFileType.jittrace)
                {
                    if (!commandLineOptions.OutputFileName.Name.EndsWith(".jittrace"))
                    {
                        PrintUsage(commandLineOptions, $"jittrace output file name must end with .jittrace");
                        return(-9);
                    }
                }
                if (commandLineOptions.FileType == PgoFileType.mibc)
                {
                    if (!commandLineOptions.OutputFileName.Name.EndsWith(".mibc"))
                    {
                        PrintUsage(commandLineOptions, $"mibc output file name must end with .mibc");
                        return(-9);
                    }
                }
            }

            string etlFileName = commandLineOptions.TraceFile.FullName;

            foreach (string nettraceExtension in new string[] { ".netperf", ".netperf.zip", ".nettrace" })
            {
                if (commandLineOptions.TraceFile.FullName.EndsWith(nettraceExtension))
                {
                    etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - nettraceExtension.Length) + ".etlx";
                    PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}");
                    TraceLog.CreateFromEventPipeDataFile(commandLineOptions.TraceFile.FullName, etlFileName);
                }
            }

            string lttngExtension = ".trace.zip";

            if (commandLineOptions.TraceFile.FullName.EndsWith(lttngExtension))
            {
                etlFileName = commandLineOptions.TraceFile.FullName.Substring(0, commandLineOptions.TraceFile.FullName.Length - lttngExtension.Length) + ".etlx";
                PrintMessage($"Creating ETLX file {etlFileName} from {commandLineOptions.TraceFile.FullName}");
                TraceLog.CreateFromLttngTextDataFile(commandLineOptions.TraceFile.FullName, etlFileName);
            }

            UnZipIfNecessary(ref etlFileName, commandLineOptions.BasicProgressMessages ? Console.Out : new StringWriter());

            using (var traceLog = TraceLog.OpenOrConvert(etlFileName))
            {
                if ((!commandLineOptions.Pid.HasValue && commandLineOptions.ProcessName == null) && traceLog.Processes.Count != 1)
                {
                    PrintError("Trace file contains multiple processes to distinguish between");
                    PrintOutput("Either a pid or process name from the following list must be specified");
                    foreach (TraceProcess proc in traceLog.Processes)
                    {
                        PrintOutput($"Procname = {proc.Name} Pid = {proc.ProcessID}");
                    }
                    return(1);
                }

                if (commandLineOptions.Pid.HasValue && (commandLineOptions.ProcessName != null))
                {
                    PrintError("--pid and --process-name cannot be specified together");
                    return(-1);
                }

                // For a particular process
                TraceProcess p;
                if (commandLineOptions.Pid.HasValue)
                {
                    p = traceLog.Processes.LastProcessWithID(commandLineOptions.Pid.Value);
                }
                else if (commandLineOptions.ProcessName != null)
                {
                    List <TraceProcess> matchingProcesses = new List <TraceProcess>();
                    foreach (TraceProcess proc in traceLog.Processes)
                    {
                        if (String.Compare(proc.Name, commandLineOptions.ProcessName, StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            matchingProcesses.Add(proc);
                        }
                    }

                    if (matchingProcesses.Count == 0)
                    {
                        PrintError("Unable to find matching process in trace");
                        return(-1);
                    }
                    if (matchingProcesses.Count > 1)
                    {
                        StringBuilder errorMessage = new StringBuilder();

                        errorMessage.AppendLine("Found multiple matching processes in trace");
                        foreach (TraceProcess proc in matchingProcesses)
                        {
                            errorMessage.AppendLine($"{proc.Name}\tpid={proc.ProcessID}\tCPUMSec={proc.CPUMSec}");
                        }
                        PrintError(errorMessage.ToString());
                        return(-2);
                    }
                    p = matchingProcesses[0];
                }
                else
                {
                    p = traceLog.Processes.First();
                }

                if (!p.EventsInProcess.ByEventType <MethodDetailsTraceData>().Any())
                {
                    PrintError($"No MethodDetails\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-3);
                }

                if (!p.EventsInProcess.ByEventType <GCBulkTypeTraceData>().Any())
                {
                    PrintError($"No BulkType data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-4);
                }

                if (!p.EventsInProcess.ByEventType <ModuleLoadUnloadTraceData>().Any())
                {
                    PrintError($"No managed module load data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-5);
                }

                if (!p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>().Any())
                {
                    PrintError($"No managed jit starting data\nWas the trace collected with provider at least \"Microsoft-Windows-DotNETRuntime:0x4000080018:5\"?");
                    return(-5);
                }

                PgoTraceProcess pgoProcess    = new PgoTraceProcess(p);
                int?            clrInstanceId = commandLineOptions.ClrInstanceId;
                if (!clrInstanceId.HasValue)
                {
                    HashSet <int> clrInstanceIds         = new HashSet <int>();
                    HashSet <int> examinedClrInstanceIds = new HashSet <int>();
                    foreach (var assemblyLoadTrace in p.EventsInProcess.ByEventType <AssemblyLoadUnloadTraceData>())
                    {
                        if (examinedClrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID))
                        {
                            if (pgoProcess.ClrInstanceIsCoreCLRInstance(assemblyLoadTrace.ClrInstanceID))
                            {
                                clrInstanceIds.Add(assemblyLoadTrace.ClrInstanceID);
                            }
                        }
                    }

                    if (clrInstanceIds.Count != 1)
                    {
                        if (clrInstanceIds.Count == 0)
                        {
                            PrintError($"No managed CLR in target process, or per module information could not be loaded from the trace.");
                        }
                        else
                        {
                            // There are multiple clr processes... search for the one that implements
                            int[] clrInstanceIdsArray = clrInstanceIds.ToArray();
                            Array.Sort(clrInstanceIdsArray);
                            StringBuilder errorMessage = new StringBuilder();
                            errorMessage.AppendLine("Multiple CLR instances used in process. Choose one to examine with -clrInstanceID:<id> Valid ids:");
                            foreach (int instanceID in clrInstanceIds)
                            {
                                errorMessage.AppendLine(instanceID.ToString());
                            }
                            PrintError(errorMessage.ToString());
                        }
                        return(-10);
                    }
                    else
                    {
                        clrInstanceId = clrInstanceIds.First();
                    }
                }

                var tsc = new TraceTypeSystemContext(pgoProcess, clrInstanceId.Value, s_logger);

                if (commandLineOptions.VerboseWarnings)
                {
                    PrintWarning($"{traceLog.EventsLost} Lost events");
                }

                bool filePathError = false;
                if (commandLineOptions.Reference != null)
                {
                    foreach (FileInfo fileReference in commandLineOptions.Reference)
                    {
                        if (!File.Exists(fileReference.FullName))
                        {
                            PrintError($"Unable to find reference '{fileReference.FullName}'");
                            filePathError = true;
                        }
                        else
                        {
                            tsc.GetModuleFromPath(fileReference.FullName);
                        }
                    }
                }

                if (filePathError)
                {
                    return(-6);
                }

                if (!tsc.Initialize())
                {
                    return(-12);
                }

                TraceRuntimeDescToTypeSystemDesc idParser = new TraceRuntimeDescToTypeSystemDesc(p, tsc, clrInstanceId.Value);

                SortedDictionary <int, ProcessedMethodData> methodsToAttemptToPrepare = new SortedDictionary <int, ProcessedMethodData>();

                if (commandLineOptions.ProcessR2REvents)
                {
                    foreach (var e in p.EventsInProcess.ByEventType <R2RGetEntryPointTraceData>())
                    {
                        int    parenIndex = e.MethodSignature.IndexOf('(');
                        string retArg     = e.MethodSignature.Substring(0, parenIndex);
                        string paramsArgs = e.MethodSignature.Substring(parenIndex);
                        string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs;
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            if (!commandLineOptions.Warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Skipped R2REntryPoint {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}");
                            continue;
                        }
                        MethodDesc method           = null;
                        string     extraWarningText = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings);
                        }
                        catch (Exception exception)
                        {
                            extraWarningText = exception.ToString();
                        }

                        if (method == null)
                        {
                            if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Unable to parse {methodNameFromEventDirectly} when looking up R2R methods");
                            if (extraWarningText != null)
                            {
                                PrintWarning(extraWarningText);
                            }
                            continue;
                        }

                        if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter))
                        {
                            methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "R2RLoad"));
                        }
                    }
                }

                // Find all the jitStart events.
                if (commandLineOptions.ProcessJitEvents)
                {
                    foreach (var e in p.EventsInProcess.ByEventType <MethodJittingStartedTraceData>())
                    {
                        int    parenIndex = e.MethodSignature.IndexOf('(');
                        string retArg     = e.MethodSignature.Substring(0, parenIndex);
                        string paramsArgs = e.MethodSignature.Substring(parenIndex);
                        string methodNameFromEventDirectly = retArg + e.MethodNamespace + "." + e.MethodName + paramsArgs;
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            if (!commandLineOptions.Warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Skipped {methodNameFromEventDirectly} due to ClrInstanceID of {e.ClrInstanceID}");
                            continue;
                        }

                        MethodDesc method           = null;
                        string     extraWarningText = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings);
                        }
                        catch (Exception exception)
                        {
                            extraWarningText = exception.ToString();
                        }

                        if (method == null)
                        {
                            if ((e.MethodNamespace == "dynamicClass") || !commandLineOptions.Warnings)
                            {
                                continue;
                            }

                            PrintWarning($"Unable to parse {methodNameFromEventDirectly}");
                            if (extraWarningText != null)
                            {
                                PrintWarning(extraWarningText);
                            }
                            continue;
                        }

                        if ((e.TimeStampRelativeMSec >= commandLineOptions.ExcludeEventsBefore) && (e.TimeStampRelativeMSec <= commandLineOptions.ExcludeEventsAfter))
                        {
                            methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, method, "JitStart"));
                        }
                    }
                }

                Dictionary <MethodDesc, Dictionary <MethodDesc, int> > callGraph = null;
                Dictionary <MethodDesc, int> exclusiveSamples = null;
                if (commandLineOptions.GenerateCallGraph)
                {
                    HashSet <MethodDesc> methodsListedToPrepare = new HashSet <MethodDesc>();
                    foreach (var entry in methodsToAttemptToPrepare)
                    {
                        methodsListedToPrepare.Add(entry.Value.Method);
                    }

                    callGraph        = new Dictionary <MethodDesc, Dictionary <MethodDesc, int> >();
                    exclusiveSamples = new Dictionary <MethodDesc, int>();
                    // Capture the addresses of jitted code
                    List <ValueTuple <InstructionPointerRange, MethodDesc> > codeLocations = new List <(InstructionPointerRange, MethodDesc)>();
                    foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadTraceData>())
                    {
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            continue;
                        }

                        MethodDesc method = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings);
                        }
                        catch (Exception)
                        {
                        }

                        if (method != null)
                        {
                            codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), method));
                        }
                    }
                    foreach (var e in p.EventsInProcess.ByEventType <MethodLoadUnloadVerboseTraceData>())
                    {
                        if (e.ClrInstanceID != clrInstanceId.Value)
                        {
                            continue;
                        }

                        MethodDesc method = null;
                        try
                        {
                            method = idParser.ResolveMethodID(e.MethodID, commandLineOptions.VerboseWarnings);
                        }
                        catch (Exception)
                        {
                        }

                        if (method != null)
                        {
                            codeLocations.Add((new InstructionPointerRange(e.MethodStartAddress, e.MethodSize), method));
                        }
                    }

                    var sigProvider = new R2RSignatureTypeProvider(tsc);
                    foreach (var module in p.LoadedModules)
                    {
                        if (module.FilePath == "")
                        {
                            continue;
                        }

                        if (!File.Exists(module.FilePath))
                        {
                            continue;
                        }

                        try
                        {
                            byte[] image = File.ReadAllBytes(module.FilePath);
                            using (FileStream fstream = new FileStream(module.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                            {
                                var r2rCheckPEReader = new System.Reflection.PortableExecutable.PEReader(fstream, System.Reflection.PortableExecutable.PEStreamOptions.LeaveOpen);

                                if (!ILCompiler.Reflection.ReadyToRun.ReadyToRunReader.IsReadyToRunImage(r2rCheckPEReader))
                                {
                                    continue;
                                }
                            }

                            var reader = new ILCompiler.Reflection.ReadyToRun.ReadyToRunReader(tsc, module.FilePath);
                            foreach (var methodEntry in reader.GetCustomMethodToRuntimeFunctionMapping <TypeDesc, MethodDesc, R2RSigProviderContext>(sigProvider))
                            {
                                foreach (var runtimeFunction in methodEntry.Value.RuntimeFunctions)
                                {
                                    codeLocations.Add((new InstructionPointerRange(module.ImageBase + (ulong)runtimeFunction.StartAddress, runtimeFunction.Size), methodEntry.Key));
                                }
                            }
                        }
                        catch { }
                    }

                    InstructionPointerRange[] instructionPointerRanges = new InstructionPointerRange[codeLocations.Count];
                    MethodDesc[] methods = new MethodDesc[codeLocations.Count];
                    for (int i = 0; i < codeLocations.Count; i++)
                    {
                        instructionPointerRanges[i] = codeLocations[i].Item1;
                        methods[i] = codeLocations[i].Item2;
                    }

                    Array.Sort(instructionPointerRanges, methods);

                    foreach (var e in p.EventsInProcess.ByEventType <SampledProfileTraceData>())
                    {
                        var callstack = e.CallStack();
                        if (callstack == null)
                        {
                            continue;
                        }

                        ulong      address1         = callstack.CodeAddress.Address;
                        MethodDesc topOfStackMethod = LookupMethodByAddress(address1);
                        MethodDesc nextMethod       = null;
                        if (callstack.Caller != null)
                        {
                            ulong address2 = callstack.Caller.CodeAddress.Address;
                            nextMethod = LookupMethodByAddress(address2);
                        }

                        if (topOfStackMethod != null)
                        {
                            if (!methodsListedToPrepare.Contains(topOfStackMethod))
                            {
                                methodsListedToPrepare.Add(topOfStackMethod);
                                methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, topOfStackMethod, "SampleMethod"));
                            }

                            if (exclusiveSamples.TryGetValue(topOfStackMethod, out int count))
                            {
                                exclusiveSamples[topOfStackMethod] = count + 1;
                            }
                            else
                            {
                                exclusiveSamples[topOfStackMethod] = 1;
                            }
                        }

                        if (topOfStackMethod != null && nextMethod != null)
                        {
                            if (!methodsListedToPrepare.Contains(nextMethod))
                            {
                                methodsListedToPrepare.Add(nextMethod);
                                methodsToAttemptToPrepare.Add((int)e.EventIndex, new ProcessedMethodData(e.TimeStampRelativeMSec, nextMethod, "SampleMethodCaller"));
                            }

                            if (!callGraph.TryGetValue(nextMethod, out var innerDictionary))
                            {
                                innerDictionary       = new Dictionary <MethodDesc, int>();
                                callGraph[nextMethod] = innerDictionary;
                            }
                            if (innerDictionary.TryGetValue(topOfStackMethod, out int count))
                            {
                                innerDictionary[topOfStackMethod] = count + 1;
                            }
                            else
                            {
                                innerDictionary[topOfStackMethod] = 1;
                            }
                        }
                    }

                    MethodDesc LookupMethodByAddress(ulong address)
                    {
                        int index = Array.BinarySearch(instructionPointerRanges, new InstructionPointerRange(address, 1));

                        if (index >= 0)
                        {
                            return(methods[index]);
                        }
                        else
                        {
                            index = ~index;
                            if (index >= instructionPointerRanges.Length)
                            {
                                return(null);
                            }

                            if (instructionPointerRanges[index].StartAddress < address)
                            {
                                if (instructionPointerRanges[index].EndAddress > address)
                                {
                                    return(methods[index]);
                                }
                            }

                            if (index == 0)
                            {
                                return(null);
                            }

                            index--;

                            if (instructionPointerRanges[index].StartAddress < address)
                            {
                                if (instructionPointerRanges[index].EndAddress > address)
                                {
                                    return(methods[index]);
                                }
                            }

                            return(null);
                        }
                    }
                }

                Dictionary <MethodDesc, MethodChunks> instrumentationDataByMethod = new Dictionary <MethodDesc, MethodChunks>();

                foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataVerboseTraceData>())
                {
                    AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data);
                }
                foreach (var e in p.EventsInProcess.ByEventType <JitInstrumentationDataTraceData>())
                {
                    AddToInstrumentationData(e.ClrInstanceID, e.MethodID, e.MethodFlags, e.Data);
                }

                // Local function used with the above two loops as the behavior is supposed to be identical
                void AddToInstrumentationData(int eventClrInstanceId, long methodID, int methodFlags, byte[] data)
                {
                    if (eventClrInstanceId != clrInstanceId.Value)
                    {
                        return;
                    }

                    MethodDesc method = null;

                    try
                    {
                        method = idParser.ResolveMethodID(methodID, commandLineOptions.VerboseWarnings);
                    }
                    catch (Exception)
                    {
                    }

                    if (method != null)
                    {
                        if (!instrumentationDataByMethod.TryGetValue(method, out MethodChunks perMethodChunks))
                        {
                            perMethodChunks = new MethodChunks();
                            instrumentationDataByMethod.Add(method, perMethodChunks);
                        }
                        const int FinalChunkFlag = unchecked ((int)0x80000000);
                        int       chunkIndex     = methodFlags & ~FinalChunkFlag;
                        if ((chunkIndex != (perMethodChunks.LastChunk + 1)) || perMethodChunks.Done)
                        {
                            instrumentationDataByMethod.Remove(method);
                            return;
                        }
                        perMethodChunks.LastChunk = perMethodChunks.InstrumentationData.Count;
                        perMethodChunks.InstrumentationData.Add(data);
                        if ((methodFlags & FinalChunkFlag) == FinalChunkFlag)
                        {
                            perMethodChunks.Done = true;
                        }
                    }
                }

                if (commandLineOptions.DisplayProcessedEvents)
                {
                    foreach (var entry in methodsToAttemptToPrepare)
                    {
                        MethodDesc method = entry.Value.Method;
                        string     reason = entry.Value.Reason;
                        PrintOutput($"{entry.Value.Millisecond.ToString("F4")} {reason} {method}");
                    }
                }

                PrintMessage($"Done processing input file");

                if (commandLineOptions.OutputFileName == null)
                {
                    return(0);
                }

                // Deduplicate entries
                HashSet <MethodDesc>       methodsInListAlready = new HashSet <MethodDesc>();
                List <ProcessedMethodData> methodsUsedInProcess = new List <ProcessedMethodData>();

                PgoDataLoader pgoDataLoader = new PgoDataLoader(idParser);

                foreach (var entry in methodsToAttemptToPrepare)
                {
                    if (methodsInListAlready.Add(entry.Value.Method))
                    {
                        var methodData = entry.Value;
                        if (commandLineOptions.GenerateCallGraph)
                        {
                            exclusiveSamples.TryGetValue(methodData.Method, out methodData.ExclusiveWeight);
                            callGraph.TryGetValue(methodData.Method, out methodData.WeightedCallData);
                        }
                        if (instrumentationDataByMethod.TryGetValue(methodData.Method, out MethodChunks chunks))
                        {
                            int size = 0;
                            foreach (byte[] arr in chunks.InstrumentationData)
                            {
                                size += arr.Length;
                            }

                            byte[] instrumentationData = new byte[size];
                            int    offset = 0;

                            foreach (byte[] arr in chunks.InstrumentationData)
                            {
                                arr.CopyTo(instrumentationData, offset);
                                offset += arr.Length;
                            }

                            var intDecompressor = new PgoProcessor.PgoEncodedCompressedIntParser(instrumentationData, 0);
                            methodData.InstrumentationData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(pgoDataLoader, intDecompressor, true).ToArray();
                        }
                        methodsUsedInProcess.Add(methodData);
                    }
                }

                if (commandLineOptions.FileType.Value == PgoFileType.jittrace)
                {
                    GenerateJittraceFile(commandLineOptions.OutputFileName, methodsUsedInProcess, commandLineOptions.JitTraceOptions);
                }
                else if (commandLineOptions.FileType.Value == PgoFileType.mibc)
                {
                    ILCompiler.MethodProfileData[] methodProfileData = new ILCompiler.MethodProfileData[methodsUsedInProcess.Count];
                    for (int i = 0; i < methodProfileData.Length; i++)
                    {
                        ProcessedMethodData processedData = methodsUsedInProcess[i];
                        methodProfileData[i] = new ILCompiler.MethodProfileData(processedData.Method, ILCompiler.MethodProfilingDataFlags.ReadMethodCode, processedData.ExclusiveWeight, processedData.WeightedCallData, 0xFFFFFFFF, processedData.InstrumentationData);
                    }
                    return(MibcEmitter.GenerateMibcFile(tsc, commandLineOptions.OutputFileName, methodProfileData, commandLineOptions.ValidateOutputFile, commandLineOptions.Uncompressed));
                }
            }
            return(0);
        }