[Perf] (MG_Remote/Client): the create window lands OFF - the deferral cannot be collected, 8 reply slots against 59,673 replies in one frame - measured on the device at 4,536 blocking creates either way

The window was the handoff's remaining item: let up to N resource_create answers be
outstanding, read a provisional accept, collect the answers in order, and un-latch an
object whose late answer is DECLINED. It is a sound mechanism and the gates below pin
it - and on the device it does nothing at all, which is why the default is 1.

MEASURED, same device, same frame, same 101,421,396 B staged, same binary:

    MOBILEGL_IPC_CREATE_WINDOW=4   by_op 2 = 4,536   wall 28.64 s
    MOBILEGL_IPC_CREATE_WINDOW=1   by_op 2 = 4,536   wall 28.64 s
    (the handoff's pre-window baseline: 31.3 s)

by_op 2 counts the creates that took the BLOCKING path (LinkMetricsBeginReply is
called with ownsReplySlot = rowCarriesReplySlot && wantReply), so it not moving means
no create deferred. A temporary counter in the row said why: pushed=24, blocked=4,476,
took=20, readfail=8,951, pending pinned at 4 - the drain READ the answers back and
failed every time.

WHY, IN THE PROTOCOL'S OWN ARITHMETIC. An answer is readable only until its pool slot
is reused, and the pool is kDefaultReplySlotCount = 8. The server answers EVERY
reply-owning record, not only the rows that wait, because it cannot know which those
are (ClientSession.cpp:1897-1900: "The server posts either way"). This frame posts
59,673 of them: create 4,536 + respecify 20,633 + params 18,056 + sub-data 12,671 +
the rest. 8 slots against 59,673 replies churns 7,459 times per frame, i.e. 13.2
replies between two creates, so an answer is overwritten after 8 replies - 0.61 of a
create. The deferral is not slow, it is UNREADABLE, and no window depth fixes that.

AND IT IS NOT NEUTRAL: with the window on, the provisional accept latches an object
the applier may have refused, and the un-latch that corrects it lives in that same
unreadable drain. A refusal would become an object the client believes is published -
the silent divergence the suspect list exists to prevent. So the machinery is kept
(one experiment away from usable: a deeper pool, or a "do not answer me" bit, both
wire changes) and the default is off.

Worktree note: the window implementation itself was uncommitted in the tree at
82ed1df9 (MOBILEGL-CS-HANDOFF-2.md section 2, "can compile, gates mostly green, never
run on a device"). This commit lands it in the state the measurement supports. The
row also gains the heal the suspect list was missing - a BLOCKING create that lands
takes its object back out of it, or kCreateSuspectMax recoveries would retire the
window for the rest of the process - and the clamp that ties the environment's value
to the array, with a static_assert tying the array to half the reply pool so "someone
raises kCreateWindowMax to 8 and steps on the pool" is a compile error.

Gates (RemoteClientControls.inc), all green, 171/171 RemoteClientTest:
  ACreateWindowDefersTheAnswersAndTheWindowOffDoesNot - window on = 12 records 0 waits;
    the SAME CHILD turns the knob to 1 and it is 12 records 12 waits (the negative
    control); pending <= effective after every create; 99 clamps to the array; the
    array is <= half the pool
  ARefusedCreateUnlatchesItsObjectAndItsNextCreateBlocks - a real refusal (the
    server's consumed mask narrowed) clears the latch, +1 suspect, the object's next
    create BLOCKS (2 records 2 waits), and restoring the consumer HEALS it (latch
    back, suspect -1)

Docs: CONTRACT-P5E.md section 2.5 rewritten (it still said all three rows keep
kWaitReply), plus
docs/Disaggregated/notes/p12/CREATE-WINDOW-MEASURED.md (the numbers, the arithmetic,
the picture evidence: both arms SSIM 0.977) and
docs/Disaggregated/notes/p12/UNPUBLISH-GUARD-SIGNALS.md (handoff section 3: neither
caps generation nor FreshlyPrimed is a signal for "the applier dropped its records",
and the residual gap is one line - the dedup at TextureEmit.h:838 does not read the
latch, so an UNCHANGED descriptor after a drop produces no record and therefore no
refusal to self-heal from).
This commit is contained in:
BZLZHH
2026-09-26 00:47:19 +08:00
parent a2c1f5f292
commit d2efd1d79d
9 changed files with 787 additions and 22 deletions
@@ -53,6 +53,9 @@
#include <MG_Backend/MGPipe/PipeInputs.h>
#include <MG_Backend/DirectGLES/Managers.h>
#include <MG_Impl/Pipe/PipeFill.h>
// P12: MGPipeTextureEmitterInstance(), so a control case can name the handle of an object it
// created and read the publication latch the converted rows read.
#include <MG_Impl/Pipe/TextureEmit.h>
#include <Init.h>
#include <MG_Impl/EGLImpl/EGLImpl.h>
#include <MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h>