From d868e1c4761783e53bffe0caa581af3b41f559c1 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Mon, 10 Aug 2026 09:56:05 -0400 Subject: [PATCH] [Test] (MG_Util, MG_State): remove the TEMP stage-timing probes - the async-compile measurement campaign is done --- .../GLState/ProgramState/ProgramLinkTask.cpp | 25 +--- .../GLState/ProgramState/ProgramSpirvTask.cpp | 36 +----- .../ProgramState/ShaderCompileTask.cpp | 22 +--- MobileGL/MG_Util/Debug/TempStageProbe.h | 121 ------------------ .../ShaderTranspiler/ShaderCompiler.cpp | 28 +--- .../MG_Util/ShaderTranspiler/ShaderCompiler.h | 4 - 6 files changed, 8 insertions(+), 228 deletions(-) delete mode 100644 MobileGL/MG_Util/Debug/TempStageProbe.h diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.cpp index 5f374d1e..f20cc3d5 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramLinkTask.cpp @@ -13,7 +13,6 @@ #include #include #include -#include // TEMP-STAGE-PROBE #include #include #include @@ -294,15 +293,6 @@ namespace MobileGL::MG_State::GLState { const GlslangThreadAllocatorGuard glslangGuard; using namespace MG_Util::ShaderTranspiler; - // TEMP-STAGE-PROBE: "linktask-total" (whole link body, superset of glslang-link / - // spirv-gen / spirv-opt / reflection / spvc-routing / the ConsumeShaders re-parse) - // plus the every-25-links running-total dump of every stage. - // Declared FIRST so it is destroyed LAST: the dump then already includes this link's - // own contribution to every stage, including "linktask-total". - const MG_Util::Debug::TempStageProbeLinkTick tempStageProbeLinkTick; - const MG_Util::Debug::TempStageProbeScope tempStageProbeLinkTask( - MG_Util::Debug::kTempStageProbeLinkTaskTotal); - MOBILEGL_ASSERT(in.env != nullptr, "ProgramLinkTask: the CompileEnv snapshot is missing"); const CompileEnv& env = *in.env; @@ -342,12 +332,7 @@ namespace MobileGL::MG_State::GLState { .explicitOpaqueUniformBindings = &artifacts.explicitOpaqueUniformBindings}; MGLOG_D("ProgramObject %u: Calling ShaderCompiler::LinkProgram", in.externalIndex); - // TEMP-STAGE-PROBE: "glslang-link" - TProgram::link + mapIO. - auto result = [&] { - const MG_Util::Debug::TempStageProbeScope tempStageProbeGlslangLink( - MG_Util::Debug::kTempStageProbeGlslangLink); - return ShaderCompiler::LinkProgram(attrib); - }(); + auto result = ShaderCompiler::LinkProgram(attrib); if (result) { artifacts.linkStatus = true; artifacts.program = result.value(); @@ -416,13 +401,7 @@ namespace MobileGL::MG_State::GLState { // AND read the OPTIMIZED SPIR-V, so BuildGlobalUboRouting still runs strictly after // both DoReflection and GenerateSpirv. MGLOG_D("ProgramObject %u: Starting reflection", in.externalIndex); - // TEMP-STAGE-PROBE: "reflection" - buildReflection + the GL location assignment. - const bool tempStageProbeReflectionOk = [&] { - const MG_Util::Debug::TempStageProbeScope tempStageProbeReflection( - MG_Util::Debug::kTempStageProbeReflection); - return static_cast(DoReflection(env)); - }(); - if (!tempStageProbeReflectionOk) { + if (!DoReflection(env)) { DeferLog(std::format("ProgramObject {}: Link failed during reflection: {}", in.externalIndex, artifacts.infoLog)); return; diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramSpirvTask.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramSpirvTask.cpp index 311568f4..08f479c0 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramSpirvTask.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramSpirvTask.cpp @@ -10,7 +10,6 @@ #include // GlslangThreadAllocatorGuard #include -#include // TEMP-STAGE-PROBE #include #include #include @@ -102,11 +101,6 @@ namespace MobileGL::MG_State::GLState { return; } - // TEMP-STAGE-PROBE: "spirvtask-total" (whole phase-B body, superset of spirv-gen / - // spirv-null / spirv-opt / spvc-routing). - const MG_Util::Debug::TempStageProbeScope tempStageProbeSpirvTask( - MG_Util::Debug::kTempStageProbeSpirvTaskTotal); - MGLOG_D("ProgramObject %u: Starting SPIR-V generation", externalIndex); GenerateSpirv(handoff, externalIndex); // GlslangToSpv was the only consumer of the parsed ASTs; everything after this point @@ -138,12 +132,7 @@ namespace MobileGL::MG_State::GLState { handoff.shaders.clear(); MGLOG_D("ProgramObject %u: Building global-UBO routing tables", externalIndex); - { - // TEMP-STAGE-PROBE: "spvc-routing" - the SPIRV-Cross session per SPIR-V module. - const MG_Util::Debug::TempStageProbeScope tempStageProbeSpvcRouting( - MG_Util::Debug::kTempStageProbeSpvcRouting); - BuildGlobalUboRouting(handoff, externalIndex); - } + BuildGlobalUboRouting(handoff, externalIndex); MGLOG_D("ProgramObject %u: Binary generation finished (generatedSpirv size=%zu)", externalIndex, artifacts.generatedSpirv.size()); } @@ -166,12 +155,7 @@ namespace MobileGL::MG_State::GLState { .program = *handoff.reflection.program, }; MGLOG_D("ProgramObject %u: GenerateSpirv - requesting SPIR-V binary from program", externalIndex); - // TEMP-STAGE-PROBE: "spirv-gen" - GlslangToSpv for every stage of this program. - auto binaryResult = [&] { - const MG_Util::Debug::TempStageProbeScope tempStageProbeSpirvGen( - MG_Util::Debug::kTempStageProbeSpirvGen); - return ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); - }(); + auto binaryResult = ShaderCompiler::GetSpirvBinaryFromProgram(binaryAttrib); if (!binaryResult) { DeferLog(std::format("ProgramObject {}: GenerateSpirv - GetSpirvBinaryFromProgram failed", externalIndex)); MOBILEGL_ASSERT(binaryResult, "GetSpirvBinaryFromProgram failed"); @@ -182,24 +166,8 @@ namespace MobileGL::MG_State::GLState { artifacts.generatedSpirv.size()); // Linked SPIR-V generated, sanitize and optimize it - { - // TEMP-STAGE-PROBE: "spirv-null" - the same Optimizer::Run with ZERO passes, - // on the pre-optimize binary: pure BuildModule + serialize + IRContext - // teardown. Its device/desktop share ratio against "spirv-opt" is the - // allocator-pathology discriminator. Costs one extra plumbing round per - // module; diagnostic build only. - const MG_Util::Debug::TempStageProbeScope tempStageProbeSpirvNull( - MG_Util::Debug::kTempStageProbeSpirvNull); - for (auto& spv : artifacts.generatedSpirv) { - Vector nullOut; - (void)ShaderCompiler::TempProbeNullOptimizeBinary(spv, nullOut); - } - } Bool allOptimized = true; { - // TEMP-STAGE-PROBE: "spirv-opt" - the spirv-tools optimizer run over every module. - const MG_Util::Debug::TempStageProbeScope tempStageProbeSpirvOpt( - MG_Util::Debug::kTempStageProbeSpirvOpt); for (auto& spv : artifacts.generatedSpirv) { auto success = ShaderCompiler::SanitizeAndOptimizeBinary(spv, spv); if (!success) { diff --git a/MobileGL/MG_State/GLState/ProgramState/ShaderCompileTask.cpp b/MobileGL/MG_State/GLState/ProgramState/ShaderCompileTask.cpp index 7ac9bf1f..70165f11 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ShaderCompileTask.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ShaderCompileTask.cpp @@ -9,7 +9,6 @@ #include "ShaderCompileTask.h" #include -#include // TEMP-STAGE-PROBE #include #include #include @@ -156,13 +155,7 @@ namespace { MobileGL::MG_State::GLState::ShaderPreprocessResult result; result.preprocessedSource = source; - { - // TEMP-STAGE-PROBE: "preprocess". Only reached on a ShaderPreprocessCache miss, - // so its call count is the miss count, not the glCompileShader count. - const MobileGL::MG_Util::Debug::TempStageProbeScope tempStageProbePreprocess( - MobileGL::MG_Util::Debug::kTempStageProbePreprocess); - PreprocessShaderSource(stage, result.preprocessedSource, env); - } + PreprocessShaderSource(stage, result.preprocessedSource, env); if (stage == ShaderStage::Compute) { if (const std::optional localSizeError = @@ -214,10 +207,6 @@ namespace MobileGL::MG_State::GLState { // status + log, so turn a throw into exactly that - a completed job whose result // is "this shader did not compile", with a log the application can read. // (JobNode still catches: it is the last resort for anything below.) - // TEMP-STAGE-PROBE: "compiletask-total" - whole ShaderCompileTask body (superset of - // "preprocess" + "parse"); the difference is the task's own bookkeeping. - const MG_Util::Debug::TempStageProbeScope tempStageProbeCompileTask( - MG_Util::Debug::kTempStageProbeCompileTaskTotal); try { RunCompilePipeline(); } catch (const std::exception& e) { @@ -338,14 +327,7 @@ namespace MobileGL::MG_State::GLState { // Re-parse against the SAME environment the original parse used, // not against whatever the backend reports now. .env = artifacts.env.get()}; - // TEMP-STAGE-PROBE: "parse-reparse" - the link-time consume-once re-parse. This goes - // through ShaderCompiler::CompileShader, so it is ALSO counted in "parse"; it is - // recorded separately so the "parse" total can be split into first-parse vs re-parse. - auto result = [&] { - const MG_Util::Debug::TempStageProbeScope tempStageProbeReparse( - MG_Util::Debug::kTempStageProbeParseReparse); - return ShaderCompiler::CompileShader(attrib); - }(); + auto result = ShaderCompiler::CompileShader(attrib); if (!result) { // Should be unreachable: the same source parsed successfully at Compile(). outReparseLog = result.error().log; diff --git a/MobileGL/MG_Util/Debug/TempStageProbe.h b/MobileGL/MG_Util/Debug/TempStageProbe.h deleted file mode 100644 index d569cdf5..00000000 --- a/MobileGL/MG_Util/Debug/TempStageProbe.h +++ /dev/null @@ -1,121 +0,0 @@ -// MobileGL - MobileGL/MG_Util/Debug/TempStageProbe.h -// Copyright (c) 2025-2026 MobileGL-Dev -// Licensed under the GNU Lesser General Public License v3.0: -// https://www.gnu.org/licenses/gpl-3.0.txt -// https://www.gnu.org/licenses/lgpl-3.0.txt -// SPDX-License-Identifier: LGPL-3.0-only -// End of Source File Header -// -// TEMP-STAGE-PROBE: TEMPORARY instrumentation. Measures the per-stage wall time of the -// shader frontend (preprocess / glslang parse / glslang link+mapIO / SPIR-V generation / -// spirv-tools optimize / reflection / SPIRV-Cross global-UBO routing) so a shaderpack load -// can be attributed stage by stage. Delete this file together with every call site marked -// TEMP-STAGE-PROBE when the measurement is finished. Every identifier is spelled -// tempStageProbe* / TempStageProbe* / kTempStageProbe* so both spellings are greppable. - -#pragma once - -#include - -#include -#include - -namespace MobileGL::MG_Util::Debug { - // TEMP-STAGE-PROBE: stage ids. The two *Total entries are SUPERSETS of the stages above - // them (they time the whole task body), kept so the residue inside a task body is - // visible; kTempStageProbeParseReparse is a SUBSET of kTempStageProbeParse (the link's - // consume-once re-parse goes through the same ShaderCompiler::CompileShader). - enum TempStageProbeStageId : int { - kTempStageProbePreprocess = 0, - kTempStageProbeParse, - kTempStageProbeParseReparse, - kTempStageProbeGlslangLink, - kTempStageProbeSpirvGen, - kTempStageProbeSpirvNull, - kTempStageProbeSpirvOpt, - kTempStageProbeReflection, - kTempStageProbeSpvcRouting, - kTempStageProbeCompileTaskTotal, - kTempStageProbeLinkTaskTotal, - kTempStageProbeSpirvTaskTotal, - kTempStageProbeStageCount - }; - - inline const char* const kTempStageProbeStageNames[kTempStageProbeStageCount] = { - "preprocess", - "parse", - "parse-reparse[subset-of-parse]", - "glslang-link", - "spirv-gen", - "spirv-null[plumbing-only]", - "spirv-opt", - "reflection", - "spvc-routing", - "compiletask-total[superset]", - "linktask-total[superset]", - "spirvtask-total[superset]", - }; - - inline std::atomic tempStageProbeMicros[kTempStageProbeStageCount] = {}; - inline std::atomic tempStageProbeCalls[kTempStageProbeStageCount] = {}; - inline std::atomic tempStageProbeLinkCount{0}; - inline std::atomic tempStageProbeLastDumpNanos{0}; - - // TEMP-STAGE-PROBE: scoped accumulator. Relaxed atomics only - nothing here orders any - // other memory, and the probe must not perturb what it measures. - class TempStageProbeScope { - public: - explicit TempStageProbeScope(int tempStageProbeStageId) - : tempStageProbeStage(tempStageProbeStageId), - tempStageProbeStart(std::chrono::steady_clock::now()) {} - ~TempStageProbeScope() { - const auto tempStageProbeElapsedUs = std::chrono::duration_cast( - std::chrono::steady_clock::now() - tempStageProbeStart) - .count(); - tempStageProbeMicros[tempStageProbeStage].fetch_add( - static_cast(tempStageProbeElapsedUs), std::memory_order_relaxed); - tempStageProbeCalls[tempStageProbeStage].fetch_add(1ull, std::memory_order_relaxed); - } - TempStageProbeScope(const TempStageProbeScope&) = delete; - TempStageProbeScope& operator=(const TempStageProbeScope&) = delete; - - private: - int tempStageProbeStage; - std::chrono::steady_clock::time_point tempStageProbeStart; - }; - - // TEMP-STAGE-PROBE: one MGLOG_I line per stage carrying the running cumulative total. - inline void TempStageProbeDumpTotals(unsigned long long tempStageProbeLinkIndex) { - for (int tempStageProbeIdx = 0; tempStageProbeIdx < kTempStageProbeStageCount; ++tempStageProbeIdx) { - const unsigned long long tempStageProbeUs = - tempStageProbeMicros[tempStageProbeIdx].load(std::memory_order_relaxed); - const unsigned long long tempStageProbeN = - tempStageProbeCalls[tempStageProbeIdx].load(std::memory_order_relaxed); - MGLOG_I("TEMP-STAGE-PROBE: %s total %llu.%03llu ms over %llu calls (after %llu links)", - kTempStageProbeStageNames[tempStageProbeIdx], tempStageProbeUs / 1000ull, - tempStageProbeUs % 1000ull, tempStageProbeN, tempStageProbeLinkIndex); - } - } - - // TEMP-STAGE-PROBE: ticks the program-link counter on scope exit (so a link that returns - // early still counts) and dumps every stage's running total every 25 links. The 3-second - // fallback exists so the LAST link of a load also publishes totals - the process is - // force-stopped afterwards, so there is no exit hook to rely on. - class TempStageProbeLinkTick { - public: - ~TempStageProbeLinkTick() { - const unsigned long long tempStageProbeIndex = - tempStageProbeLinkCount.fetch_add(1ull, std::memory_order_relaxed) + 1ull; - const long long tempStageProbeNowNanos = - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); - const long long tempStageProbeLastNanos = tempStageProbeLastDumpNanos.load(std::memory_order_relaxed); - const bool tempStageProbeDueByCount = (tempStageProbeIndex % 25ull) == 0ull; - const bool tempStageProbeDueByTime = tempStageProbeNowNanos - tempStageProbeLastNanos > 3000000000LL; - if (!tempStageProbeDueByCount && !tempStageProbeDueByTime) return; - tempStageProbeLastDumpNanos.store(tempStageProbeNowNanos, std::memory_order_relaxed); - TempStageProbeDumpTotals(tempStageProbeIndex); - } - }; -} // namespace MobileGL::MG_Util::Debug diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index f9898098..095fa235 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -32,7 +32,6 @@ #include #include #include -#include // TEMP-STAGE-PROBE #include namespace MobileGL { @@ -225,18 +224,8 @@ namespace MobileGL { return std::unexpected(r); } - // TEMP-STAGE-PROBE: "parse" - one glslang TShader::parse. Both the first - // attempt and the legacy-#version retry below go through here, and so does - // ProgramLinkTask's consume-once re-parse (separately counted there as - // "parse-reparse") and ShaderCompiler::PrewarmBuiltins' three warm-up parses. - const auto tempStageProbeParseShaderSource = [&](const String& tempStageProbeSource) { - const MobileGL::MG_Util::Debug::TempStageProbeScope tempStageProbeParse( - MobileGL::MG_Util::Debug::kTempStageProbeParse); - return ParseShaderSource(lang, shaderType, tempStageProbeSource, attrib.flags, attrib.env); - }; - const String source(attrib.sourceStr); - auto result = tempStageProbeParseShaderSource(source); + auto result = ParseShaderSource(lang, shaderType, source, attrib.flags, attrib.env); if (result) return result; // Legacy desktop sources are normalized to "#version 330 core" (with a marker on the @@ -252,7 +241,7 @@ namespace MobileGL { return result; } - auto retryResult = tempStageProbeParseShaderSource(retrySource); // TEMP-STAGE-PROBE + auto retryResult = ParseShaderSource(lang, shaderType, retrySource, attrib.flags, attrib.env); if (!retryResult) return result; MGLOG_D("CompileShader: %s only parsed after retargeting its legacy #version to 460", @@ -385,19 +374,6 @@ namespace MobileGL { return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options); } - // TEMP-STAGE-PROBE tempStageProbeNullOptimize: SanitizeAndOptimizeBinary minus - // every pass - measures the pure IR plumbing (BuildModule + serialize + - // IRContext teardown) so a device run can separate allocator-bound plumbing - // from transformation work. Remove with the probes. - bool ShaderCompiler::TempProbeNullOptimizeBinary(const Vector& inputBinary, - Vector& outputBinary) { - using namespace spvtools; - OptimizerOptions options; - options.set_run_validator(false); - Optimizer optimizer(SPV_ENV_VULKAN_1_1); - return optimizer.Run(inputBinary.data(), inputBinary.size(), &outputBinary, options); - } - bool ShaderCompiler::LowerDrawParametersForEssl(const Vector& inputBinary, Vector& outputBinary) { using namespace spvtools; diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h index 450b4863..bd1a5964 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.h @@ -22,10 +22,6 @@ namespace MobileGL { static Result>> GetSpirvBinaryFromProgram(const ProgramBinaryAttrib& attrib); static bool SanitizeAndOptimizeBinary(const Vector& inputBinary, Vector& outputBinary); - // TEMP-STAGE-PROBE: SanitizeAndOptimizeBinary with zero passes - pure IR - // plumbing, for the allocator-pathology discriminator. Remove with the probes. - static bool TempProbeNullOptimizeBinary(const Vector& inputBinary, - Vector& outputBinary); // Demotes DrawIndex/BaseInstance/BaseVertex builtins to plain Private globals // (mg_DrawID/mg_BaseInstance/mg_BaseVertex) so SPIRV-Cross can emit ESSL. // Only for backends without native draw-parameter support (DirectGLES).