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); } }
public void WalkTheStackAndExpandSamplesHandlesBrokenStacks(StackSourceFrameIndex kind) { // Main() calls WRONG const double relativeTime = 0.1; var main = new FakeStackSourceSample( relativeTime: relativeTime, name: "Main", frameIndex: (StackSourceFrameIndex)5, // 5 is first non-taken enum value stackIndex: (StackSourceCallStackIndex)1, // 1 is first non-taken enum value callerIndex: StackSourceCallStackIndex.Invalid); var wrong = new FakeStackSourceSample( relativeTime: relativeTime, name: "WRONG", frameIndex: kind, stackIndex: (StackSourceCallStackIndex)2, callerIndex: main.StackIndex); var allSamples = new[] { main, wrong }; var leafs = new[] { new SpeedScopeStackSourceWriter.Sample(wrong.StackIndex, -1, wrong.RelativeTime, wrong.Metric, -1) }; var stackSource = new StackSourceStub(allSamples); var frameNameToId = new Dictionary <string, int>(); var frameIdToSamples = SpeedScopeStackSourceWriter.WalkTheStackAndExpandSamples(stackSource, leafs, frameNameToId); Assert.Equal(0, frameNameToId[main.Name]); Assert.False(frameNameToId.ContainsKey(wrong.Name)); var theOnlySample = frameIdToSamples.Single().Value.Single(); Assert.Equal(relativeTime, theOnlySample.RelativeTime); Assert.Equal(0, theOnlySample.Depth); }
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); } } }
public void CloseMetricCanBeZeroIfItDoesNotCreateAProfileEventThatStartsAndEndsAtTheSameMoment() { const double metric = 0.1; var samples = new[] { new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: metric, relativeTime: 0.1, depth: 0, callerFrameId: 0), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: metric, relativeTime: 0.2, depth: 0, callerFrameId: 0), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: 0.0, relativeTime: 0.3, depth: 0, callerFrameId: 0), // 0.0 metric }; var input = new Dictionary <int, List <SpeedScopeStackSourceWriter.Sample> >() { { 0, samples.ToList() } }; var aggregatedEvents = SpeedScopeStackSourceWriter.GetAggregatedOrderedProfileEvents(input); // we should have: // Open at 0.1 depth 0 and Close 0.3 Assert.Equal(2, aggregatedEvents.Count); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[0].Type); Assert.Equal(0.1, aggregatedEvents[0].RelativeTime); Assert.Equal(0, aggregatedEvents[0].Depth); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[1].Type); Assert.Equal(0.3, aggregatedEvents[1].RelativeTime); Assert.Equal(0, aggregatedEvents[0].Depth); }
// 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); } }
public void OrderForExportOrdersTheProfileEventsAsExpectedByTheSpeedScope() { var profileEvents = new List <SpeedScopeStackSourceWriter.ProfileEvent>() { new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Open, frameId: 0, depth: 0, relativeTime: 0.1), new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Open, frameId: 1, depth: 1, relativeTime: 0.1), new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Close, frameId: 1, depth: 1, relativeTime: 0.3), new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Close, frameId: 0, depth: 0, relativeTime: 0.3), new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Open, frameId: 2, depth: 0, relativeTime: 0.3), new SpeedScopeStackSourceWriter.ProfileEvent(SpeedScopeStackSourceWriter.ProfileEventType.Close, frameId: 2, depth: 0, relativeTime: 0.4), }; profileEvents.Reverse(); // reverse to make sure that it does sort the elements in right way var ordered = SpeedScopeStackSourceWriter.OrderForExport(profileEvents).ToArray(); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, ordered[0].Type); Assert.Equal(0.1, ordered[0].RelativeTime); Assert.Equal(0, ordered[0].Depth); Assert.Equal(0, ordered[0].FrameId); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, ordered[1].Type); Assert.Equal(0.1, ordered[1].RelativeTime); Assert.Equal(1, ordered[1].Depth); Assert.Equal(1, ordered[1].FrameId); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, ordered[2].Type); Assert.Equal(0.3, ordered[2].RelativeTime); Assert.Equal(1, ordered[2].Depth); Assert.Equal(1, ordered[2].FrameId); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, ordered[3].Type); Assert.Equal(0.3, ordered[3].RelativeTime); Assert.Equal(0, ordered[3].Depth); Assert.Equal(0, ordered[3].FrameId); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, ordered[4].Type); Assert.Equal(0.3, ordered[4].RelativeTime); Assert.Equal(0, ordered[4].Depth); Assert.Equal(2, ordered[4].FrameId); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, ordered[5].Type); Assert.Equal(0.4, ordered[5].RelativeTime); Assert.Equal(0, ordered[5].Depth); Assert.Equal(2, ordered[5].FrameId); }
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); } }
public void TwoSamplesCanNotHappenAtTheSameTime() { const double zeroMetric = 0.0; const double relativeTime = 0.1; var samples = new[] { new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: zeroMetric, relativeTime: relativeTime, depth: 0, callerFrameId: 0), // 0.0 metric new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: zeroMetric, relativeTime: relativeTime, depth: 0, callerFrameId: 0), // 0.0 metric and same relative time }; var input = new Dictionary <int, List <SpeedScopeStackSourceWriter.Sample> >() { { 0, samples.ToList() } }; Assert.Throws <ArgumentException>(() => SpeedScopeStackSourceWriter.GetAggregatedOrderedProfileEvents(input)); }
public void GetAggregatedOrderedProfileEventsConvertsContinuousSamplesWithPausesToMultipleEvents() { const double metric = 0.1; var samples = new[] { new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 0.1), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 0.2), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 0.7), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 1.1), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 1.2), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, callerFrameId: 0, metric: metric, depth: 0, relativeTime: 1.3), }; var input = new Dictionary <int, List <SpeedScopeStackSourceWriter.Sample> >() { { 0, samples.ToList() } }; var aggregatedEvents = SpeedScopeStackSourceWriter.GetAggregatedOrderedProfileEvents(input); // we should have <0.1, 0.3> and <0.7, 0.8> (the tool would ignore <0.7, 0.7>) and <1.1, 1.4> Assert.Equal(6, aggregatedEvents.Count); Assert.Equal(0.1, aggregatedEvents[0].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[0].Type); Assert.Equal(0.2 + metric, aggregatedEvents[1].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[1].Type); Assert.Equal(0.7, aggregatedEvents[2].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[2].Type); Assert.Equal(0.7 + metric, aggregatedEvents[3].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[3].Type); Assert.Equal(1.1, aggregatedEvents[4].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[4].Type); Assert.Equal(1.3 + metric, aggregatedEvents[5].RelativeTime); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[5].Type); }
public void WalkTheStackAndExpandSamplesProducesFullInformation() { // Main() calls A() calls B() const double relativeTime = 0.1; var main = new FakeStackSourceSample( relativeTime: relativeTime, name: "Main", frameIndex: (StackSourceFrameIndex)5, // 5 is first non-taken enum value stackIndex: (StackSourceCallStackIndex)1, // 1 is first non-taken enum value callerIndex: StackSourceCallStackIndex.Invalid); var a = new FakeStackSourceSample( relativeTime: relativeTime, name: "A", frameIndex: (StackSourceFrameIndex)6, stackIndex: (StackSourceCallStackIndex)2, callerIndex: main.StackIndex); var b = new FakeStackSourceSample( relativeTime: relativeTime, name: "B", frameIndex: (StackSourceFrameIndex)7, stackIndex: (StackSourceCallStackIndex)3, callerIndex: a.StackIndex); var allSamples = new[] { main, a, b }; var leafs = new[] { new SpeedScopeStackSourceWriter.Sample(b.StackIndex, -1, b.RelativeTime, b.Metric, -1) }; var stackSource = new StackSourceStub(allSamples); var frameNameToId = new Dictionary <string, int>(); var frameIdToSamples = SpeedScopeStackSourceWriter.WalkTheStackAndExpandSamples(stackSource, leafs, frameNameToId); Assert.Equal(0, frameNameToId[main.Name]); Assert.Equal(1, frameNameToId[a.Name]); Assert.Equal(2, frameNameToId[b.Name]); Assert.All(frameIdToSamples.Select(pair => pair.Value), samples => Assert.Equal(relativeTime, samples.Single().RelativeTime)); Assert.Equal(0, frameIdToSamples[0].Single().Depth); Assert.Equal(1, frameIdToSamples[1].Single().Depth); Assert.Equal(2, frameIdToSamples[2].Single().Depth); }
public void GetSortedSamplesReturnsSamplesSortedByRelativeTimeAndGrouppedByThread() { const string ThreadName = "Thread (123)"; var thread_1 = new FakeStackSourceSample( relativeTime: 0.1, name: ThreadName, frameIndex: (StackSourceFrameIndex)5, // 5 is first non-taken enum value stackIndex: (StackSourceCallStackIndex)1, // 1 is first non-taken enum value callerIndex: StackSourceCallStackIndex.Invalid); var a_1 = new FakeStackSourceSample( relativeTime: 0.1, name: "A", frameIndex: (StackSourceFrameIndex)6, stackIndex: (StackSourceCallStackIndex)2, callerIndex: thread_1.StackIndex); var thread_2 = new FakeStackSourceSample( relativeTime: 0.2, name: ThreadName, frameIndex: (StackSourceFrameIndex)5, // 5 is first non-taken enum value stackIndex: (StackSourceCallStackIndex)3, // 1 is first non-taken enum value callerIndex: StackSourceCallStackIndex.Invalid); var a_2 = new FakeStackSourceSample( relativeTime: 0.2, name: "A", frameIndex: (StackSourceFrameIndex)6, stackIndex: (StackSourceCallStackIndex)4, callerIndex: thread_2.StackIndex); var sourceSamples = new[] { thread_1, thread_2, a_2, a_1 }; var stackSource = new StackSourceStub(sourceSamples); var result = SpeedScopeStackSourceWriter.GetSortedSamplesPerThread(stackSource)[ThreadName]; Assert.Equal(0.1, result[0].RelativeTime); Assert.Equal(0.1, result[1].RelativeTime); Assert.Equal(0.2, result[2].RelativeTime); Assert.Equal(0.2, result[2].RelativeTime); }
public void GetAggregatedOrderedProfileEventsConvertsContinuousSamplesWithDifferentCallerIdToMultipleEvents() { const double metric = 0.1; var samples = new[] { new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: metric, relativeTime: 0.1, depth: 0, callerFrameId: 0), new SpeedScopeStackSourceWriter.Sample((StackSourceCallStackIndex)1, metric: metric, relativeTime: 0.2, depth: 0, callerFrameId: 1), // callerFrameId change! }; var input = new Dictionary <int, List <SpeedScopeStackSourceWriter.Sample> >() { { 0, samples.ToList() } }; var aggregatedEvents = SpeedScopeStackSourceWriter.GetAggregatedOrderedProfileEvents(input); // we should have: // Open at 0.1 depth 0 and Close 0.2 // Open at 0.2 depth 0 and Close 0.3 Assert.Equal(4, aggregatedEvents.Count); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[0].Type); Assert.Equal(0.1, aggregatedEvents[0].RelativeTime); Assert.Equal(0, aggregatedEvents[0].Depth); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[1].Type); Assert.Equal(0.1 + metric, aggregatedEvents[1].RelativeTime); Assert.Equal(0, aggregatedEvents[0].Depth); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Open, aggregatedEvents[2].Type); Assert.Equal(0.2, aggregatedEvents[2].RelativeTime); Assert.Equal(0, aggregatedEvents[2].Depth); Assert.Equal(SpeedScopeStackSourceWriter.ProfileEventType.Close, aggregatedEvents[3].Type); Assert.Equal(0.2 + metric, aggregatedEvents[3].RelativeTime); Assert.Equal(0, aggregatedEvents[3].Depth); }