173 lines
7.5 KiB
C#
173 lines
7.5 KiB
C#
using NUnit.Framework;
|
|
|
|
namespace UnityEngine.Rendering.Tests
|
|
{
|
|
static class FrameTimingTestExtensions
|
|
{
|
|
public static BottleneckHistogram ToHistogram(this FrameTimeSample s)
|
|
{
|
|
var history = new BottleneckHistory(1);
|
|
history.AddBottleneckFromAveragedSample(s);
|
|
history.ComputeHistogram();
|
|
return history.Histogram;
|
|
}
|
|
|
|
public static string ToDebugString(this BottleneckHistogram h) =>
|
|
$"GPU={h.GPU}, CPU={h.CPU}, PresentLimited={h.PresentLimited}, Balanced={h.Balanced}";
|
|
}
|
|
|
|
class DebugFrameTimingTests
|
|
{
|
|
static FrameTimeSample MakeSample(
|
|
float fullFrameTime,
|
|
float gpu,
|
|
float mainCpu,
|
|
float renderCpu,
|
|
float presentWait = 0f,
|
|
float fps = 0f)
|
|
{
|
|
return new FrameTimeSample
|
|
{
|
|
FullFrameTime = fullFrameTime,
|
|
GPUFrameTime = gpu,
|
|
MainThreadCPUFrameTime = mainCpu,
|
|
RenderThreadCPUFrameTime = renderCpu,
|
|
MainThreadCPUPresentWaitTime = presentWait,
|
|
FramesPerSecond = fps
|
|
};
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_ZeroGPUFrameTime_ProducesIndeterminate()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 0, mainCpu: 5, renderCpu: 5).ToHistogram();
|
|
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f),
|
|
$"Zero GPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_ZeroMainThreadCPUFrameTime_ProducesIndeterminate()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 0, renderCpu: 5).ToHistogram();
|
|
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f),
|
|
$"Zero MainThreadCPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_GPUBound_ProducesGPU()
|
|
{
|
|
// GPU close to FullFrameTime, CPU times are not.
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 9, mainCpu: 2, renderCpu: 2).ToHistogram();
|
|
Assert.That(h.GPU, Is.EqualTo(1f),
|
|
$"GPU-dominant sample must put 100% in the GPU bucket. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_MainThreadCPUBound_ProducesCPU()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 9, renderCpu: 2).ToHistogram();
|
|
Assert.That(h.CPU, Is.EqualTo(1f),
|
|
$"MainThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_RenderThreadCPUBound_ProducesCPU()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 9).ToHistogram();
|
|
Assert.That(h.CPU, Is.EqualTo(1f),
|
|
$"RenderThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_BalancedWithPresentWait_ProducesPresentLimited()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 2, presentWait: 1f).ToHistogram();
|
|
Assert.That(h.PresentLimited, Is.EqualTo(1f),
|
|
$"Non-dominant sample with present wait > 0.5ms must classify as PresentLimited. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_BalancedWithoutPresentWait_ProducesBalanced()
|
|
{
|
|
var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 5, renderCpu: 5, presentWait: 0f).ToHistogram();
|
|
Assert.That(h.Balanced, Is.EqualTo(1f),
|
|
$"Non-dominant sample with no present wait must classify as Balanced. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_MixedSamples_RatiosMatchSampleCounts()
|
|
{
|
|
// 2x GPU, 2x CPU, 1x PresentLimited -> 0.4 / 0.4 / 0.2 / 0
|
|
var history = new BottleneckHistory(8);
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2));
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2));
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 2, 2, presentWait: 1f));
|
|
history.ComputeHistogram();
|
|
var h = history.Histogram;
|
|
|
|
Assert.That(h.GPU, Is.EqualTo(0.4f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}.");
|
|
Assert.That(h.CPU, Is.EqualTo(0.4f).Within(1e-6f), $"CPU bucket. Got {h.ToDebugString()}.");
|
|
Assert.That(h.PresentLimited, Is.EqualTo(0.2f).Within(1e-6f), $"PresentLimited bucket. Got {h.ToDebugString()}.");
|
|
Assert.That(h.Balanced, Is.EqualTo(0f), $"Balanced bucket. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Histogram_IndeterminateSamples_ReduceVisibleTotalBelowOne()
|
|
{
|
|
// 1 valid GPU sample + 4 indeterminate (GPU=0) -> visible total = 0.2.
|
|
var history = new BottleneckHistory(8);
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
|
|
for (int i = 0; i < 4; i++)
|
|
history.AddBottleneckFromAveragedSample(MakeSample(10, 0, 5, 5));
|
|
history.ComputeHistogram();
|
|
var h = history.Histogram;
|
|
|
|
Assert.That(h.GPU, Is.EqualTo(0.2f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}.");
|
|
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0.2f).Within(1e-6f),
|
|
$"Indeterminate samples must be excluded from visible buckets. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void BottleneckHistory_DiscardOldSamples_KeepsAtMostHistorySize()
|
|
{
|
|
// With historySize=3, add 5 GPU-bound then 2 CPU-bound samples.
|
|
// Retained samples should be [GPU, CPU, CPU] -> GPU=1/3, CPU=2/3.
|
|
const int historySize = 3;
|
|
var history = new BottleneckHistory(historySize);
|
|
var gpuSample = MakeSample(10, 9, 2, 2);
|
|
var cpuSample = MakeSample(10, 2, 9, 2);
|
|
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
history.DiscardOldSamples(historySize);
|
|
history.AddBottleneckFromAveragedSample(gpuSample);
|
|
}
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
history.DiscardOldSamples(historySize);
|
|
history.AddBottleneckFromAveragedSample(cpuSample);
|
|
}
|
|
history.ComputeHistogram();
|
|
var h = history.Histogram;
|
|
|
|
Assert.That(h.GPU, Is.EqualTo(1f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}.");
|
|
Assert.That(h.CPU, Is.EqualTo(2f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}.");
|
|
}
|
|
|
|
[Test]
|
|
public void Reset_ClearsBottleneckHistogram()
|
|
{
|
|
var debug = new DebugFrameTiming();
|
|
debug.m_BottleneckHistory.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
|
|
debug.m_BottleneckHistory.ComputeHistogram();
|
|
|
|
debug.Reset();
|
|
|
|
var h = debug.m_BottleneckHistory.Histogram;
|
|
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f), $"Reset must zero the histogram. Got {h.ToDebugString()}.");
|
|
}
|
|
}
|
|
}
|