From 458ccde176628e97cb6fa37894e9acbf4642de26 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sat, 5 Sep 2026 21:21:29 -0400 Subject: [PATCH] [Feat] (Metrics, Config): make the boundary-counter summary cadence a knob, because the device harness never reaches the teardown dump - MOBILEGL_PIPE_STATS_PERIOD (default 120, clamped to [1, 1000000]) sets the frames per summary line; Init() latches it and a zero falls back to the default - the trace APK's replay never tears MobileGL down, so MOBILEGL_PIPE_STATS_FILE never fires on device and a fixture shorter than the period (create-indirect) reported nothing - PipeStatsTest pins the latch and the zero fallback --- MobileGL/Config.h | 5 +++++ MobileGL/ConfigLoader.cpp | 1 + MobileGL/MG_Test/Util/PipeStatsTest.cpp | 22 +++++++++++++++++++--- MobileGL/MG_Util/Metrics/PipeStats.cpp | 11 +++++++++-- MobileGL/MG_Util/Metrics/PipeStats.h | 5 ++++- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/MobileGL/Config.h b/MobileGL/Config.h index 3ceb3c9d..0c59110e 100644 --- a/MobileGL/Config.h +++ b/MobileGL/Config.h @@ -347,6 +347,11 @@ namespace MobileGL::MG_Config { // the server without shipping index bytes per draw. Over budget it degrades to // per-draw staging, counted separately in the stats. Uint32 PipeIndexMirrorMb = 64; + // MOBILEGL_PIPE_STATS_PERIOD: frames per boundary-counter summary line. 120 is the + // steady-state cadence; the device retrace harness never reaches the teardown dump + // and a trimmed fixture (create-indirect) is shorter than 120 frames, so a run that + // needs its numbers at all sets this low enough to land at least one window. + Uint32 PipeStatsPeriod = 120; // MOBILEGL_PIPE_STATS_FILE: where the boundary counters' teardown JSON dump goes. // Empty (the default) means no dump; the per-120-frame summary line still goes to // the log whenever PipeStats is on, so a device run needs no writable path. diff --git a/MobileGL/ConfigLoader.cpp b/MobileGL/ConfigLoader.cpp index a329008e..f4087c56 100644 --- a/MobileGL/ConfigLoader.cpp +++ b/MobileGL/ConfigLoader.cpp @@ -252,6 +252,7 @@ namespace MobileGL::MG_ConfigLoader { QueryEnvQuirkOverride("MOBILEGL_PIPE_LEGACY_MEMOS") != MG_Config::QuirkOverride::ForceOff; features.PipeTexelRetainMb = QueryEnvUint32("MOBILEGL_PIPE_TEXEL_RETAIN_MB", 0, 0, 4096); features.PipeIndexMirrorMb = QueryEnvUint32("MOBILEGL_PIPE_INDEX_MIRROR_MB", 64, 0, 4096); + features.PipeStatsPeriod = QueryEnvUint32("MOBILEGL_PIPE_STATS_PERIOD", 120, 1, 1000000); QueryEnvVariable("MOBILEGL_PIPE_STATS_FILE", features.PipeStatsFile, ""); } diff --git a/MobileGL/MG_Test/Util/PipeStatsTest.cpp b/MobileGL/MG_Test/Util/PipeStatsTest.cpp index 4d329ed7..9ccd4e45 100644 --- a/MobileGL/MG_Test/Util/PipeStatsTest.cpp +++ b/MobileGL/MG_Test/Util/PipeStatsTest.cpp @@ -12,6 +12,7 @@ #include +#include #include #include @@ -77,6 +78,21 @@ namespace { EXPECT_EQ(PS::FrameCount(), 1u); } + TEST_F(PipeStatsTest, InitLatchesTheSummaryPeriodFromTheConfigAndNeverKeepsZero) { + // The device retrace harness never reaches the teardown dump, so the summary + // cadence is the only way a short fixture yields numbers at all: it must follow + // MOBILEGL_PIPE_STATS_PERIOD, and a zero must fall back rather than divide. + const Uint32 saved = MobileGL::MG_Config::Features.PipeStatsPeriod; + MobileGL::MG_Config::Features.PipeStatsPeriod = 7; + PS::Init(); + EXPECT_EQ(PS::SummaryFramePeriod(), 7u); + MobileGL::MG_Config::Features.PipeStatsPeriod = 0; + PS::Init(); + EXPECT_EQ(PS::SummaryFramePeriod(), PS::kDefaultSummaryFramePeriod); + MobileGL::MG_Config::Features.PipeStatsPeriod = saved; + PS::Init(); + } + TEST_F(PipeStatsTest, GateHitsAndMissesAreSeparateCounters) { for (Uint32 i = 0; i < 5; ++i) { PS::CountGate(PS::Gate::MagmaPipelineMemo, /*hit=*/true); @@ -262,10 +278,10 @@ namespace { // A summary is emitted every kSummaryFramePeriod presents. The period is a constant the // smoke check depends on, so a change to it has to break a test. TEST_F(PipeStatsTest, SummaryPeriodIsOneHundredAndTwentyFrames) { - EXPECT_EQ(PS::kSummaryFramePeriod, 120u); - for (Uint64 i = 0; i < PS::kSummaryFramePeriod; ++i) { + EXPECT_EQ(PS::SummaryFramePeriod(), 120u); + for (Uint64 i = 0; i < PS::SummaryFramePeriod(); ++i) { PS::OnPresent(); } - EXPECT_EQ(PS::FrameCount(), PS::kSummaryFramePeriod); + EXPECT_EQ(PS::FrameCount(), PS::SummaryFramePeriod()); } } // namespace diff --git a/MobileGL/MG_Util/Metrics/PipeStats.cpp b/MobileGL/MG_Util/Metrics/PipeStats.cpp index 165e436c..8813b915 100644 --- a/MobileGL/MG_Util/Metrics/PipeStats.cpp +++ b/MobileGL/MG_Util/Metrics/PipeStats.cpp @@ -130,6 +130,8 @@ namespace MobileGL::MG_Util::PipeStats { Uint64 g_windowBaseFrames = 0; Bool g_shutdownDone = false; + // Frames per summary line, latched by Init() from MOBILEGL_PIPE_STATS_PERIOD. + Uint64 g_summaryPeriod = kDefaultSummaryFramePeriod; inline void Bump(Counter& counter, Uint64 amount) { counter.fetch_add(amount, std::memory_order_relaxed); } @@ -253,14 +255,19 @@ namespace MobileGL::MG_Util::PipeStats { ResetCounters(); g_shutdownDone = false; g_pipeStatsEnabled = MG_Config::Features.PipeStats; + g_summaryPeriod = MG_Config::Features.PipeStatsPeriod == 0 + ? kDefaultSummaryFramePeriod + : static_cast(MG_Config::Features.PipeStatsPeriod); if (g_pipeStatsEnabled) { MGLOG_I("MGPipe stats: counters ON (MOBILEGL_PIPE_STATS), summary every %llu frames%s%s", - static_cast(kSummaryFramePeriod), + static_cast(g_summaryPeriod), MG_Config::Features.PipeStatsFile.empty() ? "" : ", JSON dump to ", MG_Config::Features.PipeStatsFile.c_str()); } } + Uint64 SummaryFramePeriod() { return g_summaryPeriod; } + void Shutdown() { if (!g_pipeStatsEnabled || g_shutdownDone) { return; @@ -336,7 +343,7 @@ namespace MobileGL::MG_Util::PipeStats { #endif } const Uint64 frames = g_frameCount.fetch_add(1, std::memory_order_relaxed) + 1; - if (frames % kSummaryFramePeriod == 0) { + if (frames % g_summaryPeriod == 0) { EmitSummaryLine(); } } diff --git a/MobileGL/MG_Util/Metrics/PipeStats.h b/MobileGL/MG_Util/Metrics/PipeStats.h index 367a323e..0e8e74e4 100644 --- a/MobileGL/MG_Util/Metrics/PipeStats.h +++ b/MobileGL/MG_Util/Metrics/PipeStats.h @@ -129,7 +129,10 @@ namespace MobileGL::MG_Util::PipeStats { inline constexpr Uint32 kPayloadHistogramBuckets = 24; // Frames between two summary lines when MOBILEGL_PIPE_STATS=1. - inline constexpr Uint64 kSummaryFramePeriod = 120; + inline constexpr Uint64 kDefaultSummaryFramePeriod = 120; + // The period Init() latched from MOBILEGL_PIPE_STATS_PERIOD (kDefaultSummaryFramePeriod + // when unset); never 0. + Uint64 SummaryFramePeriod(); // The latch. Read directly by Enabled() so the off path is a global load and a // predicted branch - do not turn this into a function call.