diff --git a/engine/MUNGA/JMOVER.cpp b/engine/MUNGA/JMOVER.cpp index ae2c912..5fad336 100644 --- a/engine/MUNGA/JMOVER.cpp +++ b/engine/MUNGA/JMOVER.cpp @@ -117,6 +117,16 @@ EntitySegment* } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// #149 perf telemetry (BT_PERF_LOG; counters cost two increments when unset). +// gBTSegWDirty counts the EXPENSIVE arm -- the mark-every-segment pass that +// invalidates the whole table -- separately from plain calls, because the #141 +// sweep put this accessor on per-frame weapon/beam paths and the open question +// is whether that multiplied the dirty-pass rate (each pass forces the next +// query of EVERY segment to re-derive its parent chain). +int gBTSegWCalls = 0; +int gBTSegWDirty = 0; +double gBTSegWMs = 0.0; + // void JointedMover::GetSegmentToWorld( @@ -125,6 +135,10 @@ void ) { Check(this); + static const int sPerf = getenv("BT_PERF_LOG") ? 1 : 0; + LARGE_INTEGER t0, t1, fq; + ++gBTSegWCalls; + if (sPerf) QueryPerformanceCounter(&t0); JointSubsystem *joints = GetJointSubsystem(); Check(joints); @@ -135,6 +149,7 @@ void // if (joints->AreJointsModified()) { + ++gBTSegWDirty; EntitySegment::SegmentTableIterator iterator(segmentTable); EntitySegment *current_segment; while( (current_segment = iterator.ReadAndNext() ) != NULL) @@ -153,6 +168,12 @@ void my_segment.GetSegmentToEntity(), localToWorld ); + if (sPerf) + { + QueryPerformanceCounter(&t1); + QueryPerformanceFrequency(&fq); + gBTSegWMs += 1000.0 * (double)(t1.QuadPart - t0.QuadPart) / (double)fq.QuadPart; + } Check_Fpu(); } diff --git a/engine/MUNGA_L4/L4VIDEO.cpp b/engine/MUNGA_L4/L4VIDEO.cpp index 4fd3a02..a8d118a 100644 --- a/engine/MUNGA_L4/L4VIDEO.cpp +++ b/engine/MUNGA_L4/L4VIDEO.cpp @@ -9034,6 +9034,20 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte DEBUG_STREAM << "[rstat] frames=" << sFrames << " avg=" << (sAcc / sFrames) << "ms maxDraw=" << sMaxD << " maxPresent=" << sMaxP << " batches=" << gNumBatches << " culled=" << gBTNumCulled << "\n" << std::flush; + // #149: segment-refresh telemetry on the same cadence (BT_PERF_LOG). + // calls = GetSegmentToWorld entries; dirty = the mark-every-segment + // invalidation passes (the expensive arm the #141 sweep may have + // multiplied); ms = time inside the accessor for the whole window. + { + static const int sSegPerf = getenv("BT_PERF_LOG") ? 1 : 0; + extern int gBTSegWCalls, gBTSegWDirty; + extern double gBTSegWMs; + if (sSegPerf) + DEBUG_STREAM << "[segperf] calls=" << gBTSegWCalls + << " dirty=" << gBTSegWDirty + << " ms=" << gBTSegWMs << "\n" << std::flush; + gBTSegWCalls = 0; gBTSegWDirty = 0; gBTSegWMs = 0.0; + } sAcc = 0.0; sFrames = 0; sMaxD = 0.0; sMaxP = 0.0; } } diff --git a/game/reconstructed/mech4.cpp b/game/reconstructed/mech4.cpp index 6667676..222b880 100644 --- a/game/reconstructed/mech4.cpp +++ b/game/reconstructed/mech4.cpp @@ -9031,8 +9031,20 @@ void // This is the BEAM muzzle -- the same stale-cache exposure the // missile launch had, so a peer's beam would also originate // from the bind-pose gun port instead of the twisted torso. + // #149 A/B (BT_BEAM_SEGFRESH=0): revert THIS site to the + // pre-sweep plain compose, to measure whether the per-beam + // per-frame dirty-pass is the 857 draw-stall regression. + // This site runs inside the DRAW path per emitter per frame; + // the other swept sites are per-salvo/per-hit and cannot be + // a per-frame cost. Default = fresh (the swept behaviour). + static const int sBeamFresh = + !(getenv("BT_BEAM_SEGFRESH") && *getenv("BT_BEAM_SEGFRESH") == '0'); LinearMatrix mw; - GetSegmentToWorld(*s_portCache[energyOrdinal], &mw); + if (sBeamFresh) + GetSegmentToWorld(*s_portCache[energyOrdinal], &mw); + else + mw.Multiply(s_portCache[energyOrdinal]->GetSegmentToEntity(), + localToWorld); mz = mw; // Point3D = matrix translation } } diff --git a/scratchpad/night14/segperf.sh b/scratchpad/night14/segperf.sh new file mode 100644 index 0000000..a139461 --- /dev/null +++ b/scratchpad/night14/segperf.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# ========================================================================= +# #149 -- 817 -> 857 stall regression (Oracle: 97 blocks >50ms, all in the +# mission-load window, maxDraw up to 518ms; zero such blocks on 817, same +# machine). My filed suspect was the #141 segment-cache sweep -- but that is +# a HYPOTHESIS, and #137 just taught us what plausible-but-unmeasured +# theories are worth. So: measure first. +# +# INSTRUMENTATION (this build): +# [segperf] calls= dirty= ms=