您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
370 行
11 KiB
370 行
11 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.SceneManagement;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
#endif
|
|
|
|
namespace BoatAttack.Benchmark
|
|
{
|
|
public class Benchmark : MonoBehaviour
|
|
{
|
|
// data
|
|
public bool autoStart = true;
|
|
private bool singleBench = false;
|
|
[HideInInspector] public string urpVersion = "N/A";
|
|
public static string UrpVersion;
|
|
[HideInInspector] public int simpleRunScene = -1;
|
|
public BenchmarkConfigData settings;
|
|
public bool simpleRun = false;
|
|
public FinishAction finish = FinishAction.Exit;
|
|
public static bool SimpleRun;
|
|
private int _benchIndex;
|
|
public static BenchmarkData Current { get; private set; }
|
|
|
|
private static PerfomanceStats _stats;
|
|
|
|
// Timing data
|
|
public static int CurrentRunIndex;
|
|
public static int CurrentRunFrame;
|
|
private int _totalRunFrames;
|
|
private bool _running = false;
|
|
|
|
// Bench results
|
|
private readonly List<PerfBasic> _perfData = new List<PerfBasic>();
|
|
|
|
private void Start()
|
|
{
|
|
if (settings == null) AppSettings.ExitGame("Benchmark Not Setup");
|
|
|
|
SceneManager.sceneLoaded += OnSceneLoaded;
|
|
|
|
if (autoStart)
|
|
{
|
|
Initialize();
|
|
}
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
UrpVersion = urpVersion;
|
|
if(settings.disableVSync)
|
|
QualitySettings.vSyncCount = 0;
|
|
if(settings.stats)
|
|
_stats = gameObject.AddComponent<PerfomanceStats>();
|
|
DontDestroyOnLoad(gameObject);
|
|
|
|
if (simpleRun && settings.benchmarkData?[simpleRunScene] != null)
|
|
{
|
|
if(settings.stats)
|
|
_stats.mode = PerfomanceStats.PerfMode.DisplayOnly;
|
|
SimpleRun = simpleRun;
|
|
Current = settings.benchmarkData?[simpleRunScene];
|
|
LoadBenchmark();
|
|
}
|
|
else
|
|
{
|
|
if(settings.stats)
|
|
_stats.mode = PerfomanceStats.PerfMode.Benchmark;
|
|
Current = settings.benchmarkData?[_benchIndex];
|
|
LoadBenchmark();
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
RenderPipelineManager.endFrameRendering -= EndFrameRendering;
|
|
#if UNITY_EDITOR
|
|
EditorSceneManager.playModeStartScene = null; // need to reset benchmark start scene once benchmark is destroyed
|
|
#endif
|
|
}
|
|
|
|
public void LoadBenchmark(int index)
|
|
{
|
|
singleBench = true;
|
|
_benchIndex = index;
|
|
Initialize();
|
|
}
|
|
|
|
private void LoadBenchmark()
|
|
{
|
|
AppSettings.LoadScene(Current.scene);
|
|
}
|
|
|
|
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
{
|
|
if (scene.path != Current.scene) return;
|
|
|
|
if (Current.warmup)
|
|
{
|
|
CurrentRunIndex = -1;
|
|
}
|
|
else
|
|
{
|
|
CurrentRunIndex = 0;
|
|
}
|
|
|
|
CurrentRunFrame = 0;
|
|
|
|
switch (Current.type)
|
|
{
|
|
case BenchmarkType.Scene:
|
|
break;
|
|
case BenchmarkType.Shader:
|
|
break;
|
|
default:
|
|
AppSettings.ExitGame("Benchmark Not Setup");
|
|
break;
|
|
}
|
|
|
|
if(settings.stats)
|
|
_stats.StartRun(Current.benchmarkName, Current.runLength);
|
|
|
|
BeginRun();
|
|
RenderPipelineManager.endFrameRendering += EndFrameRendering;
|
|
}
|
|
|
|
private void BeginRun()
|
|
{
|
|
CurrentRunFrame = 0;
|
|
}
|
|
|
|
private void EndFrameRendering(ScriptableRenderContext context, Camera[] cameras)
|
|
{
|
|
CurrentRunFrame++;
|
|
if (CurrentRunFrame < Current.runLength) return;
|
|
|
|
if(settings.stats)
|
|
_stats.EndRun();
|
|
|
|
CurrentRunIndex++;
|
|
if (CurrentRunIndex < Current.runs || simpleRun)
|
|
{
|
|
BeginRun();
|
|
}
|
|
else
|
|
{
|
|
RenderPipelineManager.endFrameRendering -= EndFrameRendering;
|
|
EndBenchmark();
|
|
}
|
|
}
|
|
|
|
public void EndBenchmark()
|
|
{
|
|
if(settings.stats && settings.saveData) SaveBenchmarkStats();
|
|
_benchIndex++;
|
|
|
|
if (_benchIndex < settings.benchmarkData.Count && !singleBench)
|
|
{
|
|
Current = settings.benchmarkData[_benchIndex];
|
|
LoadBenchmark();
|
|
}
|
|
else
|
|
{
|
|
FinishBenchmark();
|
|
}
|
|
}
|
|
|
|
private void FinishBenchmark()
|
|
{
|
|
SaveBenchmarkFile();
|
|
SceneManager.MoveGameObjectToScene(gameObject, SceneManager.GetActiveScene());
|
|
switch (finish)
|
|
{
|
|
case FinishAction.Exit:
|
|
AppSettings.ExitGame();
|
|
break;
|
|
case FinishAction.ShowStats:
|
|
break;
|
|
case FinishAction.Nothing:
|
|
break;
|
|
case FinishAction.MainMenu:
|
|
AppSettings.LoadScene(0);
|
|
break;
|
|
default:
|
|
AppSettings.ExitGame("Benchmark Not Setup");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void SaveBenchmarkStats()
|
|
{
|
|
var stats = _stats.EndBench();
|
|
if (stats != null)
|
|
{
|
|
_perfData.Add(stats);
|
|
}
|
|
}
|
|
|
|
private void SaveBenchmarkFile()
|
|
{
|
|
// File name
|
|
var dateTimeNow = DateTime.Now;
|
|
var filename = $"{Application.productName}-{SystemInfo.deviceName}-{dateTimeNow.ToShortDateString()}-{dateTimeNow.ToShortTimeString()}";
|
|
filename = Path.GetInvalidFileNameChars().Aggregate(filename, (current, c) => current.Replace(c, '-'));
|
|
var path = GetResultPath() + $"/{filename}.json";
|
|
|
|
// Pack results
|
|
var results = new PerfResults
|
|
{
|
|
fileName = Path.GetFileName(path),
|
|
filePath = Path.GetFullPath(path),
|
|
timestamp = DateTime.Now.ToString(DateTimeFormatInfo.InvariantInfo),
|
|
perfStats = _perfData.ToArray()
|
|
};
|
|
|
|
// Write file
|
|
File.WriteAllText(path, JsonUtility.ToJson(results));
|
|
}
|
|
|
|
private static string GetResultPath()
|
|
{
|
|
var path = Application.isEditor ? Directory.GetParent(Application.dataPath).ToString() : Application.persistentDataPath;
|
|
path += "/PerformanceResults";
|
|
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
|
|
return path;
|
|
}
|
|
|
|
public static List<PerfResults> LoadAllBenchmarkStats()
|
|
{
|
|
var list = new List<PerfResults>();
|
|
var fileList = Directory.GetFiles(GetResultPath());
|
|
|
|
foreach (var file in fileList)
|
|
{
|
|
if(!File.Exists(file))
|
|
break;
|
|
|
|
var data = File.ReadAllText(file);
|
|
var result = JsonUtility.FromJson<PerfResults>(data);
|
|
list.Add(result);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
}
|
|
|
|
public class PerfResults
|
|
{
|
|
public string fileName;
|
|
public string filePath;
|
|
public string timestamp;
|
|
public PerfBasic[] perfStats;
|
|
}
|
|
|
|
[Serializable]
|
|
public class PerfBasic
|
|
{
|
|
public TestInfo info;
|
|
public int Frames;
|
|
public RunData[] RunData;
|
|
|
|
public PerfBasic(string benchmarkName, string urpVersion, int frames)
|
|
{
|
|
Frames = frames;
|
|
info = new TestInfo(benchmarkName) {UrpVersion = urpVersion};
|
|
RunData = new RunData[Benchmark.Current.runs];
|
|
for (var index = 0; index < RunData.Length; index++)
|
|
{
|
|
RunData[index] = new RunData(new float[frames]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
public class RunData
|
|
{
|
|
public float RunTime;
|
|
public float AvgMs;
|
|
public FrameData MinFrame = FrameData.DefaultMin;
|
|
public FrameData MaxFrame = FrameData.DefaultMax;
|
|
public float[] rawSamples;
|
|
|
|
public RunData(float[] times) { rawSamples = times; }
|
|
|
|
public void Average()
|
|
{
|
|
AvgMs = 0.0f;
|
|
foreach (var sample in rawSamples)
|
|
{
|
|
AvgMs += sample / rawSamples.Length;
|
|
}
|
|
}
|
|
public void SetMin(float ms, int frame) { MinFrame.ms = ms; MinFrame.frameIndex = frame; }
|
|
public void SetMax(float ms, int frame) { MaxFrame.ms = ms; MaxFrame.frameIndex = frame; }
|
|
|
|
public void EndRun(float runtime, FrameData min, FrameData max)
|
|
{
|
|
RunTime = runtime;
|
|
MinFrame = min;
|
|
MaxFrame = max;
|
|
Average();
|
|
}
|
|
|
|
}
|
|
|
|
[Serializable]
|
|
public class FrameData
|
|
{
|
|
public int frameIndex;
|
|
public float ms;
|
|
|
|
public FrameData(int frameNumber, float frameTime)
|
|
{
|
|
frameIndex = frameNumber;
|
|
ms = frameTime;
|
|
}
|
|
|
|
public void Set(int frameNumber, float frameTime)
|
|
{
|
|
frameIndex = frameNumber;
|
|
ms = frameTime;
|
|
}
|
|
|
|
public static FrameData DefaultMin => new FrameData(-1, Single.PositiveInfinity);
|
|
|
|
public static FrameData DefaultMax => new FrameData(-1, Single.NegativeInfinity);
|
|
}
|
|
|
|
[Serializable]
|
|
public class TestInfo
|
|
{
|
|
public string BenchmarkName;
|
|
public string Scene;
|
|
public string UnityVersion;
|
|
public string UrpVersion;
|
|
public string BoatAttackVersion;
|
|
public string Platform;
|
|
public string API;
|
|
public string CPU;
|
|
public string GPU;
|
|
public string Os;
|
|
public string Quality;
|
|
public string Resolution;
|
|
|
|
public TestInfo(string benchmarkName, string urpVersion = "N/A")
|
|
{
|
|
BenchmarkName = benchmarkName;
|
|
Scene = Utility.RemoveWhitespace(SceneManager.GetActiveScene().name);
|
|
UnityVersion = Application.unityVersion;
|
|
UrpVersion = urpVersion;
|
|
BoatAttackVersion = Application.version;
|
|
Platform = Utility.RemoveWhitespace(Application.platform.ToString());
|
|
API = Utility.RemoveWhitespace(SystemInfo.graphicsDeviceType.ToString());
|
|
CPU = Utility.RemoveWhitespace(SystemInfo.processorType);
|
|
GPU = Utility.RemoveWhitespace(SystemInfo.graphicsDeviceName);
|
|
Os = Utility.RemoveWhitespace(SystemInfo.operatingSystem);
|
|
Quality = Utility.RemoveWhitespace(QualitySettings.names[QualitySettings.GetQualityLevel()]);
|
|
Resolution = $"{Display.main.renderingWidth}x{Display.main.renderingHeight}";
|
|
}
|
|
}
|
|
}
|