PerformanceStatistics.cs
1 using Ryujinx.Common; 2 using System.Timers; 3 4 namespace Ryujinx.HLE 5 { 6 public class PerformanceStatistics 7 { 8 private const int FrameTypeGame = 0; 9 private const int PercentTypeFifo = 0; 10 11 private readonly double[] _frameRate; 12 private readonly double[] _accumulatedFrameTime; 13 private readonly double[] _previousFrameTime; 14 15 private readonly double[] _averagePercent; 16 private readonly double[] _accumulatedActiveTime; 17 private readonly double[] _percentLastEndTime; 18 private readonly double[] _percentStartTime; 19 20 private readonly long[] _framesRendered; 21 private readonly double[] _percentTime; 22 23 private readonly object[] _frameLock; 24 private readonly object[] _percentLock; 25 26 private readonly double _ticksToSeconds; 27 28 private readonly Timer _resetTimer; 29 30 public PerformanceStatistics() 31 { 32 _frameRate = new double[1]; 33 _accumulatedFrameTime = new double[1]; 34 _previousFrameTime = new double[1]; 35 36 _averagePercent = new double[1]; 37 _accumulatedActiveTime = new double[1]; 38 _percentLastEndTime = new double[1]; 39 _percentStartTime = new double[1]; 40 41 _framesRendered = new long[1]; 42 _percentTime = new double[1]; 43 44 _frameLock = new[] { new object() }; 45 _percentLock = new[] { new object() }; 46 47 _resetTimer = new Timer(750); 48 49 _resetTimer.Elapsed += ResetTimerElapsed; 50 _resetTimer.AutoReset = true; 51 52 _resetTimer.Start(); 53 54 _ticksToSeconds = 1.0 / PerformanceCounter.TicksPerSecond; 55 } 56 57 private void ResetTimerElapsed(object sender, ElapsedEventArgs e) 58 { 59 CalculateFrameRate(FrameTypeGame); 60 CalculateAveragePercent(PercentTypeFifo); 61 } 62 63 private void CalculateFrameRate(int frameType) 64 { 65 double frameRate = 0; 66 67 lock (_frameLock[frameType]) 68 { 69 if (_accumulatedFrameTime[frameType] > 0) 70 { 71 frameRate = _framesRendered[frameType] / _accumulatedFrameTime[frameType]; 72 } 73 74 _frameRate[frameType] = frameRate; 75 _framesRendered[frameType] = 0; 76 _accumulatedFrameTime[frameType] = 0; 77 } 78 } 79 80 private void CalculateAveragePercent(int percentType) 81 { 82 // If start time is non-zero, a percent reading is still being measured. 83 // If there aren't any readings, the default should be 100% if still being measured, or 0% if not. 84 double percent = (_percentStartTime[percentType] == 0) ? 0 : 100; 85 86 lock (_percentLock[percentType]) 87 { 88 if (_percentTime[percentType] > 0) 89 { 90 percent = (_accumulatedActiveTime[percentType] / _percentTime[percentType]) * 100; 91 } 92 93 _averagePercent[percentType] = percent; 94 _percentTime[percentType] = 0; 95 _accumulatedActiveTime[percentType] = 0; 96 } 97 } 98 99 public void RecordGameFrameTime() 100 { 101 RecordFrameTime(FrameTypeGame); 102 } 103 104 public void RecordFifoStart() 105 { 106 StartPercentTime(PercentTypeFifo); 107 } 108 109 public void RecordFifoEnd() 110 { 111 EndPercentTime(PercentTypeFifo); 112 } 113 114 private void StartPercentTime(int percentType) 115 { 116 double currentTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; 117 118 _percentStartTime[percentType] = currentTime; 119 } 120 121 private void EndPercentTime(int percentType) 122 { 123 double currentTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; 124 double elapsedTime = currentTime - _percentLastEndTime[percentType]; 125 double elapsedActiveTime = currentTime - _percentStartTime[percentType]; 126 127 lock (_percentLock[percentType]) 128 { 129 _accumulatedActiveTime[percentType] += elapsedActiveTime; 130 _percentTime[percentType] += elapsedTime; 131 } 132 133 _percentLastEndTime[percentType] = currentTime; 134 _percentStartTime[percentType] = 0; 135 } 136 137 private void RecordFrameTime(int frameType) 138 { 139 double currentFrameTime = PerformanceCounter.ElapsedTicks * _ticksToSeconds; 140 double elapsedFrameTime = currentFrameTime - _previousFrameTime[frameType]; 141 142 _previousFrameTime[frameType] = currentFrameTime; 143 144 lock (_frameLock[frameType]) 145 { 146 _accumulatedFrameTime[frameType] += elapsedFrameTime; 147 148 _framesRendered[frameType]++; 149 } 150 } 151 152 public double GetGameFrameRate() 153 { 154 return _frameRate[FrameTypeGame]; 155 } 156 157 public double GetFifoPercent() 158 { 159 return _averagePercent[PercentTypeFifo]; 160 } 161 162 public double GetGameFrameTime() 163 { 164 return 1000 / _frameRate[FrameTypeGame]; 165 } 166 } 167 }