perf(network): Improve performance by refactoring loop logic and removing unused static variables#2659
perf(network): Improve performance by refactoring loop logic and removing unused static variables#2659Caball009 wants to merge 4 commits into
Conversation
7ebd8f1 to
a2267a1
Compare
|
I think it would be nice if we can change the signature of NetPacket from |
Perhaps I can just put the relevant logic from |
I think it's best to do this in a separate pull request because it involves another set of changes. |
3fe1916 to
d4f75e9
Compare
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/GameNetwork/Transport.cpp | Most complex change: introduces shared bufferIndex across while-loop iterations in doRecv() and inner loop in doSend() latency path. Logic is correct given all three arrays are MAX_MESSAGES in size, and continue after the latency block gives proper mutual exclusion. The re-enabled DEBUG_ASSERTCRASH fires correctly for the actual first lost packet. |
| Core/GameEngine/Source/GameNetwork/ConnectionManager.cpp | Removes dead numPackets/numCommands static counters; converts while-loops to for-loops; adds early break. packet is set to nullptr immediately after deleteInstance inside the first loop, so the deleteInstance(packet) after the second loop is a safe null call. |
| Core/GameEngine/Source/GameNetwork/NAT.cpp | Adds early break on empty slot. Safe because NAT calls m_transport->update() immediately before the loop, guaranteeing a freshly-filled contiguous buffer. Unrecognized packets (neither PROBE nor KEEPALIVE) are never cleared — a pre-existing issue that does not interact badly with the break since uncleared slots keep length > 0. |
| Core/GameEngine/Source/GameNetwork/LANAPI.cpp | Minor change: variable declaration moved into for-init, ARRAY_SIZE() substituted, else { break; } added on empty slot. The !LANbuttonPushed guard in the loop condition is correctly retained. Every branch (including default) ends by setting m_inBuffer[i].length = 0, so LANAPI always leaves a clean buffer for the next frame's doRecv(). |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant GameLoop
participant Transport
participant Consumer
GameLoop->>Transport: update()
activate Transport
Transport->>Transport: doRecv - fills m_inBuffer[0..k] contiguously
note right of Transport: bufferIndex resets to 0 each call,<br/>skips full slots, fills only empty ones
Transport->>Transport: doSend - delivers delayed msgs to m_inBuffer[k+1..m]
deactivate Transport
GameLoop->>Consumer: doRelay / connectionUpdate / LANAPI::update
activate Consumer
Consumer->>Consumer: "iterate i=0 while length > 0"
Consumer->>Consumer: "clear m_inBuffer[i].length = 0"
Consumer->>Consumer: else break on first empty slot (NEW)
deactivate Consumer
note over Transport,Consumer: Invariant: m_inBuffer is always a contiguous filled prefix.<br/>Break is safe only because doRecv fills from index 0<br/>and consumers clear sequentially.
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant GameLoop
participant Transport
participant Consumer
GameLoop->>Transport: update()
activate Transport
Transport->>Transport: doRecv - fills m_inBuffer[0..k] contiguously
note right of Transport: bufferIndex resets to 0 each call,<br/>skips full slots, fills only empty ones
Transport->>Transport: doSend - delivers delayed msgs to m_inBuffer[k+1..m]
deactivate Transport
GameLoop->>Consumer: doRelay / connectionUpdate / LANAPI::update
activate Consumer
Consumer->>Consumer: "iterate i=0 while length > 0"
Consumer->>Consumer: "clear m_inBuffer[i].length = 0"
Consumer->>Consumer: else break on first empty slot (NEW)
deactivate Consumer
note over Transport,Consumer: Invariant: m_inBuffer is always a contiguous filled prefix.<br/>Break is safe only because doRecv fills from index 0<br/>and consumers clear sequentially.
Reviews (3): Last reviewed commit: "Used explicit 'length > 0' check instead..." | Re-trigger Greptile
| m_transport->m_inBuffer[i].length = 0; | ||
| } | ||
| } else { | ||
| break; |
There was a problem hiding this comment.
Alternatively could do early breaks in the loops. But its ok either way.
| } | ||
| else | ||
| { | ||
| break; |
There was a problem hiding this comment.
So there cannot be non-zero buffer after a zero buffer, yes?
There was a problem hiding this comment.
That's right. Transport::doRecv should handle that correctly.
| for (Int i = 0; i < MAX_MESSAGES; ++i) { | ||
| if (m_transport->m_inBuffer[i].length != 0) { | ||
| for (size_t i = 0; i < ARRAY_SIZE(m_transport->m_inBuffer); ++i) { | ||
| if (m_transport->m_inBuffer[i].length > 0) { |
There was a problem hiding this comment.
Status quo: Compares with > 0, != 0
Expectation:
> 0, <= 0
or
== 0, != 0
There was a problem hiding this comment.
I've split this off to a separate commit. I do think this is the right comparator, though, as long as length is still signed.
The original code already does it this way here:
There was a problem hiding this comment.
I can change the == 0 cases to <= 0 if you like.
I can put the loop logic in another PR and put #2866 in here to replace all memory pooled uses of |
|
Whatever makes most sense. |
This PR makes modest performance improvements:
See commits for cleaner diffs.
TODO: