A game about forced loneliness, made by TACStudios
at master 131 lines 4.9 kB view raw
1using System; 2using System.Collections.Generic; 3 4namespace UnityEngine.Rendering 5{ 6 /// <summary> 7 /// Represents a system bottleneck, meaning the factor that is most dominant in determining 8 /// the total frame time. 9 /// </summary> 10 internal enum PerformanceBottleneck 11 { 12 Indeterminate, // Cannot be determined 13 PresentLimited, // Limited by presentation (vsync or framerate cap) 14 CPU, // Limited by CPU (main and/or render thread) 15 GPU, // Limited by GPU 16 Balanced, // Limited by both CPU and GPU, i.e. well balanced 17 } 18 19 /// <summary> 20 /// BottleneckHistogram represents the distribution of bottlenecks over the Bottleneck History Window, 21 /// the size of which is determined by <see cref="DebugFrameTiming.bottleneckHistorySize"/>. 22 /// </summary> 23 internal struct BottleneckHistogram 24 { 25 internal float PresentLimited; 26 internal float CPU; 27 internal float GPU; 28 internal float Balanced; 29 }; 30 31 /// <summary> 32 /// Container class for bottleneck history with helper to calculate histogram. 33 /// </summary> 34 internal class BottleneckHistory 35 { 36 public BottleneckHistory(int initialCapacity) 37 { 38 m_Bottlenecks.Capacity = initialCapacity; 39 } 40 41 List<PerformanceBottleneck> m_Bottlenecks = new(); 42 43 internal BottleneckHistogram Histogram; 44 45 internal void DiscardOldSamples(int historySize) 46 { 47 Debug.Assert(historySize > 0, "Invalid sampleHistorySize"); 48 49 while (m_Bottlenecks.Count >= historySize) 50 m_Bottlenecks.RemoveAt(0); 51 52 m_Bottlenecks.Capacity = historySize; 53 } 54 55 internal void AddBottleneckFromAveragedSample(FrameTimeSample frameHistorySampleAverage) 56 { 57 var bottleneck = DetermineBottleneck(frameHistorySampleAverage); 58 m_Bottlenecks.Add(bottleneck); 59 } 60 61 internal void ComputeHistogram() 62 { 63 var stats = new BottleneckHistogram(); 64 for (int i = 0; i < m_Bottlenecks.Count; i++) 65 { 66 switch (m_Bottlenecks[i]) 67 { 68 case PerformanceBottleneck.Balanced: 69 stats.Balanced++; 70 break; 71 case PerformanceBottleneck.CPU: 72 stats.CPU++; 73 break; 74 case PerformanceBottleneck.GPU: 75 stats.GPU++; 76 break; 77 case PerformanceBottleneck.PresentLimited: 78 stats.PresentLimited++; 79 break; 80 } 81 } 82 83 stats.Balanced /= m_Bottlenecks.Count; 84 stats.CPU /= m_Bottlenecks.Count; 85 stats.GPU /= m_Bottlenecks.Count; 86 stats.PresentLimited /= m_Bottlenecks.Count; 87 88 Histogram = stats; 89 } 90 91 static PerformanceBottleneck DetermineBottleneck(FrameTimeSample s) 92 { 93 const float kNearFullFrameTimeThresholdPercent = 0.2f; 94 const float kNonZeroPresentWaitTimeMs = 0.5f; 95 96 if (s.GPUFrameTime == 0 || s.MainThreadCPUFrameTime == 0) // In direct mode, render thread doesn't exist 97 return PerformanceBottleneck.Indeterminate; // Missing data 98 float fullFrameTimeWithMargin = (1f - kNearFullFrameTimeThresholdPercent) * s.FullFrameTime; 99 100 // GPU time is close to frame time, CPU times are not 101 if (s.GPUFrameTime > fullFrameTimeWithMargin && 102 s.MainThreadCPUFrameTime < fullFrameTimeWithMargin && 103 s.RenderThreadCPUFrameTime < fullFrameTimeWithMargin) 104 return PerformanceBottleneck.GPU; 105 106 // One of the CPU times is close to frame time, GPU is not 107 if (s.GPUFrameTime < fullFrameTimeWithMargin && 108 (s.MainThreadCPUFrameTime > fullFrameTimeWithMargin || 109 s.RenderThreadCPUFrameTime > fullFrameTimeWithMargin)) 110 return PerformanceBottleneck.CPU; 111 112 // Main thread waited due to Vsync or target frame rate 113 if (s.MainThreadCPUPresentWaitTime > kNonZeroPresentWaitTimeMs) 114 { 115 // None of the times are close to frame time 116 if (s.GPUFrameTime < fullFrameTimeWithMargin && 117 s.MainThreadCPUFrameTime < fullFrameTimeWithMargin && 118 s.RenderThreadCPUFrameTime < fullFrameTimeWithMargin) 119 return PerformanceBottleneck.PresentLimited; 120 } 121 122 return PerformanceBottleneck.Balanced; 123 } 124 125 internal void Clear() 126 { 127 m_Bottlenecks.Clear(); 128 Histogram = new BottleneckHistogram(); 129 } 130 } 131}