/ src / Ryujinx.HLE / PerformanceStatistics.cs
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  }