MangoHud icon indicating copy to clipboard operation
MangoHud copied to clipboard

Make sampling period of fps_metrics configurable

Open nodscher opened this issue 8 months ago • 15 comments

Hi, it would be nice if the sampling period of fps_metrics would be configurable, like the regular fps one is. I personally find the default way to high and would like to change it without compiling a custom version.

Having it based on ms like in the fps would be the nicest, but I think making size_t max_size in fps_metrics.h configurable would be enough

nodscher avatar Apr 23 '25 13:04 nodscher

So, std::vector<float> frametimes would store 10 (etc...) seconds worth of frametimes instead of 10.000 frames?

https://github.com/flightlessmango/MangoHud/blob/0c11540e68a8ddec9944faa2707f1ed669976a47/src/fps_metrics.h#L21-L23C9

17314642 avatar Apr 23 '25 15:04 17314642

I think it would be good enough if just the number of frames would be configurable (like 500 instead of 10.000 frames)

nodscher avatar Apr 23 '25 15:04 nodscher

Having it based on ms like in the fps would be the nicest

so this no longer applies?

17314642 avatar Apr 23 '25 15:04 17314642

If this is easy enough to implement it would be nice, but it would be fine without

nodscher avatar Apr 23 '25 15:04 nodscher

I don't see any problems implementing either of those approaches.

But storing some amount of seconds worth of frametimes is definitely better approach, because you have a constant amount of time by which you divide your frametimes.

If one user has 60fps, and other has 150fps, mangohud will show avg fps over 2.8 minutes for first user, while for other only over 1.1 minute (in case max_size=10000)

17314642 avatar Apr 23 '25 16:04 17314642

Ok sorry for wasting your time on those replies then. That sounds great

nodscher avatar Apr 23 '25 16:04 nodscher

You're not, I'm just trying to better understand what functionality you want.

17314642 avatar Apr 23 '25 16:04 17314642

We used to collect fps metrics over a set time frame, but that had issues, which is why I changed it. For example long frames hold more weight than other frames, so the calculations become less accurate

flightlessmango avatar Apr 23 '25 16:04 flightlessmango

So you're saying that I would be just returning the old method?

And adding configurable max_size is enough here?

17314642 avatar Apr 23 '25 17:04 17314642

The main problem here is misunderstanding what AVG metric does.

The point of AVG metric is to show average fps value over some time frame.

sum_of_fps_over_30sec / 30sec is mathematically correct here. But humans will think that number is wrong, even though it fulfills it's purpose.

IMO, people think that avg fps is some kind of game smoothess indicator, when it's not, so no need to butcher it up in code and still call it avg fps

Currently what mangohud calls avg fps is arithmetic mean of frame times or harmonic mean of fps

17314642 avatar Apr 23 '25 17:04 17314642

For example long frames hold more weight than other frames, so the calculations become less accurate

For that, median fps is needed, to not get affected by any outliers

17314642 avatar Apr 23 '25 17:04 17314642

I thought about it myself a little. Isn't that solvable by dynamically changing the max_size based on the fps (f/s*s=f)? That keeps all frames equally weight and gives seconds as an input.

instant change:

diff --git a/src/fps_metrics.h b/src/fps_metrics.h
index d755c91..3a32998 100644
--- a/src/fps_metrics.h
+++ b/src/fps_metrics.h
@@ -129,8 +129,9 @@ class fpsMetrics {
 
             // lock before modifying vector
             std::lock_guard<std::mutex> lock(mtx);
-
-            if (frametimes.size() >= max_size)
+            max_size = 1 * fps;
+            SPDLOG_INFO("FPS: {}, Max Size: {}, Frametime Size: {}", fps, max_size, frametimes.size());
+            while (frametimes.size() >= max_size)
                 frametimes.erase(frametimes.begin());
 
             frametimes.push_back(new_frametime);

ramp up/ ramp down

diff --git a/src/fps_metrics.h b/src/fps_metrics.h
index d755c91..ddd4ae5 100644
--- a/src/fps_metrics.h
+++ b/src/fps_metrics.h
@@ -129,10 +129,13 @@ class fpsMetrics {
 
             // lock before modifying vector
             std::lock_guard<std::mutex> lock(mtx);
-
-            if (frametimes.size() >= max_size)
+            max_size = 1 * fps;
+            SPDLOG_INFO("FPS: {}, Max Size: {}, Frametime Size: {}", fps, max_size, frametimes.size());
+            if (frametimes.size() >= max_size) {
                 frametimes.erase(frametimes.begin());
-
+                if (frametimes.size() >= max_size)
+                    frametimes.erase(frametimes.begin());
+            }
             frametimes.push_back(new_frametime);
         }
 

These would both be with a one second sampling period (I've never done anything in anything lower level than python, so I don't trust that code being proper and don't trust myself with making it configurable without making it a vibe coded mess )

nodscher avatar Apr 23 '25 19:04 nodscher

actually it would be way smarter to base it of the already calculated avg fps. But that goes beyond my C++ skills

nodscher avatar Apr 23 '25 19:04 nodscher

Isn't that solvable by dynamically changing the max_size based on the fps (f/s*s=f)?

f/s*s=f this line just states that f = f

did you mean max_size = sec * avg_fps?

17314642 avatar Apr 23 '25 19:04 17314642

Yes It's the same thing but with the units

nodscher avatar Apr 23 '25 19:04 nodscher