From 5f3a9eade8b57355166419e36654fdbb0b0f3e9e Mon Sep 17 00:00:00 2001 From: Andy Adshead Date: Sat, 2 Feb 2019 03:21:35 +0000 Subject: [PATCH 1/4] Support for multiple profiling levels --- Ryujinx.Profiler/Profile.cs | 4 ++++ Ryujinx.Profiler/ProfileConfig.cs | 2 ++ Ryujinx.Profiler/Settings.cs | 1 + Ryujinx/Config.cs | 1 + Ryujinx/Ryujinx.conf | 3 +++ 5 files changed, 11 insertions(+) diff --git a/Ryujinx.Profiler/Profile.cs b/Ryujinx.Profiler/Profile.cs index a6127fe5d1..8869865e51 100644 --- a/Ryujinx.Profiler/Profile.cs +++ b/Ryujinx.Profiler/Profile.cs @@ -66,6 +66,8 @@ namespace Ryujinx.Profiler { if (!ProfilingEnabled()) return; + if (config.Level > _settings.MaxLevel) + return; _profileInstance.BeginProfile(config); } @@ -74,6 +76,8 @@ namespace Ryujinx.Profiler { if (!ProfilingEnabled()) return; + if (config.Level > _settings.MaxLevel) + return; _profileInstance.EndProfile(config); } diff --git a/Ryujinx.Profiler/ProfileConfig.cs b/Ryujinx.Profiler/ProfileConfig.cs index 44798e95be..8133ac60c8 100644 --- a/Ryujinx.Profiler/ProfileConfig.cs +++ b/Ryujinx.Profiler/ProfileConfig.cs @@ -10,6 +10,8 @@ namespace Ryujinx.Profiler public string SessionGroup; public string SessionItem; + public int Level; + // Private cached variables private string _cachedTag; private string _cachedSession; diff --git a/Ryujinx.Profiler/Settings.cs b/Ryujinx.Profiler/Settings.cs index f74a3cda2d..a3c677d81a 100644 --- a/Ryujinx.Profiler/Settings.cs +++ b/Ryujinx.Profiler/Settings.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Profiler public bool FileDumpEnabled { get; set; } = false; public string DumpLocation { get; set; } = ""; public float UpdateRate { get; set; } = 0.1f; + public int MaxLevel { get; set; } = 0; // 19531225 = 5 seconds in ticks public long History { get; set; } = 19531225; diff --git a/Ryujinx/Config.cs b/Ryujinx/Config.cs index da6b934614..fdff2e8aa2 100644 --- a/Ryujinx/Config.cs +++ b/Ryujinx/Config.cs @@ -75,6 +75,7 @@ namespace Ryujinx DumpLocation = profilePath, UpdateRate = (float)((updateRateHz <= 0) ? -1 : 1.0f / updateRateHz), History = (long)(Convert.ToDouble(parser.Value("Profiling_History")) * PerformanceCounter.TicksPerSecond), + MaxLevel = Convert.ToInt32(parser.Value("Profiling_Max_Level")), }); SystemLanguage SetLanguage = Enum.Parse(parser.Value("System_Language")); diff --git a/Ryujinx/Ryujinx.conf b/Ryujinx/Ryujinx.conf index 2f1436bf18..e3c854cc80 100644 --- a/Ryujinx/Ryujinx.conf +++ b/Ryujinx/Ryujinx.conf @@ -34,6 +34,9 @@ Profiling_Update_Rate = 4 #Set how long to keep profiling data in seconds, reduce if profiling is taking too much RAM Profiling_History = 5 +#Set the maximum profiling level. Higher values may cause a heavy load on your system but will allow you to profile in more detail. +Profiling_Max_Level = 0 + #System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b #Change System Language System_Language = AmericanEnglish From 0fe8238d1623544e3ca99d9b2db6a12488861898 Mon Sep 17 00:00:00 2001 From: Andy Adshead Date: Sat, 2 Feb 2019 03:22:49 +0000 Subject: [PATCH 2/4] Sometimes it would have to wait a long time for lock to clear so moved it to a tryenter and skip if already locked --- Ryujinx.Profiler/InternalProfile.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Ryujinx.Profiler/InternalProfile.cs b/Ryujinx.Profiler/InternalProfile.cs index 75f9581e54..1dcc4ed462 100644 --- a/Ryujinx.Profiler/InternalProfile.cs +++ b/Ryujinx.Profiler/InternalProfile.cs @@ -150,10 +150,11 @@ namespace Ryujinx.Profiler { _preserve = PerformanceCounter.ElapsedTicks; - // Make sure to clear queue - lock (_timerQueueClearLock) + // Skip clearing queue if already clearing + if (Monitor.TryEnter(_timerQueueClearLock)) { ClearTimerQueue(); + Monitor.Exit(_timerQueueClearLock); } return Timers; From aef7582888d32de469ec230d345c6c2a5374ea48 Mon Sep 17 00:00:00 2001 From: Andy Adshead Date: Sat, 2 Feb 2019 03:23:43 +0000 Subject: [PATCH 3/4] Dumb bug regarding clearing of timestamps. Start is already removed so no need to add it to the start --- Ryujinx.Profiler/TimingInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ryujinx.Profiler/TimingInfo.cs b/Ryujinx.Profiler/TimingInfo.cs index 23d6a5173f..2dc3072340 100644 --- a/Ryujinx.Profiler/TimingInfo.cs +++ b/Ryujinx.Profiler/TimingInfo.cs @@ -157,7 +157,7 @@ namespace Ryujinx.Profiler if (toRemove > 0) { - _timestamps.RemoveRange(toPreserveStart + toPreserveLen, toRemove); + _timestamps.RemoveRange(toPreserveLen, toRemove); } } } From 5a3cac991c6e9145bd2c7ad1d62a17a25e21f0e2 Mon Sep 17 00:00:00 2001 From: Andy Adshead Date: Sat, 2 Feb 2019 03:30:38 +0000 Subject: [PATCH 4/4] Optimisations in drawing routine: Only calculate bar top and bottom once per bar rather than once per timestamp Pre-calculate the right side of the graph as it was being calculated multiple times per bar Skip rendering timestamps that occupy the same pixel space now uses the raw timestamp to decide. While technically not as accurate it's much easier as the right side of the bar doesn't have to be calculated for a skipped timestamp --- Ryujinx.Profiler/UI/ProfileWindowGraph.cs | 71 +++++++++++------------ 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/Ryujinx.Profiler/UI/ProfileWindowGraph.cs b/Ryujinx.Profiler/UI/ProfileWindowGraph.cs index 19d676a597..137d09d5b9 100644 --- a/Ryujinx.Profiler/UI/ProfileWindowGraph.cs +++ b/Ryujinx.Profiler/UI/ProfileWindowGraph.cs @@ -22,26 +22,30 @@ namespace Ryujinx.Profiler.UI int left, right; float top, bottom; - int verticalIndex = 0; - float barHeight = (LineHeight - LinePadding); - long history = Profile.HistoryLength; - long timeWidthTicks = (long)(history / (double)_graphZoom); - long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond); + int verticalIndex = 0; + float graphRight = xOffset + width; + float barHeight = (LineHeight - LinePadding); + long history = Profile.HistoryLength; + double timeWidthTicks = history / (double)_graphZoom; + long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond); + long ticksPerPixel = (long)(timeWidthTicks / width); // Reset start point if out of bounds if (timeWidthTicks + graphPositionTicks > history) { - graphPositionTicks = history - timeWidthTicks; + graphPositionTicks = history - (long)timeWidthTicks; _graphPosition = (float)graphPositionTicks / PerformanceCounter.TicksPerMillisecond; } + graphPositionTicks = _captureTime - graphPositionTicks; + // Draw timing flags GL.Enable(EnableCap.ScissorTest); GL.Color3(0.25f, 0.25f, 0.25f); GL.Begin(PrimitiveType.Lines); foreach (TimingFlag timingFlag in _timingFlags) { - int x = (int)(xOffset + width - ((float)(_captureTime - (timingFlag.Timestamp + graphPositionTicks)) / timeWidthTicks) * width); + int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width); GL.Vertex2(x, 0); GL.Vertex2(x, Height); } @@ -51,30 +55,30 @@ namespace Ryujinx.Profiler.UI GL.Begin(PrimitiveType.Triangles); foreach (var entry in _sortedProfileData) { - int furthest = 0; + long furthest = 0; + + bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); + top = bottom + barHeight; + + // Skip rendering out of bounds bars + if (top < 0 || bottom > Height) + continue; + GL.Color3(Color.Green); foreach (Timestamp timestamp in entry.Value.GetAllTimestamps()) { - right = (int)(xOffset + width - ((float)(_captureTime - (timestamp.EndTime + graphPositionTicks)) / timeWidthTicks) * width); - // Skip drawing multiple timestamps on same pixel - if (right <= furthest) + if (timestamp.EndTime < furthest) continue; + furthest = timestamp.EndTime + ticksPerPixel; - left = (int)(xOffset + width - ((float)(_captureTime - (timestamp.BeginTime + graphPositionTicks)) / timeWidthTicks) * width); - bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - top = bottom + barHeight; + left = (int)(graphRight - ((graphPositionTicks - timestamp.BeginTime) / timeWidthTicks) * width); + right = (int)(graphRight - ((graphPositionTicks - timestamp.EndTime) / timeWidthTicks) * width); // Make sure width is at least 1px right = Math.Max(left + 1, right); - furthest = right; - - // Skip rendering out of bounds bars - if (top < 0 || bottom > Height) - continue; - GL.Vertex2(left, bottom); GL.Vertex2(left, top); GL.Vertex2(right, top); @@ -84,30 +88,23 @@ namespace Ryujinx.Profiler.UI GL.Vertex2(left, bottom); } - GL.Color3(Color.Red); // Currently capturing timestamp + GL.Color3(Color.Red); long entryBegin = entry.Value.BeginTime; if (entryBegin != -1) { - left = (int)(xOffset + width + _graphPosition - (((float)_captureTime - entryBegin) / timeWidthTicks) * width); - bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); - top = bottom + barHeight; - right = (int)(xOffset + width); + left = (int)(graphRight - ((graphPositionTicks - entryBegin) / timeWidthTicks) * width); // Make sure width is at least 1px - left = Math.Min(left - 1, right); + left = Math.Min(left - 1, (int)graphRight); - // Skip rendering out of bounds bars - if (top < 0 || bottom > Height) - continue; + GL.Vertex2(left, bottom); + GL.Vertex2(left, top); + GL.Vertex2(graphRight, top); - GL.Vertex2(left, bottom); - GL.Vertex2(left, top); - GL.Vertex2(right, top); - - GL.Vertex2(right, top); - GL.Vertex2(right, bottom); - GL.Vertex2(left, bottom); + GL.Vertex2(graphRight, top); + GL.Vertex2(graphRight, bottom); + GL.Vertex2(left, bottom); } verticalIndex++; @@ -120,7 +117,7 @@ namespace Ryujinx.Profiler.UI // Dummy draw for measure float labelWidth = _fontService.DrawText(label, 0, 0, LineHeight, false); - _fontService.DrawText(label, xOffset + width - labelWidth - LinePadding, FilterHeight + LinePadding, LineHeight); + _fontService.DrawText(label, graphRight - labelWidth - LinePadding, FilterHeight + LinePadding, LineHeight); _fontService.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", xOffset + LinePadding, FilterHeight + LinePadding, LineHeight); }