From 4038e63de14bf12c0cfbe885e2cac44577fe8a6a Mon Sep 17 00:00:00 2001 From: emmauss Date: Tue, 6 Mar 2018 22:18:49 +0200 Subject: [PATCH] Implement basic performance statistics (#53) * implement basic frame time stats * added game frame time * made performancestatictics class non-static * report average framerate instead of current framerate --- Ryujinx.Core/Logging.cs | 2 - Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs | 2 + Ryujinx.Core/PerformanceStatistics.cs | 87 +++++++++++++++++++++ Ryujinx.Core/Switch.cs | 7 +- Ryujinx/Ui/GLScreen.cs | 7 +- 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 Ryujinx.Core/PerformanceStatistics.cs diff --git a/Ryujinx.Core/Logging.cs b/Ryujinx.Core/Logging.cs index b14f26653..d544a5d64 100644 --- a/Ryujinx.Core/Logging.cs +++ b/Ryujinx.Core/Logging.cs @@ -22,8 +22,6 @@ namespace Ryujinx.Core static Logging() { - ExecutionTime.Start(); - if (File.Exists(LogFileName)) File.Delete(LogFileName); } diff --git a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs index 4b5f9819a..720dd44f9 100644 --- a/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs +++ b/Ryujinx.Core/OsHle/Services/Vi/NvFlinger.cs @@ -154,6 +154,8 @@ namespace Ryujinx.Core.OsHle.IpcServices.Android private long GbpQueueBuffer(ServiceCtx Context, BinaryReader ParcelReader) { + Context.Ns.Statistics.RecordGameFrameTime(); + //TODO: Errors. int Slot = ParcelReader.ReadInt32(); int Unknown4 = ParcelReader.ReadInt32(); diff --git a/Ryujinx.Core/PerformanceStatistics.cs b/Ryujinx.Core/PerformanceStatistics.cs new file mode 100644 index 000000000..3740daa58 --- /dev/null +++ b/Ryujinx.Core/PerformanceStatistics.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Timers; + +namespace Ryujinx.Core +{ + public class PerformanceStatistics + { + Stopwatch ExecutionTime = new Stopwatch(); + Timer ResetTimer = new Timer(1000); + + long CurrentGameFrameEnded; + long CurrentSystemFrameEnded; + long CurrentSystemFrameStart; + long LastGameFrameEnded; + long LastSystemFrameEnded; + + double AccumulatedGameFrameTime; + double AccumulatedSystemFrameTime; + double CurrentGameFrameTime; + double CurrentSystemFrameTime; + double PreviousGameFrameTime; + double PreviousSystemFrameTime; + public double GameFrameRate { get; private set; } + public double SystemFrameRate { get; private set; } + public long SystemFramesRendered; + public long GameFramesRendered; + public long ElapsedMilliseconds => ExecutionTime.ElapsedMilliseconds; + public long ElapsedMicroseconds => (long) + (((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000); + public long ElapsedNanoseconds => (long) + (((double)ExecutionTime.ElapsedTicks / Stopwatch.Frequency) * 1000000000); + + public PerformanceStatistics() + { + ExecutionTime.Start(); + ResetTimer.Elapsed += ResetTimerElapsed; + ResetTimer.AutoReset = true; + ResetTimer.Start(); + } + + private void ResetTimerElapsed(object sender, ElapsedEventArgs e) + { + ResetStatistics(); + } + + public void StartSystemFrame() + { + PreviousSystemFrameTime = CurrentSystemFrameTime; + LastSystemFrameEnded = CurrentSystemFrameEnded; + CurrentSystemFrameStart = ElapsedMicroseconds; + } + + public void EndSystemFrame() + { + CurrentSystemFrameEnded = ElapsedMicroseconds; + CurrentSystemFrameTime = CurrentSystemFrameEnded - CurrentSystemFrameStart; + AccumulatedSystemFrameTime += CurrentSystemFrameTime; + SystemFramesRendered++; + } + + public void RecordGameFrameTime() + { + CurrentGameFrameEnded = ElapsedMicroseconds; + CurrentGameFrameTime = CurrentGameFrameEnded - LastGameFrameEnded; + PreviousGameFrameTime = CurrentGameFrameTime; + LastGameFrameEnded = CurrentGameFrameEnded; + AccumulatedGameFrameTime += CurrentGameFrameTime; + GameFramesRendered++; + } + + public void ResetStatistics() + { + GameFrameRate = 1000 / ((AccumulatedGameFrameTime / GameFramesRendered) / 1000); + GameFrameRate = double.IsNaN(GameFrameRate) ? 0 : GameFrameRate; + SystemFrameRate = 1000 / ((AccumulatedSystemFrameTime / SystemFramesRendered) / 1000); + SystemFrameRate = double.IsNaN(SystemFrameRate) ? 0 : SystemFrameRate; + + GameFramesRendered = 0; + SystemFramesRendered = 0; + AccumulatedGameFrameTime = 0; + AccumulatedSystemFrameTime = 0; + } + } +} diff --git a/Ryujinx.Core/Switch.cs b/Ryujinx.Core/Switch.cs index 3f7b1e2b8..1acd87f01 100644 --- a/Ryujinx.Core/Switch.cs +++ b/Ryujinx.Core/Switch.cs @@ -17,8 +17,9 @@ namespace Ryujinx.Core internal Horizon Os { get; private set; } internal VirtualFs VFs { get; private set; } - public Hid Hid { get; private set; } - public SetSys Settings { get; private set; } + public Hid Hid { get; private set; } + public SetSys Settings { get; private set; } + public PerformanceStatistics Statistics { get; private set; } public event EventHandler Finish; @@ -32,6 +33,8 @@ namespace Ryujinx.Core Hid = new Hid(Ram); + Statistics = new PerformanceStatistics(); + Os = new Horizon(this); Os.HidSharedMem.MemoryMapped += Hid.ShMemMap; diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index 4c7cee467..b0dca81b7 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -166,9 +166,12 @@ namespace Ryujinx protected override void OnRenderFrame(FrameEventArgs e) { + Ns.Statistics.StartSystemFrame(); + GL.Viewport(0, 0, Width, Height); - Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {1f / e.Time:0})"; + Title = $"Ryujinx Screen - (Vsync: {VSync} - FPS: {Ns.Statistics.SystemFrameRate:0} - Guest FPS: " + + $"{Ns.Statistics.GameFrameRate:0})"; GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); @@ -176,6 +179,8 @@ namespace Ryujinx Renderer.Render(); SwapBuffers(); + + Ns.Statistics.EndSystemFrame(); } protected override void OnResize(EventArgs e)