aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Profiler/TimingInfo.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Profiler/TimingInfo.cs')
-rw-r--r--Ryujinx.Profiler/TimingInfo.cs174
1 files changed, 174 insertions, 0 deletions
diff --git a/Ryujinx.Profiler/TimingInfo.cs b/Ryujinx.Profiler/TimingInfo.cs
new file mode 100644
index 00000000..e444e423
--- /dev/null
+++ b/Ryujinx.Profiler/TimingInfo.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Profiler
+{
+ public struct Timestamp
+ {
+ public long BeginTime;
+ public long EndTime;
+ }
+
+ public class TimingInfo
+ {
+ // Timestamps
+ public long TotalTime { get; set; }
+ public long Instant { get; set; }
+
+ // Measurement counts
+ public int Count { get; set; }
+ public int InstantCount { get; set; }
+
+ // Work out average
+ public long AverageTime => (Count == 0) ? -1 : TotalTime / Count;
+
+ // Intentionally not locked as it's only a get count
+ public bool IsActive => _timestamps.Count > 0;
+
+ public long BeginTime
+ {
+ get
+ {
+ lock (_timestampLock)
+ {
+ if (_depth > 0)
+ {
+ return _currentTimestamp.BeginTime;
+ }
+
+ return -1;
+ }
+ }
+ }
+
+ // Timestamp collection
+ private List<Timestamp> _timestamps;
+ private readonly object _timestampLock = new object();
+ private readonly object _timestampListLock = new object();
+ private Timestamp _currentTimestamp;
+
+ // Depth of current timer,
+ // each begin call increments and each end call decrements
+ private int _depth;
+
+ public TimingInfo()
+ {
+ _timestamps = new List<Timestamp>();
+ _depth = 0;
+ }
+
+ public void Begin(long beginTime)
+ {
+ lock (_timestampLock)
+ {
+ // Finish current timestamp if already running
+ if (_depth > 0)
+ {
+ EndUnsafe(beginTime);
+ }
+
+ BeginUnsafe(beginTime);
+ _depth++;
+ }
+ }
+
+ private void BeginUnsafe(long beginTime)
+ {
+ _currentTimestamp.BeginTime = beginTime;
+ _currentTimestamp.EndTime = -1;
+ }
+
+ public void End(long endTime)
+ {
+ lock (_timestampLock)
+ {
+ _depth--;
+
+ if (_depth < 0)
+ {
+ throw new Exception("Timing info end called without corresponding begin");
+ }
+
+ EndUnsafe(endTime);
+
+ // Still have others using this timing info so recreate start for them
+ if (_depth > 0)
+ {
+ BeginUnsafe(endTime);
+ }
+ }
+ }
+
+ private void EndUnsafe(long endTime)
+ {
+ _currentTimestamp.EndTime = endTime;
+ lock (_timestampListLock)
+ {
+ _timestamps.Add(_currentTimestamp);
+ }
+
+ var delta = _currentTimestamp.EndTime - _currentTimestamp.BeginTime;
+ TotalTime += delta;
+ Instant += delta;
+
+ Count++;
+ InstantCount++;
+ }
+
+ // Remove any timestamps before given timestamp to free memory
+ public void Cleanup(long before, long preserveStart, long preserveEnd)
+ {
+ lock (_timestampListLock)
+ {
+ int toRemove = 0;
+ int toPreserveStart = 0;
+ int toPreserveLen = 0;
+
+ for (int i = 0; i < _timestamps.Count; i++)
+ {
+ if (_timestamps[i].EndTime < preserveStart)
+ {
+ toPreserveStart++;
+ InstantCount--;
+ Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
+ }
+ else if (_timestamps[i].EndTime < preserveEnd)
+ {
+ toPreserveLen++;
+ }
+ else if (_timestamps[i].EndTime < before)
+ {
+ toRemove++;
+ InstantCount--;
+ Instant -= _timestamps[i].EndTime - _timestamps[i].BeginTime;
+ }
+ else
+ {
+ // Assume timestamps are in chronological order so no more need to be removed
+ break;
+ }
+ }
+
+ if (toPreserveStart > 0)
+ {
+ _timestamps.RemoveRange(0, toPreserveStart);
+ }
+
+ if (toRemove > 0)
+ {
+ _timestamps.RemoveRange(toPreserveLen, toRemove);
+ }
+ }
+ }
+
+ public Timestamp[] GetAllTimestamps()
+ {
+ lock (_timestampListLock)
+ {
+ Timestamp[] returnTimestamps = new Timestamp[_timestamps.Count];
+ _timestamps.CopyTo(returnTimestamps);
+ return returnTimestamps;
+ }
+ }
+ }
+}