mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-15 14:03:23 +09:00
[Perf] (P12): the create window lands as the default - declared-answer retention replaces the ring, and the load frame goes 28.66 s -> 16.52 s (11.02 s at window 4)
The three things that made the deferral inert are all fixed, in the order they were
found: the reply ring could not hold an answer across the ~1,000 records between two
creates; a residency budget could not help because what displaces an answer is what
the SERVER sends, not what the client emits; and so the mechanism had to be retention.
WHAT LANDED
* ILink::DeclareReplyRead + LinkCapabilities::RetainsReplies. The wire declares a
seq will be read BEFORE it publishes, so the declaration cannot race its own
answer; a link with the capability false ignores it, and the window does not
defer on one (CreateWindowEffective() is gated on it).
* StreamLink's ring of the last 8 answers becomes a declared-answer store: a
monotone whitelist plus a cursor, answers kept until their reader TAKES them
(take-and-delete under one lock, bytes swapped into the scratch), and a capacity
of 24 that is FATAL to exceed rather than evicting. An evicted wanted answer is
unrecoverable - re-latching by sending another create wipes the server's record
(PipeApply.cpp:2033) and its PendingUploads (PipeApply.h:332) while the client
cleared its dirty flags at emission (PipeApply.h:298-304) - so the capacity is
sized so it cannot be reached and reaching it says its own name.
* An answer nobody declared is DROPPED, which is what keeps the store bounded by the
client's deferral depth instead of by the server's answer rate. Retain-on-arrival
grows ~11.3 entries per create against a server that ignores the no-reply bit.
* A read that fails after WaitForApplied has returned Reached is now Fatal{ReplyMissing}
naming the seq: on the stream arm the reply frame strictly precedes the progress
frame that publishes appliedSeq, so that combination is a broken invariant, and
retrying it (what the row used to do) wedges the window for the rest of the
process while leaving every deferred object latched on a provisional accept.
* The residency budget is deleted (WireTables.cpp keeps its history), the window
retirement branch drains once before falling back - it could otherwise strand the
answers it was holding - and Detach clears the store.
MEASURED ON THE DEVICE, load frame, both ends rebuilt, frame-sent identical per op
(create 4,536, records 103,097) throughout:
window 1 (R-5's shape) 4,536 takes 28.66 s
window 2 explicit 2,500 17.27 s
window 2 AS THE SHIPPED DEFAULT 2,563 16.52 s
window 4 1,644 11.02 s
window 2 against an OLD SERVER 2,663 16.38 s (zero Fatals)
The last row is the version-skew case the design review named as a must: a server
built before the no-reply bit answers ~55,903 records a frame, the whitelist drops
every answer nobody declared, and the deferral still reads its own back.
GATES (172 + 15 green), and the important one is proved to go red:
* ADeclaredAnswerSurvivesFarMoreInterveningAnswersThanAnyFixedBuffer - reverting the
store to "keep the last 8 arrivals" fails it immediately with "the declared answer
did not survive 64 intervening ones". That is the line between the ring-1024
stand-in and a bounded mechanism.
* AnAnswerNobodyDeclaredIsNotKeptAtAll - red if everything is retained.
* TheWindowRefusesToDeferOnALinkThatCannotRetainAnswers - on the in-process (ShmLink)
arm the knob at 4 must still block every create, red if the capability gate goes.
* The refused-create case now reads the repair that exists on THAT arm (the latch),
and asserts the window's own books are empty there.
NOT DONE, and named: the window has no unit gate on the STREAM arm yet - only the
device runs. Three rounds of this feature were green in the lanes while inert on the
device because the lanes and the device run different transports; the transport-level
retention gates close that for the store, and the window-level one should be built on
StreamClientPublicationTest's real stream session next.
This commit is contained in:
@@ -1898,10 +1898,17 @@ namespace MobileGL::MG_Remote::Client {
|
||||
// creates or parameter sets, and those three have different fixes.
|
||||
const auto replyMetricStart =
|
||||
Transport::LinkMetricsBeginReply(ownsReplySlot, static_cast<std::uint32_t>(op));
|
||||
// P12: the residency budget's clock. Placed HERE, where the record is certainly
|
||||
// published, rather than beside rowCarriesReplySlot: a call that declined before
|
||||
// encoding emits nothing and must not advance it.
|
||||
// P12: the residency clock AND the declaration, both placed HERE - after EncodeRecord has
|
||||
// an ordinal and BEFORE the publish, which is the only window in which the declaration is
|
||||
// guaranteed to precede its own answer. A call that declined before encoding emits nothing
|
||||
// and must not advance either.
|
||||
if (rowCarriesReplySlot) ++m_replyPostings;
|
||||
// THE DECLARATION THAT LETS A LINK RETAIN THIS ANSWER (P12). willReadReply, not wantReply:
|
||||
// the create window emits without waiting and reads afterwards, so its records must be
|
||||
// declared even though this call does not read them. Links that cannot retain ignore it,
|
||||
// and the window does not defer on them (see ClientSession::LinkRetainsReplies).
|
||||
if (rowCarriesReplySlot && willReadReply && m_link != nullptr)
|
||||
m_link->DeclareReplyRead(seq);
|
||||
m_producer.PublishAndNotify(seq);
|
||||
if (op == MG_Pipe::MGPWireOp::Present) {
|
||||
// A credit is permission to run ahead, not permission to retain the
|
||||
@@ -2464,6 +2471,10 @@ namespace MobileGL::MG_Remote::Client {
|
||||
|
||||
Uint64 ClientSession::ReplyPostings() const { return m_replyPostings; }
|
||||
|
||||
Bool ClientSession::LinkRetainsReplies() const {
|
||||
return m_link != nullptr && m_link->Capabilities().RetainsReplies;
|
||||
}
|
||||
|
||||
Bool ClientSession::ReadReply(Uint64 seq, void* outBytes, Uint64 outCapacity, Int32* outStatus,
|
||||
Uint64* outSize) {
|
||||
const void* bytes = nullptr; Uint64 size = 0; Int32 status = 0;
|
||||
|
||||
Reference in New Issue
Block a user