PerformanceStatistics.cs 5.4 KB

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