diff options
Diffstat (limited to 'Ryujinx.Profiler/TimingInfo.cs')
| -rw-r--r-- | Ryujinx.Profiler/TimingInfo.cs | 174 |
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; + } + } + } +} |
