Repository navigation
Presize object and array literals from compiler size hints - #496
Merged
Merged
Conversation
Every object got a json-c table of 16 entries, 40 bytes each on 64-bit,
however few keys it held. The compiler already emits the number of
plain keys of a literal as the operand of I_NOBJ, but the VM ignored it.
Size a literal's table from that count, so a schema or config table of
small objects no longer costs about 700 bytes per object. Spreads are not
counted; an object filled by spreading grows as before, and an empty
literal keeps the 16 entries of ucv_object_new().
Measured with a script building 200000 3-key objects, 50000 20-key
objects, 50000 objects using spread plus a computed key and 50000 empty
literals:
Case Count
3-key objects 200000
20-key objects 50000
spread plus computed key 50000
{} 50000
Peak RSS Time
Before 359452 KB 0.52 s
After 253180 KB 0.47 s
Signed-off-by: John Crispin <john@phrozen.org>
[derive table size from LH_LOAD_FACTOR, add measurements]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Array entry vectors share the generic uc_vector growth policy, which starts at 8 slots and grows by 1.5x. As the capacity is derived from the element count, a literal such as [1, 2, 3] or an array receiving its first push is backed by 8 slots (64 bytes on 64-bit) regardless of how few elements it holds. Add init-size aware variants of the extend and reduce helpers and use them for arrays with an initial size of 2, giving the capacity steps 2, 3, 4, 6, 9, 13, 19, ... The existing uc_vector_extend(), _reduce() and _grow() helpers keep their 8 slot default, so all other vectors behave as before. The uc_array_t layout and the exported API are unchanged. Peak RSS for 200000 arrays of the given length, before and after: Elements Before After 1 32444 KB 22296 KB 3 32376 KB 24608 KB 5 32456 KB 28936 KB 7 32424 KB 31332 KB 8 38268 KB 31100 KB 12 48060 KB 37692 KB 20 60732 KB 62648 KB A mix of 1, 3, 5, 8 and 12 element literals drops from 99192 KB to 71400 KB, and an empty array receiving a single push from 32288 KB to 22792 KB, with no measurable slowdown. Arrays of about 20 elements grow by roughly 3%. Note that the array capacity invariant now differs from modules built against older headers: such a module growing array->entries directly through the uc_vector_*() macros, instead of ucv_array_push() or ucv_array_set(), would assume 8 slots as the minimum. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
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.
Presize the backing storage of object and array literals from the size hints the compiler already emits.
This supersedes the yet unmerged remainder of #493: the object literal sizing commit from there (44bb9d4) is included here in reworked form, so it can be dropped from #493.
Commits
I_NOBJoperand instead of always using 16 entries. The table size is derived fromLH_LOAD_FACTOR, so small literals no longer rehash right after creation. The commit message now carries measurements.I_NARR's hint was already used but rounded up to the generic 8, 12, 18, ... steps. Arrays now use an initial size of 2 (2, 3, 4, 6, 9, 13, 19, ...) via new init-size aware vector helpers; all other vectors keep the default of 8.uc_array_tand the exported API are unchanged.Measurements
Peak RSS, current master vs. this branch:
{}No measurable slowdown. Arrays of around 20 elements grow by about 3%. The custom test suite (268 tests) passes, and the process total for its 723 test processes moves by only -0.45%, as those scripts are tiny and dominated by startup.
Compatibility note
A module built against older headers that grows
array->entriesdirectly through theuc_vector_*macros, instead ofucv_array_push()/ucv_array_set(), would assume 8 slots as the minimum for arrays. Nothing in-tree does this.🤖 Generated with Claude Code