Merge pull request #1 from unity/new-data-format
Add support for 2.x package data format
This commit is contained in:
Коммит
39462bb625
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityPerformanceBenchmarkReporter.Entities.New
|
||||
{
|
||||
[Serializable]
|
||||
public class TestResult
|
||||
{
|
||||
public string Name;
|
||||
public string Version;
|
||||
public List<string> Categories = new List<string>();
|
||||
public List<SampleGroup> SampleGroups = new List<SampleGroup>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SampleGroup
|
||||
{
|
||||
public string Name;
|
||||
public SampleUnit Unit;
|
||||
public bool IncreaseIsBetter;
|
||||
public List<double> Samples = new List<double>();
|
||||
public double Min;
|
||||
public double Max;
|
||||
public double Median;
|
||||
public double Average;
|
||||
public double StandardDeviation;
|
||||
public double Sum;
|
||||
|
||||
public SampleGroup(string name, SampleUnit unit, bool increaseIsBetter)
|
||||
{
|
||||
Name = name;
|
||||
Unit = unit;
|
||||
IncreaseIsBetter = increaseIsBetter;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Run
|
||||
{
|
||||
public string TestSuite;
|
||||
public int Date;
|
||||
public Player Player;
|
||||
public Hardware Hardware;
|
||||
public Editor Editor;
|
||||
public List<string> Dependencies = new List<string>();
|
||||
public List<TestResult> Results = new List<TestResult>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Editor
|
||||
{
|
||||
public string Version;
|
||||
public string Branch;
|
||||
public string Changeset;
|
||||
public int Date;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Hardware
|
||||
{
|
||||
public string OperatingSystem;
|
||||
public string DeviceModel;
|
||||
public string DeviceName;
|
||||
public string ProcessorType;
|
||||
public int ProcessorCount;
|
||||
public string GraphicsDeviceName;
|
||||
public int SystemMemorySizeMB;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Player
|
||||
{
|
||||
public string Platform;
|
||||
public bool Development;
|
||||
public int ScreenWidth;
|
||||
public int ScreenHeight;
|
||||
public int ScreenRefreshRate;
|
||||
public bool Fullscreen;
|
||||
public int Vsync;
|
||||
public int AntiAliasing;
|
||||
public string ColorSpace;
|
||||
public string AnisotropicFiltering;
|
||||
public string BlendWeights;
|
||||
public string GraphicsApi;
|
||||
public bool Batchmode;
|
||||
public string RenderThreadingMode;
|
||||
public bool GpuSkinning;
|
||||
|
||||
// strings because values are editor only enums
|
||||
public string ScriptingBackend;
|
||||
public string AndroidTargetSdkVersion;
|
||||
public string AndroidBuildSystem;
|
||||
public string BuildTarget;
|
||||
public string StereoRenderingPath;
|
||||
}
|
||||
|
||||
public enum SampleUnit
|
||||
{
|
||||
Nanosecond,
|
||||
Microsecond,
|
||||
Millisecond,
|
||||
Second,
|
||||
Byte,
|
||||
Kilobyte,
|
||||
Megabyte,
|
||||
Gigabyte,
|
||||
Undefined
|
||||
}
|
||||
}
|
|
@ -82,7 +82,7 @@ namespace UnityPerformanceBenchmarkReporter
|
|||
|
||||
foreach (var xmlFileNamePath in xmlFileNamePaths)
|
||||
{
|
||||
var performanceTestRun = testResultXmlParser.GetPerformanceTestRunFromXml(xmlFileNamePath);
|
||||
var performanceTestRun = testResultXmlParser.Parse(xmlFileNamePath);
|
||||
if (performanceTestRun != null && performanceTestRun.Results.Any())
|
||||
{
|
||||
perfTestRuns.Add(
|
||||
|
@ -96,7 +96,7 @@ namespace UnityPerformanceBenchmarkReporter
|
|||
for (var i = 0; i < resultFilesOrderedByResultName.Length; i++)
|
||||
{
|
||||
var performanceTestRun =
|
||||
testResultXmlParser.GetPerformanceTestRunFromXml(resultFilesOrderedByResultName[i].Key);
|
||||
testResultXmlParser.Parse(resultFilesOrderedByResultName[i].Key);
|
||||
|
||||
if (performanceTestRun != null && performanceTestRun.Results.Any())
|
||||
{
|
||||
|
|
|
@ -2,71 +2,71 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using UnityPerformanceBenchmarkReporter.Entities;
|
||||
using UnityPerformanceBenchmarkReporter.Entities.New;
|
||||
|
||||
namespace UnityPerformanceBenchmarkReporter
|
||||
{
|
||||
public class TestResultXmlParser
|
||||
{
|
||||
public PerformanceTestRun GetPerformanceTestRunFromXml(string resultXmlFileName)
|
||||
public PerformanceTestRun Parse(string path)
|
||||
{
|
||||
ValidateInput(resultXmlFileName);
|
||||
var xmlDocument = TryLoadResultXmlFile(resultXmlFileName);
|
||||
var performanceTestRun = TryParseXmlToPerformanceTestRun(xmlDocument);
|
||||
return performanceTestRun;
|
||||
var xmlDocument = XDocument.Load(path);
|
||||
return Parse(xmlDocument);
|
||||
}
|
||||
|
||||
private void ValidateInput(string resultXmlFileName)
|
||||
private static PerformanceTestRun Parse(XDocument xmlDocument)
|
||||
{
|
||||
if (string.IsNullOrEmpty(resultXmlFileName))
|
||||
var output = xmlDocument.Descendants("output");
|
||||
var xElements = output as XElement[] ?? output.ToArray();
|
||||
|
||||
if (!xElements.Any())
|
||||
{
|
||||
throw new ArgumentNullException(resultXmlFileName, nameof(resultXmlFileName));
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!File.Exists(resultXmlFileName))
|
||||
var run = DeserializeMetadata(xElements) ?? DeserializeMetadataV2(xElements);
|
||||
|
||||
if (run == null)
|
||||
{
|
||||
throw new FileNotFoundException("Result file not found; {0}", resultXmlFileName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private XDocument TryLoadResultXmlFile(string resultXmlFileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
return XDocument.Load(resultXmlFileName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errMsg = string.Format("Failed to load xml result file: {0}", resultXmlFileName);
|
||||
WriteExceptionConsoleErrorMessage(errMsg, e);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
run.EndTime = DateTime.Now.ToUniversalTime()
|
||||
.Subtract(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc))
|
||||
.TotalMilliseconds;
|
||||
|
||||
private PerformanceTestRun TryParseXmlToPerformanceTestRun(XDocument xmlDocument)
|
||||
{
|
||||
var output = xmlDocument.Descendants("output").ToArray();
|
||||
if (output == null || !output.Any())
|
||||
{
|
||||
throw new Exception("The xmlDocument passed to the TryParseXmlToPerformanceTestRun method does not have any \'ouput\' xml tags needed for correct parsing.");
|
||||
}
|
||||
|
||||
var run = new PerformanceTestRun();
|
||||
DeserializeTestResults(output, run);
|
||||
DeserializeMetadata(output, run);
|
||||
DeserializeTestResults(xElements, run);
|
||||
DeserializeTestResultsV2(xElements, run);
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
private void DeserializeTestResults(IEnumerable<XElement> output, PerformanceTestRun run)
|
||||
private static void DeserializeTestResults(IEnumerable<XElement> output, PerformanceTestRun run)
|
||||
{
|
||||
foreach (var element in output)
|
||||
{
|
||||
foreach (var line in element.Value.Split('\n'))
|
||||
{
|
||||
var json = GetJsonFromHashtag("performancetestresult", line);
|
||||
if (json == null) continue;
|
||||
|
||||
var result = JsonConvert.DeserializeObject<PerformanceTestResult>(json);
|
||||
run.Results.Add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeserializeTestResultsV2(IEnumerable<XElement> output, PerformanceTestRun run)
|
||||
{
|
||||
foreach (var element in output)
|
||||
{
|
||||
foreach (var line in element.Value.Split('\n'))
|
||||
{
|
||||
var json = GetJsonFromHashtag("performancetestresult2", line);
|
||||
if (json == null)
|
||||
{
|
||||
continue;
|
||||
|
@ -75,102 +75,161 @@ namespace UnityPerformanceBenchmarkReporter
|
|||
var result = TryDeserializePerformanceTestResultJsonObject(json);
|
||||
if (result != null)
|
||||
{
|
||||
run.Results.Add(result);
|
||||
var pt = new PerformanceTestResult()
|
||||
{
|
||||
TestCategories = result.Categories,
|
||||
TestName = result.Name,
|
||||
TestVersion = result.Version,
|
||||
SampleGroups = result.SampleGroups.Select(sg => new Entities.SampleGroup
|
||||
{
|
||||
Samples = sg.Samples,
|
||||
Average = sg.Average,
|
||||
Max = sg.Max,
|
||||
Median = sg.Median,
|
||||
Min = sg.Min,
|
||||
Sum = sg.Sum,
|
||||
StandardDeviation = sg.StandardDeviation,
|
||||
SampleCount = sg.Samples.Count,
|
||||
Definition = new SampleGroupDefinition()
|
||||
{
|
||||
Name = sg.Name,
|
||||
SampleUnit = (Entities.SampleUnit)sg.Unit,
|
||||
IncreaseIsBetter = sg.IncreaseIsBetter
|
||||
}
|
||||
}).ToList()
|
||||
};
|
||||
run.Results.Add(pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DeserializeMetadata(IEnumerable<XElement> output, PerformanceTestRun run)
|
||||
private static PerformanceTestRun DeserializeMetadata(IEnumerable<XElement> output)
|
||||
{
|
||||
return (output
|
||||
.SelectMany(element => element.Value.Split('\n'),
|
||||
(element, line) => GetJsonFromHashtag("performancetestruninfo", line))
|
||||
.Where(json => json != null)
|
||||
.Select(JsonConvert.DeserializeObject<PerformanceTestRun>)).FirstOrDefault();
|
||||
}
|
||||
|
||||
private static PerformanceTestRun DeserializeMetadataV2(IEnumerable<XElement> output)
|
||||
{
|
||||
foreach (var element in output)
|
||||
{
|
||||
var elements = element.Value.Split('\n');
|
||||
if(elements.Any(e => e.Length > 0 && e.Substring(0, 2).Equals("##")))
|
||||
{
|
||||
var line = elements.First(e => e.Length > 0 && e.Substring(0, 2).Equals("##"));
|
||||
var pattern = @"##performancetestruninfo2:(.+)\n";
|
||||
var regex = new Regex(pattern);
|
||||
var matches = regex.Match(element.Value);
|
||||
if (!matches.Success) continue;
|
||||
if (matches.Groups.Count == 0) continue;
|
||||
|
||||
var json = GetJsonFromHashtag("performancetestruninfo", line);
|
||||
|
||||
// This is the happy case where we have a performancetestruninfo json object
|
||||
if (json != null)
|
||||
if (matches.Groups[1].Captures.Count > 1)
|
||||
{
|
||||
throw new Exception("Performance test run had multiple hardware and player settings, there should only be one.");
|
||||
}
|
||||
|
||||
var json = matches.Groups[1].Value;
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
throw new Exception("Performance test run has incomplete hardware and player settings.");
|
||||
}
|
||||
|
||||
var result = TryDeserializePerformanceTestRunJsonObject(json);
|
||||
if (result != null)
|
||||
|
||||
var run = new PerformanceTestRun()
|
||||
{
|
||||
run.TestSuite = result.TestSuite;
|
||||
run.EditorVersion = result.EditorVersion;
|
||||
run.QualitySettings = result.QualitySettings;
|
||||
run.ScreenSettings = result.ScreenSettings;
|
||||
run.BuildSettings = result.BuildSettings;
|
||||
run.PlayerSettings = result.PlayerSettings;
|
||||
run.PlayerSystemInfo = result.PlayerSystemInfo;
|
||||
run.StartTime = result.StartTime;
|
||||
// @TODO fix end time, does it matter for now?
|
||||
run.EndTime = run.StartTime;
|
||||
}
|
||||
}
|
||||
// Unhappy case where we couldn't find a performancetestruninfo object
|
||||
// This could be because we have missing metadata for the test run
|
||||
// In this case, we try to look for a performancetestresult json object
|
||||
// We should have at least startime metadata that we can use to correctly
|
||||
// display the test results on the x-axis of the chart
|
||||
else
|
||||
BuildSettings = new BuildSettings()
|
||||
{
|
||||
json = GetJsonFromHashtag("performancetestresult", line);
|
||||
if (json != null)
|
||||
Platform = result.Player.Platform,
|
||||
BuildTarget = result.Player.BuildTarget,
|
||||
DevelopmentPlayer = true,
|
||||
AndroidBuildSystem = result.Player.AndroidBuildSystem
|
||||
},
|
||||
EditorVersion = new EditorVersion()
|
||||
{
|
||||
var result = TryDeserializePerformanceTestRunJsonObject(json);
|
||||
run.StartTime = result.StartTime;
|
||||
// @TODO fix end time, does it matter for now?
|
||||
run.EndTime = run.StartTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Branch = result.Editor.Branch,
|
||||
DateSeconds = result.Editor.Date,
|
||||
FullVersion = $"{result.Editor.Version} ({result.Editor.Changeset})",
|
||||
RevisionValue = 0
|
||||
},
|
||||
PlayerSettings = new PlayerSettings()
|
||||
{
|
||||
GpuSkinning = result.Player.GpuSkinning,
|
||||
GraphicsApi = result.Player.GraphicsApi,
|
||||
RenderThreadingMode = result.Player.RenderThreadingMode,
|
||||
ScriptingBackend = result.Player.ScriptingBackend,
|
||||
AndroidTargetSdkVersion = result.Player.AndroidTargetSdkVersion,
|
||||
EnabledXrTargets = new List<string>(),
|
||||
ScriptingRuntimeVersion = "",
|
||||
StereoRenderingPath = result.Player.StereoRenderingPath
|
||||
},
|
||||
QualitySettings = new QualitySettings()
|
||||
{
|
||||
Vsync = result.Player.Vsync,
|
||||
AntiAliasing = result.Player.AntiAliasing,
|
||||
AnisotropicFiltering = result.Player.AnisotropicFiltering,
|
||||
BlendWeights = result.Player.BlendWeights,
|
||||
ColorSpace = result.Player.ColorSpace
|
||||
},
|
||||
ScreenSettings = new ScreenSettings()
|
||||
{
|
||||
Fullscreen = result.Player.Fullscreen,
|
||||
ScreenHeight = result.Player.ScreenHeight,
|
||||
ScreenWidth = result.Player.ScreenWidth,
|
||||
ScreenRefreshRate = result.Player.ScreenRefreshRate
|
||||
},
|
||||
PlayerSystemInfo = new PlayerSystemInfo()
|
||||
{
|
||||
DeviceModel = result.Hardware.DeviceModel,
|
||||
DeviceName = result.Hardware.DeviceName,
|
||||
OperatingSystem = result.Hardware.OperatingSystem,
|
||||
ProcessorCount = result.Hardware.ProcessorCount,
|
||||
ProcessorType = result.Hardware.ProcessorType,
|
||||
GraphicsDeviceName = result.Hardware.GraphicsDeviceName,
|
||||
SystemMemorySize = result.Hardware.SystemMemorySizeMB,
|
||||
XrDevice = "",
|
||||
XrModel = ""
|
||||
},
|
||||
StartTime = result.Date,
|
||||
TestSuite = result.TestSuite,
|
||||
Results = new List<PerformanceTestResult>()
|
||||
};
|
||||
|
||||
return run;
|
||||
}
|
||||
|
||||
private PerformanceTestResult TryDeserializePerformanceTestResultJsonObject(string json)
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Run TryDeserializePerformanceTestRunJsonObject(string json)
|
||||
{
|
||||
PerformanceTestResult performanceTestResult;
|
||||
try
|
||||
{
|
||||
performanceTestResult = JsonConvert.DeserializeObject<PerformanceTestResult>(json);
|
||||
return JsonConvert.DeserializeObject<Run>(json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errMsg = string.Format("Exception thrown while deserializing json string to PerformanceTestResult: {0}", json);
|
||||
WriteExceptionConsoleErrorMessage(errMsg, e);
|
||||
throw;
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
return performanceTestResult;
|
||||
return null;
|
||||
}
|
||||
|
||||
private void WriteExceptionConsoleErrorMessage(string errMsg, Exception e)
|
||||
private static Entities.New.TestResult TryDeserializePerformanceTestResultJsonObject(string json)
|
||||
{
|
||||
Console.Error.WriteLine("{0}\r\nException: {1}\r\nInnerException: {2}", errMsg, e.Message,
|
||||
e.InnerException.Message);
|
||||
}
|
||||
|
||||
private PerformanceTestRun TryDeserializePerformanceTestRunJsonObject(string json)
|
||||
{
|
||||
PerformanceTestRun performanceTestRun;
|
||||
try
|
||||
{
|
||||
performanceTestRun = JsonConvert.DeserializeObject<PerformanceTestRun>(json);
|
||||
return JsonConvert.DeserializeObject<Entities.New.TestResult>(json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errMsg = string.Format("Exception thrown while deserializing json string to PerformanceTestRun: {0}", json);
|
||||
WriteExceptionConsoleErrorMessage(errMsg, e);
|
||||
throw;
|
||||
Console.WriteLine(e.Message);
|
||||
}
|
||||
|
||||
return performanceTestRun;
|
||||
return null;
|
||||
}
|
||||
|
||||
private string GetJsonFromHashtag(string tag, string line)
|
||||
private static string GetJsonFromHashtag(string tag, string line)
|
||||
{
|
||||
if (!line.Contains($"##{tag}:")) return null;
|
||||
var jsonStart = line.IndexOf('{');
|
||||
|
@ -179,18 +238,19 @@ namespace UnityPerformanceBenchmarkReporter
|
|||
while (openBrackets > 0 || stringIndex == jsonStart)
|
||||
{
|
||||
var character = line[stringIndex];
|
||||
switch (character)
|
||||
if (character == '{')
|
||||
{
|
||||
case '{':
|
||||
openBrackets++;
|
||||
break;
|
||||
case '}':
|
||||
}
|
||||
|
||||
if (character == '}')
|
||||
{
|
||||
openBrackets--;
|
||||
break;
|
||||
}
|
||||
|
||||
stringIndex++;
|
||||
}
|
||||
|
||||
var jsonEnd = stringIndex;
|
||||
return line.Substring(jsonStart, jsonEnd - jsonStart);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче