Skip to content

Commit 7423568

Browse files
arttu-peltonenEvergreen
authored andcommitted
Re-enable RuntimeProfilerTests
1 parent 0ff666f commit 7423568

3 files changed

Lines changed: 214 additions & 15 deletions

File tree

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
using NUnit.Framework;
2+
3+
namespace UnityEngine.Rendering.Tests
4+
{
5+
static class FrameTimingTestExtensions
6+
{
7+
public static BottleneckHistogram ToHistogram(this FrameTimeSample s)
8+
{
9+
var history = new BottleneckHistory(1);
10+
history.AddBottleneckFromAveragedSample(s);
11+
history.ComputeHistogram();
12+
return history.Histogram;
13+
}
14+
15+
public static string ToDebugString(this BottleneckHistogram h) =>
16+
$"GPU={h.GPU}, CPU={h.CPU}, PresentLimited={h.PresentLimited}, Balanced={h.Balanced}";
17+
}
18+
19+
class DebugFrameTimingTests
20+
{
21+
static FrameTimeSample MakeSample(
22+
float fullFrameTime,
23+
float gpu,
24+
float mainCpu,
25+
float renderCpu,
26+
float presentWait = 0f,
27+
float fps = 0f)
28+
{
29+
return new FrameTimeSample
30+
{
31+
FullFrameTime = fullFrameTime,
32+
GPUFrameTime = gpu,
33+
MainThreadCPUFrameTime = mainCpu,
34+
RenderThreadCPUFrameTime = renderCpu,
35+
MainThreadCPUPresentWaitTime = presentWait,
36+
FramesPerSecond = fps
37+
};
38+
}
39+
40+
[Test]
41+
public void Histogram_ZeroGPUFrameTime_ProducesIndeterminate()
42+
{
43+
var h = MakeSample(fullFrameTime: 10, gpu: 0, mainCpu: 5, renderCpu: 5).ToHistogram();
44+
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f),
45+
$"Zero GPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}.");
46+
}
47+
48+
[Test]
49+
public void Histogram_ZeroMainThreadCPUFrameTime_ProducesIndeterminate()
50+
{
51+
var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 0, renderCpu: 5).ToHistogram();
52+
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f),
53+
$"Zero MainThreadCPUFrameTime must classify as Indeterminate (all buckets 0). Got {h.ToDebugString()}.");
54+
}
55+
56+
[Test]
57+
public void Histogram_GPUBound_ProducesGPU()
58+
{
59+
// GPU close to FullFrameTime, CPU times are not.
60+
var h = MakeSample(fullFrameTime: 10, gpu: 9, mainCpu: 2, renderCpu: 2).ToHistogram();
61+
Assert.That(h.GPU, Is.EqualTo(1f),
62+
$"GPU-dominant sample must put 100% in the GPU bucket. Got {h.ToDebugString()}.");
63+
}
64+
65+
[Test]
66+
public void Histogram_MainThreadCPUBound_ProducesCPU()
67+
{
68+
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 9, renderCpu: 2).ToHistogram();
69+
Assert.That(h.CPU, Is.EqualTo(1f),
70+
$"MainThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}.");
71+
}
72+
73+
[Test]
74+
public void Histogram_RenderThreadCPUBound_ProducesCPU()
75+
{
76+
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 9).ToHistogram();
77+
Assert.That(h.CPU, Is.EqualTo(1f),
78+
$"RenderThread-dominant sample must put 100% in the CPU bucket. Got {h.ToDebugString()}.");
79+
}
80+
81+
[Test]
82+
public void Histogram_BalancedWithPresentWait_ProducesPresentLimited()
83+
{
84+
var h = MakeSample(fullFrameTime: 10, gpu: 2, mainCpu: 2, renderCpu: 2, presentWait: 1f).ToHistogram();
85+
Assert.That(h.PresentLimited, Is.EqualTo(1f),
86+
$"Non-dominant sample with present wait > 0.5ms must classify as PresentLimited. Got {h.ToDebugString()}.");
87+
}
88+
89+
[Test]
90+
public void Histogram_BalancedWithoutPresentWait_ProducesBalanced()
91+
{
92+
var h = MakeSample(fullFrameTime: 10, gpu: 5, mainCpu: 5, renderCpu: 5, presentWait: 0f).ToHistogram();
93+
Assert.That(h.Balanced, Is.EqualTo(1f),
94+
$"Non-dominant sample with no present wait must classify as Balanced. Got {h.ToDebugString()}.");
95+
}
96+
97+
[Test]
98+
public void Histogram_MixedSamples_RatiosMatchSampleCounts()
99+
{
100+
// 2x GPU, 2x CPU, 1x PresentLimited -> 0.4 / 0.4 / 0.2 / 0
101+
var history = new BottleneckHistory(8);
102+
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
103+
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
104+
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2));
105+
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 9, 2));
106+
history.AddBottleneckFromAveragedSample(MakeSample(10, 2, 2, 2, presentWait: 1f));
107+
history.ComputeHistogram();
108+
var h = history.Histogram;
109+
110+
Assert.That(h.GPU, Is.EqualTo(0.4f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}.");
111+
Assert.That(h.CPU, Is.EqualTo(0.4f).Within(1e-6f), $"CPU bucket. Got {h.ToDebugString()}.");
112+
Assert.That(h.PresentLimited, Is.EqualTo(0.2f).Within(1e-6f), $"PresentLimited bucket. Got {h.ToDebugString()}.");
113+
Assert.That(h.Balanced, Is.EqualTo(0f), $"Balanced bucket. Got {h.ToDebugString()}.");
114+
}
115+
116+
[Test]
117+
public void Histogram_IndeterminateSamples_ReduceVisibleTotalBelowOne()
118+
{
119+
// 1 valid GPU sample + 4 indeterminate (GPU=0) -> visible total = 0.2.
120+
var history = new BottleneckHistory(8);
121+
history.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
122+
for (int i = 0; i < 4; i++)
123+
history.AddBottleneckFromAveragedSample(MakeSample(10, 0, 5, 5));
124+
history.ComputeHistogram();
125+
var h = history.Histogram;
126+
127+
Assert.That(h.GPU, Is.EqualTo(0.2f).Within(1e-6f), $"GPU bucket. Got {h.ToDebugString()}.");
128+
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0.2f).Within(1e-6f),
129+
$"Indeterminate samples must be excluded from visible buckets. Got {h.ToDebugString()}.");
130+
}
131+
132+
[Test]
133+
public void BottleneckHistory_DiscardOldSamples_KeepsAtMostHistorySize()
134+
{
135+
// With historySize=3, add 5 GPU-bound then 2 CPU-bound samples.
136+
// Retained samples should be [GPU, CPU, CPU] -> GPU=1/3, CPU=2/3.
137+
const int historySize = 3;
138+
var history = new BottleneckHistory(historySize);
139+
var gpuSample = MakeSample(10, 9, 2, 2);
140+
var cpuSample = MakeSample(10, 2, 9, 2);
141+
142+
for (int i = 0; i < 5; i++)
143+
{
144+
history.DiscardOldSamples(historySize);
145+
history.AddBottleneckFromAveragedSample(gpuSample);
146+
}
147+
for (int i = 0; i < 2; i++)
148+
{
149+
history.DiscardOldSamples(historySize);
150+
history.AddBottleneckFromAveragedSample(cpuSample);
151+
}
152+
history.ComputeHistogram();
153+
var h = history.Histogram;
154+
155+
Assert.That(h.GPU, Is.EqualTo(1f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}.");
156+
Assert.That(h.CPU, Is.EqualTo(2f / 3f).Within(1e-6f), $"Only 3 newest samples should be retained. Got {h.ToDebugString()}.");
157+
}
158+
159+
[Test]
160+
public void Reset_ClearsBottleneckHistogram()
161+
{
162+
var debug = new DebugFrameTiming();
163+
debug.m_BottleneckHistory.AddBottleneckFromAveragedSample(MakeSample(10, 9, 2, 2));
164+
debug.m_BottleneckHistory.ComputeHistogram();
165+
166+
debug.Reset();
167+
168+
var h = debug.m_BottleneckHistory.Histogram;
169+
Assert.That(h.GPU + h.CPU + h.PresentLimited + h.Balanced, Is.EqualTo(0f), $"Reset must zero the histogram. Got {h.ToDebugString()}.");
170+
}
171+
}
172+
}

Packages/com.unity.render-pipelines.core/Tests/Runtime/DebugFrameTimingTests.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/com.unity.render-pipelines.core/Tests/Runtime/RuntimeProfilerTests.cs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using System.Collections;
22
using UnityEngine.TestTools;
33
using NUnit.Framework;
4+
#if ENABLE_VR && ENABLE_XR_MODULE
5+
using UnityEngine.XR;
6+
#endif
47

58
namespace UnityEngine.Rendering.Tests
69
{
@@ -21,6 +24,9 @@ public void Setup()
2124
if (Application.isBatchMode)
2225
Assert.Ignore("Frame timing tests are not supported in batch mode, skipping test.");
2326

27+
if (GraphicsSettings.currentRenderPipeline == null)
28+
Assert.Ignore("No active Render Pipeline is set, skipping test.");
29+
2430
// HACK #1 - really shouldn't have to do this here, but previous tests are leaking gameobjects
2531
#pragma warning disable CS0618 // Type or member is obsolete
2632
var objects = GameObject.FindObjectsByType<GameObject>(FindObjectsSortMode.InstanceID);
@@ -51,21 +57,23 @@ protected IEnumerator Warmup()
5157
}
5258
}
5359

54-
// Fails on WebGL, Oculus Quest and Switch.
55-
// Unfortunately, there is no good way to exclude Oculus Quest from the test without excluding all Android devices.
56-
// https://jira.unity3d.com/browse/GFXFOUND-559
57-
[UnityPlatform(exclude = new RuntimePlatform[] { RuntimePlatform.WebGLPlayer, RuntimePlatform.Android, RuntimePlatform.Switch, RuntimePlatform.WindowsEditor })] // Unstable on WindowsEditor: https://jira.unity3d.com/browse/UUM-135231
5860
class RuntimeProfilerTests : RuntimeProfilerTestBase
5961
{
6062
[UnityTest]
6163
public IEnumerator RuntimeProfilerGivesNonZeroOutput()
6264
{
63-
if ((Application.platform == RuntimePlatform.LinuxPlayer ||
64-
Application.platform == RuntimePlatform.LinuxEditor)
65-
&& SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore)
66-
{
67-
Assert.Ignore("Test is failing on Linux OpenGLCore. https://jira.unity3d.com/browse/GFXFOUND-559");
68-
}
65+
// GPU Frame Time support is partial (https://docs.unity3d.com/6000.6/Documentation/Manual/frame-timing-manager.html),
66+
// so adding exceptions here.
67+
bool supportsGpuFrameTime = true;
68+
69+
if ((Application.platform == RuntimePlatform.LinuxPlayer || Application.platform == RuntimePlatform.LinuxEditor) && SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLCore)
70+
supportsGpuFrameTime = false; // Linux + OpenGLCore
71+
if (Application.platform == RuntimePlatform.WebGLPlayer)
72+
supportsGpuFrameTime = false; // WebGL/WebGPU
73+
#if ENABLE_VR && ENABLE_XR_MODULE
74+
if (XRSettings.enabled)
75+
supportsGpuFrameTime = false; // XR
76+
#endif
6977

7078
yield return Warmup();
7179

@@ -86,11 +94,28 @@ public IEnumerator RuntimeProfilerGivesNonZeroOutput()
8694
yield return null;
8795
}
8896

89-
Assert.True(
90-
m_DebugFrameTiming.m_BottleneckHistory.Histogram.Balanced > 0 ||
91-
m_DebugFrameTiming.m_BottleneckHistory.Histogram.CPU > 0 ||
92-
m_DebugFrameTiming.m_BottleneckHistory.Histogram.GPU > 0 ||
93-
m_DebugFrameTiming.m_BottleneckHistory.Histogram.PresentLimited > 0);
97+
// After k_NumFramesToRender frames, we should have a valid average for every headline counter.
98+
// A failure means the counter was zero on every captured frame. RenderThreadCPUFrameTime and
99+
// MainThreadCPUPresentWaitTime are excluded because they can legitimately be zero (modes without
100+
// a separate render thread; no vsync / no frame rate cap). GPUFrameTime is only asserted on
101+
// platforms known to report it (see supportsGpuFrameTime above).
102+
var avg = m_DebugFrameTiming.m_FrameHistory.SampleAverage;
103+
var zeroAvg = new System.Collections.Generic.List<string>();
104+
if (avg.FramesPerSecond <= 0f)
105+
zeroAvg.Add(nameof(avg.FramesPerSecond));
106+
if (avg.FullFrameTime <= 0f)
107+
zeroAvg.Add(nameof(avg.FullFrameTime));
108+
if (avg.MainThreadCPUFrameTime <= 0f)
109+
zeroAvg.Add(nameof(avg.MainThreadCPUFrameTime));
110+
if (supportsGpuFrameTime && avg.GPUFrameTime <= 0f)
111+
zeroAvg.Add(nameof(avg.GPUFrameTime));
112+
113+
Assert.That(zeroAvg, Is.Empty,
114+
$"After {k_NumFramesToRender} frames the following SampleAverage counters were zero: [{string.Join(", ", zeroAvg)}]. " +
115+
$"All averages: FramesPerSecond={avg.FramesPerSecond}, FullFrameTime={avg.FullFrameTime}, " +
116+
$"MainThreadCPUFrameTime={avg.MainThreadCPUFrameTime}, RenderThreadCPUFrameTime={avg.RenderThreadCPUFrameTime}, " +
117+
$"GPUFrameTime={avg.GPUFrameTime} (asserted={supportsGpuFrameTime}), " +
118+
$"MainThreadCPUPresentWaitTime={avg.MainThreadCPUPresentWaitTime}.");
94119
}
95120
}
96121
}

0 commit comments

Comments
 (0)