Track logical quicklist memory incrementally via lpBytes + compressed size#4
Draft
Track logical quicklist memory incrementally via lpBytes + compressed size#4
Conversation
a365121 to
d4853aa
Compare
…on with objectComputeSize test Signed-off-by: Lior Sventitzky <liorsve@amazon.com>
d4853aa to
3320eb3
Compare
This was referenced Apr 12, 2026
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.
Summary
Add incremental memory tracking to quicklist via a single new field
tracked_data_byteson thequickliststruct. Tracks the sum of logical entry sizes across all nodes —node->sz(=lpBytes) for uncompressed nodes,sizeof(quicklistLZF) + lzf->szfor compressed nodes. No per-node fields added, no listpack changes, zerozmalloc_sizecalls.Structural overhead (
sizeof(quicklist) + ql->len * sizeof(quicklistNode)) is O(1)-computable from existing fields and not included intracked_data_bytes.Design
Based on the "lpBytes + compressed size tracking" approach. Four choke points maintain the running total:
__quicklistInsertNode— adds entry size when a node enters the list__quicklistDelNode— subtracts entry size when a node leavesquicklistNodeUpdateSzmacro — trackslpBytesdelta on in-place listpack mutations__quicklistCompressNode/__quicklistDecompressNode— swaps betweennode->szandsizeof(quicklistLZF) + lzf->szwhen compression state changesHelper macros
quicklistNodeEntryBytes(node)— returns logical entry size accounting for compression, used by insert/delete hooksquicklistNodeUpdateSz(ql, node)— updatesnode->szfromlpBytesand tracks delta; acceptsNULLforqlwhen node is not yet linkedquicklistNodeSetSz(ql, node, new_sz)— directszassignment with delta tracking, for the plain node replace pathChanges from the design plan
+= new_node->sz+= quicklistNodeEntryBytes(new_node)quicklistDupinserts already-compressed nodes —node->szis uncompressed size, but entry is an LZF buffer. Must check encoding.quicklistNodeUpdateSzNULLguard — always passesqlif (ql)guard, passNULLfor unlinked nodes_quicklistSplitNodequicklist *paramquicklistNodeUpdateSz(quicklist, node). New (unlinked) node needsquicklistNodeUpdateSz(NULL, new_node).quicklistNodeUpdateSz(NULL, new_node)before linkingnew_node->szwas 0 fromquicklistCreateNode(), never updated. Insert hook would add 0.tracked_data_bytesonly changes on the success path.Accuracy
Tracks logical sizes, not jemalloc allocation sizes. The gap vs
objectComputeSize(which useszmalloc_size) is jemalloc size-class rounding — consistently 1-10% for typical lists, with larger relative gaps only on very small lists where a single allocation's rounding dominates:Tracked value is always ≤ computed. Gap shrinks with list size (DeepCompressDepth: 1.7%, InterleavedCompressOps: 3.2%).
Files changed
size_t tracked_data_bytestoquickliststructquicklist *threaded through compress/decompress/split functions and 5 macrosTests
test_quicklist_tracking.cpp— Correctness tests. Walks the list after each operation and verifiestracked_data_bytes == Σ quicklistNodeEntryBytes(node)for all nodes. 28/28 pass. Covers:test_quicklist_tracking_vs_compute.cpp— Comparison tests. Same tests comparingsizeof(quicklist) + ql->len * sizeof(quicklistNode) + ql->tracked_data_bytesagainstobjectComputeSize. All 27 fail with the expected jemalloc rounding gap (see table above). These tests document the accuracy trade-off and serve as a regression baseline — they will pass if upgraded tolp_malloc_size-based tracking in the future.