From 8824a17f32f23d782f1a54af4f6f21296e95330c Mon Sep 17 00:00:00 2001
From: N00MKRAD <61149547+n00mkrad@users.noreply.github.com>
Date: Thu, 26 Sep 2024 18:51:07 +0200
Subject: [PATCH] Optimize interpolation progress display, use rolling avg. for
fps
---
CodeLegacy/Flowframes.csproj | 1 +
CodeLegacy/Os/AiProcess.cs | 4 +-
CodeLegacy/Ui/InterpolationProgress.cs | 84 ++++++++++++--------------
CodeLegacy/Utilities/RollingAverage.cs | 69 +++++++++++++++++++++
4 files changed, 112 insertions(+), 46 deletions(-)
create mode 100644 CodeLegacy/Utilities/RollingAverage.cs
diff --git a/CodeLegacy/Flowframes.csproj b/CodeLegacy/Flowframes.csproj
index 9e14d44..4d4baf6 100644
--- a/CodeLegacy/Flowframes.csproj
+++ b/CodeLegacy/Flowframes.csproj
@@ -517,6 +517,7 @@
+
Form1.cs
Designer
diff --git a/CodeLegacy/Os/AiProcess.cs b/CodeLegacy/Os/AiProcess.cs
index d7ddf22..38926b6 100644
--- a/CodeLegacy/Os/AiProcess.cs
+++ b/CodeLegacy/Os/AiProcess.cs
@@ -104,7 +104,7 @@ namespace Flowframes.Os
if (!Interpolate.currentSettings.ai.Piped)
InterpolationProgress.UpdateInterpProgress(interpFramesCount, InterpolationProgress.targetFrames);
- string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Peak Output FPS: {InterpolationProgress.peakFpsOut.ToString("0.00")}";
+ string logStr = $"Done running {aiName} - Interpolation took {FormatUtils.Time(processTime.Elapsed)}. Output FPS: {InterpolationProgress.LastFps.ToString("0.0")}";
if (Interpolate.currentlyUsingAutoEnc && AutoEncode.HasWorkToDo())
{
@@ -113,7 +113,7 @@ namespace Flowframes.Os
}
if (Interpolate.currentSettings.outSettings.Format != Enums.Output.Format.Realtime)
- Logger.Log(logStr);
+ Logger.Log(logStr, replaceLastLine: Logger.LastUiLine.Contains("FPS"));
processTime.Stop();
diff --git a/CodeLegacy/Ui/InterpolationProgress.cs b/CodeLegacy/Ui/InterpolationProgress.cs
index 1d6b8f6..d09876b 100644
--- a/CodeLegacy/Ui/InterpolationProgress.cs
+++ b/CodeLegacy/Ui/InterpolationProgress.cs
@@ -33,7 +33,9 @@ namespace Flowframes.Ui
progCheckRunning = true;
deletedFramesCount = 0;
lastFrame = 0;
- peakFpsOut = 0f;
+ LastFps = 0f;
+ _framesAtTime = null;
+ _fpsRollAvg.Reset();
Program.mainForm.SetProgress(0);
}
@@ -125,9 +127,9 @@ namespace Flowframes.Ui
}
public static int interpolatedInputFramesCount;
- public static float peakFpsOut;
-
- public static int previewUpdateRateMs = 200;
+ public static float LastFps;
+ private static Tuple _framesAtTime = null;
+ private static Utilities.RollingAverage _fpsRollAvg = new Utilities.RollingAverage(10);
public static void UpdateInterpProgress(int frames, int target, string latestFramePath = "")
{
@@ -136,43 +138,48 @@ namespace Flowframes.Ui
//ResumeUtils.Save();
target = (target / Interpolate.InterpProgressMultiplier).RoundToInt();
frames = frames.Clamp(0, target);
- int percent = (int)Math.Round(((float)frames / target) * 100f);
+
+ if (_framesAtTime == null)
+ {
+ _framesAtTime = new Tuple(frames, DateTime.Now);
+ }
+
+ if (frames > _framesAtTime.Item1 && frames > 0)
+ {
+ float fpsCurrent = (frames - _framesAtTime.Item1) / (float)(DateTime.Now - _framesAtTime.Item2).TotalSeconds;
+ _fpsRollAvg.AddDataPoint(fpsCurrent);
+ _framesAtTime = new Tuple(frames, DateTime.Now);
+ }
+
+ int percent = (((float)frames / target) * 100f).RoundToInt();
Program.mainForm.SetProgress(percent);
- float generousTime = ((AiProcess.processTime.ElapsedMilliseconds - AiProcess.lastStartupTimeMs) / 1000f);
- float fps = ((float)frames / generousTime).Clamp(0, 9999);
- string fpsIn = (fps / currentFactor).ToString("0.00");
- string fpsOut = fps.ToString("0.00");
+ float fps = _fpsRollAvg.CurrentSize > 2 ? (float)_fpsRollAvg.Average : 0f;
+ string fpsIn = (fps / currentFactor).ToString("0.0");
+ string fpsOut = fps.ToString("0.0");
+ LastFps = fps;
- if (fps > peakFpsOut)
- peakFpsOut = fps;
+ float eta = fps == 0f ? 0f : (target - frames) * (1f / fps); // ETA = Remaining frames * seconds per frame. Set to 0 if FPS is 0 to avoid div. by zero
+ string etaStr = eta > 3f ? $" - ETA: {FormatUtils.Time(TimeSpan.FromSeconds(eta), false)}" : "";
+ string timeStr = AiProcess.processTime.ElapsedMilliseconds > 0 ? $" - Time: {FormatUtils.Time(AiProcess.processTime.Elapsed)}" : "";
- float secondsPerFrame = generousTime / (float)frames;
- int framesLeft = target - frames;
- float eta = framesLeft * secondsPerFrame;
- string etaStr = FormatUtils.Time(new TimeSpan(0, 0, eta.RoundToInt()), false);
+ bool replaceLine = Logger.LastUiLine.MatchesWildcard("Interpolated*/* Frames *");
- bool replaceLine = Regex.Split(Logger.textbox.Text, "\r\n|\r|\n").Last().Contains("Average Speed: ");
-
- string logStr = $"Interpolated {frames}/{target} Frames ({percent}%) - Average Speed: {fpsIn} FPS In / {fpsOut} FPS Out - ";
- logStr += $"Time: {FormatUtils.Time(AiProcess.processTime.Elapsed)} - ETA: {etaStr}";
+ string logStr = $"Interpolated {frames}/{target} Frames ({percent}%) - Speed: {fpsIn} FPS In / {fpsOut} FPS Out{timeStr}{etaStr}";
if (AutoEncode.busy) logStr += " - Encoding...";
Logger.Log(logStr, false, replaceLine);
- try
- {
- if (latestFramePath.IsNotEmpty() && frames > currentFactor)
- {
- if (bigPreviewForm == null && (preview == null || !preview.Visible) /* ||Program.mainForm.WindowState != FormWindowState.Minimized */ /* || !Program.mainForm.IsInFocus()*/) return; // Skip if the preview is not visible or the form is not in focus
- if (timeSinceLastPreviewUpdate.IsRunning && timeSinceLastPreviewUpdate.ElapsedMilliseconds < previewUpdateRateMs) return;
- Image img = IoUtils.GetImage(latestFramePath, false, false);
- SetPreviewImg(img);
- }
- }
- catch (Exception e)
- {
- //Logger.Log("Error updating preview: " + e.Message, true);
- }
+ // try
+ // {
+ // if (latestFramePath.IsNotEmpty() && frames > currentFactor)
+ // {
+ // if (bigPreviewForm == null && (preview == null || !preview.Visible) /* ||Program.mainForm.WindowState != FormWindowState.Minimized */ /* || !Program.mainForm.IsInFocus()*/) return; // Skip if the preview is not visible or the form is not in focus
+ // }
+ // }
+ // catch (Exception e)
+ // {
+ // //Logger.Log("Error updating preview: " + e.Message, true);
+ // }
}
public static async Task DeleteInterpolatedInputFrames()
@@ -193,16 +200,5 @@ namespace Flowframes.Ui
}
public static Stopwatch timeSinceLastPreviewUpdate = new Stopwatch();
-
- public static void SetPreviewImg(Image img)
- {
- if (img == null || preview == null)
- return;
-
- timeSinceLastPreviewUpdate.Restart();
-
- preview.Image = img;
- bigPreviewForm?.SetImage(img);
- }
}
}
diff --git a/CodeLegacy/Utilities/RollingAverage.cs b/CodeLegacy/Utilities/RollingAverage.cs
new file mode 100644
index 0000000..b223525
--- /dev/null
+++ b/CodeLegacy/Utilities/RollingAverage.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Flowframes.Utilities
+{
+ public class RollingAverage where T : struct
+ {
+ public int CurrentSize { get => _values.Count; }
+ public double Average { get => GetAverage(); }
+
+ private Queue _values;
+ public Queue Queue { get => _values; }
+ private int _size;
+
+ public RollingAverage(int size)
+ {
+ _values = new Queue(size);
+ _size = size;
+ }
+
+ public void AddDataPoint(T dataPoint)
+ {
+ if (_values.Count >= _size)
+ {
+ _values.Dequeue();
+ }
+
+ _values.Enqueue(dataPoint);
+ }
+
+ public double GetAverage()
+ {
+ // Convert the values to double before averaging, this is necessary because Average() does not work directly on generic types
+ if(_values == null || _values.Count == 0)
+ {
+ return 0;
+ }
+
+ return _values.Select(val => Convert.ToDouble(val)).Average();
+ }
+
+ public double GetAverage(int lastXSamples)
+ {
+ if (lastXSamples <= 0)
+ {
+ lastXSamples = 1;
+ }
+ else if (lastXSamples > _values.Count)
+ {
+ lastXSamples = _values.Count;
+ }
+
+ // Take the last X samples and calculate the average
+ return _values.Skip(Math.Max(0, _values.Count - lastXSamples)).Select(val => Convert.ToDouble(val)).Average();
+ }
+
+ public double GetAverage(float percentile)
+ {
+ int lastXSamples = (int)Math.Ceiling(_size * percentile);
+ return GetAverage(lastXSamples);
+ }
+
+ public void Reset()
+ {
+ _values.Clear();
+ }
+ }
+}