diff --git a/Ryujinx.Profiler/InternalProfile.cs b/Ryujinx.Profiler/InternalProfile.cs index 599cd8f861..df3f5a3c84 100644 --- a/Ryujinx.Profiler/InternalProfile.cs +++ b/Ryujinx.Profiler/InternalProfile.cs @@ -34,6 +34,7 @@ namespace Ryujinx.Profiler private TimingFlag[] _timingFlags; private long[] _timingFlagAverages; private long[] _timingFlagLast; + private long[] _timingFlagLastDelta; private int _timingFlagCount; private int _timingFlagIndex; @@ -43,14 +44,15 @@ namespace Ryujinx.Profiler public InternalProfile(long history, int maxFlags) { - _maxFlags = maxFlags; - Timers = new Dictionary(); - _timingFlags = new TimingFlag[_maxFlags]; - _timingFlagAverages = new long[(int)TimingFlagType.Count]; - _timingFlagLast = new long[(int)TimingFlagType.Count]; - _timerQueue = new ConcurrentQueue(); - _history = history; - _cleanupRunning = true; + _maxFlags = maxFlags; + Timers = new Dictionary(); + _timingFlags = new TimingFlag[_maxFlags]; + _timingFlagAverages = new long[(int)TimingFlagType.Count]; + _timingFlagLast = new long[(int)TimingFlagType.Count]; + _timingFlagLastDelta = new long[(int)TimingFlagType.Count]; + _timerQueue = new ConcurrentQueue(); + _history = history; + _cleanupRunning = true; // Create cleanup thread. _cleanupThread = new Thread(CleanupLoop); @@ -127,28 +129,24 @@ namespace Ryujinx.Profiler Timestamp = PerformanceCounter.ElapsedTicks }; - if (++_timingFlagIndex >= _maxFlags) - { - _timingFlagIndex = 0; - } - _timingFlagCount = Math.Max(_timingFlagCount + 1, _maxFlags); // Work out average - if (_timingFlagLast[flagId] == 0) + if (_timingFlagLast[flagId] != 0) { - _timingFlagAverages[flagId] = _timingFlags[_timingFlagIndex].Timestamp; - } - else - { - _timingFlagAverages[flagId] = (_timingFlags[_timingFlagIndex].Timestamp + _timingFlagLast[flagId]) / 2; + _timingFlagLastDelta[flagId] = _timingFlags[_timingFlagIndex].Timestamp - _timingFlagLast[flagId]; + _timingFlagAverages[flagId] = (_timingFlagAverages[flagId] == 0) ? _timingFlagLastDelta[flagId] : + (_timingFlagLastDelta[flagId] + _timingFlagAverages[flagId]) >> 1; } + _timingFlagLast[flagId] = _timingFlags[_timingFlagIndex].Timestamp; // Notify subscribers _timingFlagCallback?.Invoke(_timingFlags[_timingFlagIndex]); - // Set last time for average - _timingFlagLast[flagId] = _timingFlags[_timingFlagIndex].Timestamp; + if (++_timingFlagIndex >= _maxFlags) + { + _timingFlagIndex = 0; + } } public void BeginProfile(ProfileConfig config) @@ -209,6 +207,11 @@ namespace Ryujinx.Profiler return outFlags; } + public (long[], long[]) GetTimingAveragesAndLast() + { + return (_timingFlagAverages, _timingFlagLastDelta); + } + public void RegisterFlagReciever(Action reciever) { _timingFlagCallback = reciever; diff --git a/Ryujinx.Profiler/Profile.cs b/Ryujinx.Profiler/Profile.cs index 48237e2319..9b51076a31 100644 --- a/Ryujinx.Profiler/Profile.cs +++ b/Ryujinx.Profiler/Profile.cs @@ -128,5 +128,16 @@ namespace Ryujinx.Profiler return new TimingFlag[0]; #endif } + + public static (long[], long[]) GetTimingAveragesAndLast() + { + #if USE_PROFILING + if (!ProfilingEnabled()) + return (new long[0], new long[0]); + return _profileInstance.GetTimingAveragesAndLast(); + #else + return (new long[0], new long[0]); + #endif + } } } diff --git a/Ryujinx.Profiler/UI/ProfileWindow.cs b/Ryujinx.Profiler/UI/ProfileWindow.cs index ae7f5ffa5e..0b40e3eded 100644 --- a/Ryujinx.Profiler/UI/ProfileWindow.cs +++ b/Ryujinx.Profiler/UI/ProfileWindow.cs @@ -63,6 +63,10 @@ namespace Ryujinx.Profiler.UI private List> _unsortedProfileData; private IComparer> _sortAction = new ProfileSorters.TagAscending(); + // Flag data + private long[] _timingFlagsAverages; + private long[] _timingFlagsLast; + // Filtering private string _filterText = ""; private bool _regexEnabled = false; @@ -246,6 +250,7 @@ namespace Ryujinx.Profiler.UI Dictionary data = Profile.GetProfilingData(); if (data.Count > 0) { + (_timingFlagsAverages, _timingFlagsLast) = Profile.GetTimingAveragesAndLast(); _unsortedProfileData = data.ToList(); _profileUpdated = true; } @@ -527,13 +532,11 @@ namespace Ryujinx.Profiler.UI { float y = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex++); - float instant = (float)entry.Value.Instant / PerformanceCounter.TicksPerMillisecond; - _fontService.DrawText($"{((instant < 1) ? $"{instant * 1000:F3}us" : $"{instant:F3}ms")} ({entry.Value.InstantCount})", xOffset, y, LineHeight); + _fontService.DrawText($"{GetTimeString(entry.Value.Instant)} ({entry.Value.InstantCount})", xOffset, y, LineHeight); - float average = (float)entry.Value.AverageTime / PerformanceCounter.TicksPerMillisecond; - _fontService.DrawText((average < 1) ? $"{average * 1000:F3}us" : $"{average:F3}ms", 150 + xOffset, y, LineHeight); + _fontService.DrawText(GetTimeString(entry.Value.AverageTime), 150 + xOffset, y, LineHeight); - _fontService.DrawText($"{(float)entry.Value.TotalTime / PerformanceCounter.TicksPerMillisecond:F3}", 260 + xOffset, y, LineHeight); + _fontService.DrawText(GetTimeString(entry.Value.TotalTime), 260 + xOffset, y, LineHeight); totalInstant += entry.Value.Instant; totalAverage += entry.Value.AverageTime; @@ -554,10 +557,19 @@ namespace Ryujinx.Profiler.UI _buttons[(int)ButtonIndex.TotalTitle].UpdateSize((int)(260 + xOffset), (int)yHeight, 0, Width, TitleFontHeight); // Totals - yHeight = FilterHeight + 2; - _fontService.DrawText($"{totalInstant / PerformanceCounter.TicksPerMillisecond:F3} ({totalCount})", xOffset, yHeight, TitleFontHeight); - _fontService.DrawText($"{totalAverage / PerformanceCounter.TicksPerMillisecond:F3}", 150 + xOffset, yHeight, TitleFontHeight); - _fontService.DrawText($"{totalTime / PerformanceCounter.TicksPerMillisecond:F3}", 260 + xOffset, yHeight, TitleFontHeight); + yHeight = FilterHeight + 3; + int textHeight = LineHeight - 2; + + float tempWidth = _fontService.DrawText($"Host {GetTimeString(_timingFlagsLast[(int)TimingFlagType.SystemFrame])} " + + $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.SystemFrame])})", 5, yHeight, textHeight); + + _fontService.DrawText($"Game {GetTimeString(_timingFlagsLast[(int)TimingFlagType.FrameSwap])} " + + $"({GetTimeString(_timingFlagsAverages[(int)TimingFlagType.FrameSwap])})", 15 + tempWidth, yHeight, textHeight); + + + _fontService.DrawText($"{GetTimeString(totalInstant)} ({totalCount})", xOffset, yHeight, textHeight); + _fontService.DrawText(GetTimeString(totalAverage), 150 + xOffset, yHeight, textHeight); + _fontService.DrawText(GetTimeString(totalTime), 260 + xOffset, yHeight, textHeight); #endregion } @@ -639,6 +651,12 @@ namespace Ryujinx.Profiler.UI } #endregion + private string GetTimeString(long timestamp) + { + float time = (float)timestamp / PerformanceCounter.TicksPerMillisecond; + return (time < 1) ? $"{time * 1000:F3}us" : $"{time:F3}ms"; + } + private void FilterBackspace() { if (_filterText.Length <= 1)