Repository navigation
Conversation
Every message sent or received allocated and freed a CSteamNetworkingMessage with new/delete (see the FIXMEs in New() and ReleaseFunc(), and ValveSoftware#369). Recycle them instead: each thread keeps a small cache of free objects, and batches of 32 move between thread caches and a shared depot (protected by a leaf mutex) so that messages allocated on one thread and released on another are reused too. Caches and the depot are bounded; anything beyond that is freed. A thread's cache goes back to the depot when the thread exits, and GameNetworkingSockets_Kill frees the depot. Pooling is off in AddressSanitizer builds (it would hide use-after-free) and can be disabled with STEAMNETWORKINGSOCKETS_ENABLE_MESSAGE_POOL=0. New() now also clears m_nUserData, so a recycled object never carries over the previous message's value. Adds a message_pool test (to suite-quick) and a bench_messages benchmark.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #369 and the two
FIXME Should avoid this dynamic memory call with some sort of poolingcomments inCSteamNetworkingMessage::New()/ReleaseFunc().Every message sent or received does a
new/deleteof a ~264-byteCSteamNetworkingMessage. This recycles them:std::mutexthat is a leaf lock. Anything beyond those bounds is freed as before.GameNetworkingSockets_Kill()frees the depot and the calling thread's cache.thread_localfallback applies; can be disabled with-DSTEAMNETWORKINGSOCKETS_ENABLE_MESSAGE_POOL=0.New()also clearsm_nUserDatanow. It was never initialized before (fresh heap memory), but with reuse it would otherwise carry over the previous message's value.The payload buffer is still a separate
malloc, sinceCSteamNetworkingMessagesre-pointsm_pData/m_pfnFreeDataat a header in front of the buffer.Tests: new
message_pooltest (added tosuite-quick) allocates more messages than the caches hold, scribbles on every user-writable field, and checks recycled messages come back fully initialized, including messages allocated on 4 producer threads and released on 4 consumer threads that then exit. I checked it fails if a field isn't reinitialized.test_connection suite-quickandtest_cryptopass on macOS (Apple Silicon, clang, Release), andmessage_pool/pipealso pass with the pool compiled out.Benchmark:
tests/bench_messages.cpp(built asbench_messages, not run by ctest). Release build, Apple Silicon arm64, 1M iterations, median of 7 runs per process, then median over 13 interleaved processes, pool vs. the same build with-DSTEAMNETWORKINGSOCKETS_ENABLE_MESSAGE_POOL=0:AllocateMessage(0)+Release()AllocateMessage(64)+Release()The cross-thread pipe case is dominated by lock contention in the pipe path and is within noise (runs ranged 271-314 before, 272-352 after). I haven't measured the UDP path, where allocation is a smaller share of the per-message cost.