Skip to content

Commit

Permalink
Merge pull request #1113 from adamsitnik/chromiumTraceFileFormat
Browse files Browse the repository at this point in the history
Chromium trace file format exporter
  • Loading branch information
brianrob authored Mar 9, 2020
2 parents 781a6b5 + d2def4b commit 20f48f6
Show file tree
Hide file tree
Showing 5 changed files with 532 additions and 329 deletions.
6 changes: 5 additions & 1 deletion src/PerfView/StackViewer/StackWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ internal void DoSave(object sender, RoutedEventArgs e)
saveDialog.InitialDirectory = Path.GetDirectoryName(DataSource.FilePath);
saveDialog.Title = "File to save view";
saveDialog.DefaultExt = ".perfView.xml.zip";
saveDialog.Filter = "PerfView view file|*.perfView.xml.zip|Comma Separated Value|*.csv|Speed Scope Format|*.speedscope.json|All Files|*.*";
saveDialog.Filter = "PerfView view file|*.perfView.xml.zip|Comma Separated Value|*.csv|Speed Scope|*.speedscope.json|Chromium Trace Event|*.chromium.json|All Files|*.*";
saveDialog.AddExtension = true;
saveDialog.OverwritePrompt = true;

Expand Down Expand Up @@ -948,6 +948,10 @@ internal void DoSave(object sender, RoutedEventArgs e)
{
SpeedScopeStackSourceWriter.WriteStackViewAsJson(CallTree.StackSource, m_fileName);
}
else if (m_fileName.EndsWith(".chromium.json", StringComparison.OrdinalIgnoreCase))
{
ChromiumStackSourceWriter.WriteStackViewAsJson(CallTree.StackSource, m_fileName, false);
}
else
{
if (m_fileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
Expand Down
106 changes: 106 additions & 0 deletions src/TraceEvent/Stacks/ChromiumStackSourceWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using static Microsoft.Diagnostics.Tracing.Stacks.StackSourceWriterHelper;

namespace Microsoft.Diagnostics.Tracing.Stacks.Formats
{
public class ChromiumStackSourceWriter
{
/// <summary>
/// exports provided StackSource to a Chromium Trace File format
/// schema: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/
/// </summary>
public static void WriteStackViewAsJson(StackSource source, string filePath, bool compress)
{
if (compress && !filePath.EndsWith(".gz", StringComparison.OrdinalIgnoreCase))
filePath += ".gz";

if (File.Exists(filePath))
File.Delete(filePath);

using (var writeStream = compress ? (Stream)new GZipStream(File.Create(filePath), CompressionMode.Compress, leaveOpen: false) : File.Create(filePath))
using (var streamWriter = new StreamWriter(writeStream))
{
Export(source, streamWriter, Path.GetFileNameWithoutExtension(filePath));
}
}

#region private
private static void Export(StackSource source, TextWriter writer, string name)
{
var samplesPerThread = GetSortedSamplesPerThread(source);

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

foreach (var pair in samplesPerThread)
{
var frameIdToSamples = WalkTheStackAndExpandSamples(source, pair.Value, exportedFrameNameToExportedFrameId, exportedFrameIdToFrameTuple);

var sortedProfileEvents = GetAggregatedOrderedProfileEvents(frameIdToSamples);

profileEventsPerThread.Add(pair.Key, sortedProfileEvents);
};

WriteToFile(exportedFrameIdToFrameTuple, profileEventsPerThread, writer, name);
}

private static void WriteToFile(Dictionary<int, FrameInfo> frameIdToFrameTuple,
IReadOnlyDictionary<ThreadInfo, IReadOnlyList<ProfileEvent>> sortedProfileEventsPerThread,
TextWriter writer, string name)
{
writer.Write("{");
writer.Write("\"traceEvents\": [");
bool isFirst = true;
foreach (var perThread in sortedProfileEventsPerThread.OrderBy(pair => pair.Value.First().RelativeTime))
{
foreach (var profileEvent in perThread.Value)
{
if (!isFirst)
writer.Write(", ");
else
isFirst = false;

writer.Write("{");
writer.Write($"\"name\": \"{frameIdToFrameTuple[profileEvent.FrameId].Name}\", ");
writer.Write($"\"cat\": \"sampleEvent\", ");
writer.Write($"\"ph\": \"{(profileEvent.Type == ProfileEventType.Open ? "B" : "E")}\", ");
writer.Write($"\"ts\": {profileEvent.RelativeTime.ToString("R", CultureInfo.InvariantCulture)}, ");
writer.Write($"\"pid\": {perThread.Key.ProcessId}, ");
writer.Write($"\"tid\": {perThread.Key.Id}, ");
writer.Write($"\"sf\": {profileEvent.FrameId}");
writer.Write("}");
}
}
writer.Write("], ");
writer.Write("\"displayTimeUnit\": \"ms\", ");
writer.Write("\"stackFrames\": {");
isFirst = true;
foreach (var frame in frameIdToFrameTuple)
{
if (!isFirst)
writer.Write(", ");
else
isFirst = false;

var frameId = frame.Key;
var frameInfo = frame.Value;
writer.Write($"\"{frameId}\": {{");
writer.Write($"\"name\": \"{frameInfo.Name}\", ");
writer.Write($"\"category\": \"{frameInfo.Category}\"");
if (frameInfo.ParentId != -1)
writer.Write($", \"parent\": {frameInfo.ParentId}");
writer.Write("}");
}
writer.Write("}, ");
writer.Write($"\"otherData\": {{ \"name\": \"{name}\" }}");
writer.Write("}");
}
#endregion private
}
}
Loading

0 comments on commit 20f48f6

Please sign in to comment.