mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 12:18:30 +09:00
[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
This commit is contained in:
@@ -347,6 +347,11 @@ namespace MobileGL::MG_Config {
|
|||||||
// the server without shipping index bytes per draw. Over budget it degrades to
|
// the server without shipping index bytes per draw. Over budget it degrades to
|
||||||
// per-draw staging, counted separately in the stats.
|
// per-draw staging, counted separately in the stats.
|
||||||
Uint32 PipeIndexMirrorMb = 64;
|
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.
|
// 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
|
// 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.
|
// the log whenever PipeStats is on, so a device run needs no writable path.
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ namespace MobileGL::MG_ConfigLoader {
|
|||||||
QueryEnvQuirkOverride("MOBILEGL_PIPE_LEGACY_MEMOS") != MG_Config::QuirkOverride::ForceOff;
|
QueryEnvQuirkOverride("MOBILEGL_PIPE_LEGACY_MEMOS") != MG_Config::QuirkOverride::ForceOff;
|
||||||
features.PipeTexelRetainMb = QueryEnvUint32("MOBILEGL_PIPE_TEXEL_RETAIN_MB", 0, 0, 4096);
|
features.PipeTexelRetainMb = QueryEnvUint32("MOBILEGL_PIPE_TEXEL_RETAIN_MB", 0, 0, 4096);
|
||||||
features.PipeIndexMirrorMb = QueryEnvUint32("MOBILEGL_PIPE_INDEX_MIRROR_MB", 64, 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, "");
|
QueryEnvVariable("MOBILEGL_PIPE_STATS_FILE", features.PipeStatsFile, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <Config.h>
|
||||||
#include <MG_Util/Metrics/PipeStats.h>
|
#include <MG_Util/Metrics/PipeStats.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -77,6 +78,21 @@ namespace {
|
|||||||
EXPECT_EQ(PS::FrameCount(), 1u);
|
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) {
|
TEST_F(PipeStatsTest, GateHitsAndMissesAreSeparateCounters) {
|
||||||
for (Uint32 i = 0; i < 5; ++i) {
|
for (Uint32 i = 0; i < 5; ++i) {
|
||||||
PS::CountGate(PS::Gate::MagmaPipelineMemo, /*hit=*/true);
|
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
|
// 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.
|
// smoke check depends on, so a change to it has to break a test.
|
||||||
TEST_F(PipeStatsTest, SummaryPeriodIsOneHundredAndTwentyFrames) {
|
TEST_F(PipeStatsTest, SummaryPeriodIsOneHundredAndTwentyFrames) {
|
||||||
EXPECT_EQ(PS::kSummaryFramePeriod, 120u);
|
EXPECT_EQ(PS::SummaryFramePeriod(), 120u);
|
||||||
for (Uint64 i = 0; i < PS::kSummaryFramePeriod; ++i) {
|
for (Uint64 i = 0; i < PS::SummaryFramePeriod(); ++i) {
|
||||||
PS::OnPresent();
|
PS::OnPresent();
|
||||||
}
|
}
|
||||||
EXPECT_EQ(PS::FrameCount(), PS::kSummaryFramePeriod);
|
EXPECT_EQ(PS::FrameCount(), PS::SummaryFramePeriod());
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -130,6 +130,8 @@ namespace MobileGL::MG_Util::PipeStats {
|
|||||||
Uint64 g_windowBaseFrames = 0;
|
Uint64 g_windowBaseFrames = 0;
|
||||||
Bool g_shutdownDone = false;
|
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) {
|
inline void Bump(Counter& counter, Uint64 amount) {
|
||||||
counter.fetch_add(amount, std::memory_order_relaxed);
|
counter.fetch_add(amount, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
@@ -253,14 +255,19 @@ namespace MobileGL::MG_Util::PipeStats {
|
|||||||
ResetCounters();
|
ResetCounters();
|
||||||
g_shutdownDone = false;
|
g_shutdownDone = false;
|
||||||
g_pipeStatsEnabled = MG_Config::Features.PipeStats;
|
g_pipeStatsEnabled = MG_Config::Features.PipeStats;
|
||||||
|
g_summaryPeriod = MG_Config::Features.PipeStatsPeriod == 0
|
||||||
|
? kDefaultSummaryFramePeriod
|
||||||
|
: static_cast<Uint64>(MG_Config::Features.PipeStatsPeriod);
|
||||||
if (g_pipeStatsEnabled) {
|
if (g_pipeStatsEnabled) {
|
||||||
MGLOG_I("MGPipe stats: counters ON (MOBILEGL_PIPE_STATS), summary every %llu frames%s%s",
|
MGLOG_I("MGPipe stats: counters ON (MOBILEGL_PIPE_STATS), summary every %llu frames%s%s",
|
||||||
static_cast<unsigned long long>(kSummaryFramePeriod),
|
static_cast<unsigned long long>(g_summaryPeriod),
|
||||||
MG_Config::Features.PipeStatsFile.empty() ? "" : ", JSON dump to ",
|
MG_Config::Features.PipeStatsFile.empty() ? "" : ", JSON dump to ",
|
||||||
MG_Config::Features.PipeStatsFile.c_str());
|
MG_Config::Features.PipeStatsFile.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Uint64 SummaryFramePeriod() { return g_summaryPeriod; }
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
if (!g_pipeStatsEnabled || g_shutdownDone) {
|
if (!g_pipeStatsEnabled || g_shutdownDone) {
|
||||||
return;
|
return;
|
||||||
@@ -336,7 +343,7 @@ namespace MobileGL::MG_Util::PipeStats {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
const Uint64 frames = g_frameCount.fetch_add(1, std::memory_order_relaxed) + 1;
|
const Uint64 frames = g_frameCount.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||||
if (frames % kSummaryFramePeriod == 0) {
|
if (frames % g_summaryPeriod == 0) {
|
||||||
EmitSummaryLine();
|
EmitSummaryLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,10 @@ namespace MobileGL::MG_Util::PipeStats {
|
|||||||
inline constexpr Uint32 kPayloadHistogramBuckets = 24;
|
inline constexpr Uint32 kPayloadHistogramBuckets = 24;
|
||||||
|
|
||||||
// Frames between two summary lines when MOBILEGL_PIPE_STATS=1.
|
// 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
|
// 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.
|
// predicted branch - do not turn this into a function call.
|
||||||
|
|||||||
Reference in New Issue
Block a user