287 lines
9.1 KiB
C#
287 lines
9.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Benchmarking
|
|
{
|
|
|
|
public struct FrameData
|
|
{
|
|
public float frameTime;
|
|
private float _fpsOverride;
|
|
public float fps => (_fpsOverride > 0f) ? _fpsOverride : 1000f / frameTime;
|
|
|
|
public bool advancedFrameTiming;
|
|
public double cpuTime;
|
|
public double cpuRenderTime;
|
|
public double gpuTime;
|
|
|
|
public double timeLineTime;
|
|
|
|
const int k_timingsCaptureCount = 3;
|
|
|
|
public FrameData(float timeMS, float timelineTime = 0)
|
|
{
|
|
frameTime = timeMS;
|
|
this.timeLineTime = timelineTime;
|
|
_fpsOverride = -1f;
|
|
|
|
advancedFrameTiming = false;
|
|
cpuTime = cpuRenderTime = gpuTime = timeMS;
|
|
}
|
|
|
|
public void CaptureFrameTimings()
|
|
{
|
|
advancedFrameTiming = FrameTimingManager.IsFeatureEnabled();
|
|
|
|
if (advancedFrameTiming)
|
|
{
|
|
FrameTimingManager.CaptureFrameTimings();
|
|
FrameTiming[] timings = new FrameTiming[k_timingsCaptureCount];
|
|
uint count = FrameTimingManager.GetLatestTimings(k_timingsCaptureCount, timings);
|
|
if (count > 0)
|
|
{
|
|
cpuTime = timings[0].cpuFrameTime;
|
|
cpuRenderTime = timings[0].cpuRenderThreadFrameTime;
|
|
gpuTime = timings[0].gpuFrameTime;
|
|
|
|
// Sometimes GPU timing is invalid, try to get the previous timing values and average
|
|
//*
|
|
if (count > 1)
|
|
{
|
|
for (int i = 1; i < count; i++)
|
|
gpuTime += timings[i].gpuFrameTime;
|
|
|
|
gpuTime /= count;
|
|
}
|
|
//*/
|
|
}
|
|
}
|
|
}
|
|
|
|
public static FrameData GetCurrentFrameData( float timelineTime = 0 )
|
|
{
|
|
return new FrameData(Time.deltaTime * 1000f, timelineTime);
|
|
}
|
|
|
|
public void SetFPSOverride(float fpsOverride)
|
|
{
|
|
_fpsOverride = fpsOverride;
|
|
}
|
|
|
|
public void ResetFPSOverride() { _fpsOverride = -1f; }
|
|
|
|
public static FrameData Min(FrameData a, FrameData b, ref bool bSmaller, bool overrideFPS = false)
|
|
{
|
|
FrameData o = new FrameData();
|
|
|
|
bSmaller = b.frameTime < a.frameTime;
|
|
o.frameTime = bSmaller? b.frameTime : a.frameTime;
|
|
if (overrideFPS)
|
|
o._fpsOverride = Mathf.Min(a.fps, b.fps);
|
|
else
|
|
o._fpsOverride = -1f;
|
|
|
|
o.advancedFrameTiming = a.advancedFrameTiming && b.advancedFrameTiming;
|
|
if (o.advancedFrameTiming)
|
|
{
|
|
o.cpuTime = DoubleMin(a.cpuTime, b.cpuTime);
|
|
o.cpuRenderTime = DoubleMin(a.cpuRenderTime, b.cpuRenderTime);
|
|
o.gpuTime = DoubleMin(a.gpuTime, b.gpuTime);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
public bool MinWith(FrameData other, bool overrideFPS = false)
|
|
{
|
|
bool o = false;
|
|
this = Min(this, other, ref o, overrideFPS);
|
|
return o;
|
|
}
|
|
|
|
public static FrameData Max(FrameData a, FrameData b, ref bool bGreater, bool overrideFPS = false)
|
|
{
|
|
FrameData o = new FrameData();
|
|
|
|
bGreater = b.frameTime > a.frameTime;
|
|
|
|
o.frameTime = bGreater? b.frameTime : a.frameTime;
|
|
if (overrideFPS)
|
|
o._fpsOverride = Mathf.Max(a.fps, b.fps);
|
|
else
|
|
o._fpsOverride = -1f;
|
|
|
|
o.advancedFrameTiming = a.advancedFrameTiming && b.advancedFrameTiming;
|
|
if (o.advancedFrameTiming)
|
|
{
|
|
o.cpuTime = DoubleMax(a.cpuTime, b.cpuTime);
|
|
o.cpuRenderTime = DoubleMax(a.cpuRenderTime, b.cpuRenderTime);
|
|
o.gpuTime = DoubleMax(a.gpuTime, b.gpuTime);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
public bool MaxWith(FrameData other, bool overrideFPS = false)
|
|
{
|
|
bool o = false;
|
|
this = Max(this, other, ref o, overrideFPS);
|
|
return o;
|
|
}
|
|
|
|
public static FrameData Average(FrameData a, int countA, FrameData b, int countB, bool overrideFPS = false)
|
|
{
|
|
FrameData o = new FrameData();
|
|
float divider = 1.0f / (countA + countB);
|
|
o.frameTime = (a.frameTime * countA + b.frameTime * countB) * divider;
|
|
if (overrideFPS)
|
|
o._fpsOverride = (a.fps * countA + b.fps * countB) * divider;
|
|
else
|
|
o._fpsOverride = -1f;
|
|
|
|
o.advancedFrameTiming = a.advancedFrameTiming && b.advancedFrameTiming;
|
|
if (o.advancedFrameTiming)
|
|
{
|
|
o.cpuTime = (a.cpuTime * countA + b.cpuTime * countB) * divider;
|
|
o.cpuRenderTime = (a.cpuRenderTime * countA + b.cpuRenderTime * countB) * divider;
|
|
o.gpuTime = (a.gpuTime * countA + b.gpuTime * countB) * divider;
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
public void AverageWith(FrameData other, int count, bool overrideFPS = false)
|
|
{
|
|
this = Average(this, count - 1, other, 1, overrideFPS);
|
|
}
|
|
|
|
public static FrameData Lerp(FrameData a, FrameData b, float t)
|
|
{
|
|
FrameData o = new FrameData();
|
|
o.frameTime = Mathf.Lerp(a.frameTime, b.frameTime, t);
|
|
o._fpsOverride = -1f;
|
|
|
|
o.advancedFrameTiming = a.advancedFrameTiming && b.advancedFrameTiming;
|
|
if (o.advancedFrameTiming)
|
|
{
|
|
o.cpuTime = DoubleLerp(a.cpuTime, b.cpuTime, t);
|
|
o.cpuRenderTime = DoubleLerp(a.cpuRenderTime, b.cpuRenderTime, t);
|
|
o.gpuTime = DoubleLerp(a.gpuTime, b.gpuTime, t);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
public static FrameData MinMultiple(List<FrameData> frameTimes)
|
|
{
|
|
if (frameTimes == null || frameTimes.Count < 1)
|
|
return new FrameData();
|
|
|
|
FrameData o = frameTimes[0];
|
|
for (int i = 1; i < frameTimes.Count; i++)
|
|
{
|
|
o.MinWith(frameTimes[i], true);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
public static FrameData MaxMultiple(List<FrameData> frameTimes)
|
|
{
|
|
if (frameTimes == null || frameTimes.Count < 1)
|
|
return new FrameData();
|
|
|
|
FrameData o = frameTimes[0];
|
|
for (int i = 1; i < frameTimes.Count; i++)
|
|
{
|
|
o.MaxWith(frameTimes[i], true);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
private static double DoubleMin(double a, double b)
|
|
{
|
|
return (a < b) ? a : b;
|
|
}
|
|
private static double DoubleMax(double a, double b)
|
|
{
|
|
return (a > b) ? a : b;
|
|
}
|
|
private static double DoubleLerp(double a, double b, double t)
|
|
{
|
|
return a * (1 - t) + b * t;
|
|
}
|
|
|
|
override public string ToString()
|
|
{
|
|
return $"FrameData{{frameTime: {frameTime} ms, fps: {fps}, advancedFrameTiming: {advancedFrameTiming}, cpuTime: {cpuTime} ms, cpuRenderTime: {cpuRenderTime} ms, gpuTime: {gpuTime} ms}}";
|
|
}
|
|
|
|
public string GetValueString (DataType dataType)
|
|
{
|
|
string format = "F2";
|
|
switch (dataType)
|
|
{
|
|
case DataType.FPS:
|
|
return fps.ToString(format);
|
|
case DataType.CPUTime:
|
|
return cpuTime.ToString(format);
|
|
case DataType.CPURenderTime:
|
|
return cpuRenderTime.ToString(format);
|
|
case DataType.GPUTime:
|
|
return gpuTime.ToString(format);
|
|
default:
|
|
return frameTime.ToString(format);
|
|
}
|
|
}
|
|
|
|
public float GetValue(DataType dataType)
|
|
{
|
|
switch (dataType)
|
|
{
|
|
case DataType.FPS:
|
|
return fps;
|
|
case DataType.CPUTime:
|
|
return (float)cpuTime;
|
|
case DataType.CPURenderTime:
|
|
return (float)cpuRenderTime;
|
|
case DataType.GPUTime:
|
|
return (float)gpuTime;
|
|
default:
|
|
return frameTime;
|
|
}
|
|
}
|
|
|
|
public void WriteCSV(string before = null, bool writeTimeLineTime = false)
|
|
{
|
|
string[] strings = new string[ 5 + (before == null? 0:1) + (writeTimeLineTime?1:0) ];
|
|
|
|
int i = 0;
|
|
|
|
if (before != null)
|
|
{
|
|
strings[i] = before;
|
|
i++;
|
|
}
|
|
|
|
if (writeTimeLineTime)
|
|
{
|
|
strings[i] = timeLineTime.ToString();
|
|
i++;
|
|
}
|
|
|
|
strings[i] = frameTime.ToString();
|
|
i++;
|
|
strings[i] = fps.ToString();
|
|
i++;
|
|
strings[i] = cpuTime.ToString();
|
|
i++;
|
|
strings[i] = cpuRenderTime.ToString();
|
|
i++;
|
|
strings[i] = gpuTime.ToString();
|
|
|
|
PerformanceTest.CSVWrinteLine(strings);
|
|
}
|
|
}
|
|
} |