From 10eaf402783467311cfc55ff7a79a443a1394ada Mon Sep 17 00:00:00 2001 From: Kurt Kartaltepe Date: Sun, 19 Dec 2021 20:34:19 -0800 Subject: [PATCH] hud: Modify histogram to use buckets and report p50/p90/p99 This makes the histogram option behave like a histogram instead of simply rendering the same data as frame_timing without the histogram option. This is mostly for reference and personal use as is and does not match some of the repo's coding standards. --- src/hud_elements.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/overlay.cpp | 12 ++++++++++++ src/overlay.h | 3 ++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index 6ba6f9733b..a795249046 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -537,9 +537,41 @@ void HudElements::frame_timing(){ double min_time = 0.0f; double max_time = 50.0f; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){ - ImGui::PlotHistogram(hash, get_time_stat, HUDElements.sw_stats, - ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, - NULL, min_time, max_time, + float *ft = HUDElements.sw_stats->frame_times; + size_t ft_size = ARRAY_SIZE(HUDElements.sw_stats->frame_times); + uint32_t tsmin=0, tsmax=0; + uint32_t p50=0, p90=0, p99=0; + // one frame latency between this and update_hud_info_with_frametime. + // That makes p99 only kick in after 100 frames. + uint32_t frame_count = std::min((size_t)HUDElements.sw_stats->n_frames, ARRAY_SIZE(HUDElements.sw_stats->frames_stats)); + uint32_t frames_seen = 0; + uint32_t height = 0; + for(uint32_t i = 0; i < ft_size; i++) { + frames_seen += ft[i]; + if(ft[i] > height) { height = ft[i]; } + if(tsmin == 0 && ft[i] > 0) { tsmin = i; } + if(i > tsmax && ft[i] > 0) { tsmax = i; } + if(p50 == 0 && frames_seen >= frame_count/2) { + p50 = i; + } + if(p90 == 0 && frames_seen >= frame_count - (frame_count/10)) { + p90 = i; + } + if(p99 == 0 && frames_seen >= frame_count - (frame_count/100)) { + p99 = i; + } + } + ImGui::PushFont(HUDElements.sw_stats->font1); + ImGui::TextColored(HUDElements.colors.text, "p50/p90/p99"); + ImGui::TextColored(HUDElements.colors.text, "%3d/%3d/%3d ms", p50, p90, p99); + // ImGui::TextColored(HUDElements.colors.text, "s:%d,c:%d,h:%d", frames_seen, frame_count, height); + ImGui::TextColored(HUDElements.colors.text, "min:%d,max:%d", tsmin, tsmax); + ImGui::PopFont(); + ImGui::TableNextRow(); ImGui::TableNextColumn(); + // Draw at least 16 buckets. + ImGui::PlotHistogram(hash, ft, + std::max(tsmax, 16u), tsmin, + NULL, 0, height, ImVec2(ImGui::GetContentRegionAvailWidth() * HUDElements.params->table_columns, 50)); } else { ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats, diff --git a/src/overlay.cpp b/src/overlay.cpp index 91ca33dc4d..22ff5641b0 100644 --- a/src/overlay.cpp +++ b/src/overlay.cpp @@ -170,6 +170,18 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, struct ove if (sw_stats.last_present_time) { sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] = frametime_ns; + uint32_t frametime_ms = frametime_ns/1000000; + if (frametime_ms < 1000) { + sw_stats.frame_times[frametime_ms] += 1.0; + } + // keep the histogram for the same window as the normal frame graph. + if (sw_stats.n_frames >= ARRAY_SIZE(sw_stats.frames_stats)) { + uint32_t fp_idx = (sw_stats.n_frames + 1) % ARRAY_SIZE(sw_stats.frames_stats); + uint32_t oldest_frametime_ms = sw_stats.frames_stats[fp_idx].stats[OVERLAY_PLOTS_frame_timing]/1000000; + if(oldest_frametime_ms < 1000) { + sw_stats.frame_times[oldest_frametime_ms] -= 1.0; + } + } } frametime = frametime_ns / 1000; diff --git a/src/overlay.h b/src/overlay.h index 18b839a27a..3192441180 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -51,6 +51,7 @@ struct swapchain_stats { double time_dividor; struct frame_stat stats_min, stats_max; struct frame_stat frames_stats[200]; + float frame_times[1000]; // histogram buckets. ImFont* font1 = nullptr; ImFont* font_text = nullptr; @@ -167,4 +168,4 @@ extern void process_control_socket(struct instance_data *instance_data); void render_mpris_metadata(overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing); #endif -#endif //MANGOHUD_OVERLAY_H \ No newline at end of file +#endif //MANGOHUD_OVERLAY_H