Skip to content

size_t QuickVec and Appropriate BlockData Fields - #1402

Merged
Aidan63 merged 7 commits into
HaxeFoundation:masterfrom
Aidan63:quickvec_and_blockdata
Sep 22, 2026
Merged

Aidan63 merged 7 commits into
HaxeFoundation:masterfrom
Aidan63:quickvec_and_blockdata

Conversation

@Aidan63

@Aidan63 Aidan63 commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

This updates QuickVec to be based on size_t and updates the fields in the BlockData class to be "properly" sized. I didn't go with size_t for many of those fields as they can be much narrower. E.g. each block only has 256 lines (two of which are used for block metadata) and each line is 128 bytes long, so uint8_t and uint16_t are natural fits for this.

Comment thread include/hx/QuickVec.h
@Aidan63

Aidan63 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Merging since this new CI failure is also happening on master.

@Aidan63
Aidan63 merged commit 199b756 into HaxeFoundation:master Sep 22, 2026
144 of 145 checks passed
@Aidan63
Aidan63 deleted the quickvec_and_blockdata branch September 23, 2026 08:56
dimensionscape added a commit to dimensionscape/hxcpp that referenced this pull request Oct 2, 2026
"size_t QuickVec and Appropriate BlockData Fields" (HaxeFoundation#1402) made
BlockDataInfo's mUsedRows and mFraggedRows uint8_t. A block's row counts
run up to IMMIX_USEFUL_LINES, which is 254 with the default 32k blocks
but 508 with HXCPP_GC_BIG_BLOCKS, whose 64k blocks have 512 lines of
128 bytes. There the counts wrap: makeFull() and a full countRows()
store 508 as 252, reclaim() stores IMMIX_USEFUL_LINES - freeLines the
same way, countRows() never sees a full block as full, and a block with
256 used rows reads as empty. The rows-in-use total the collector sums
after each collection, and with it the working-memory target it sets,
comes out far below the live heap, so allocation runs a collection
almost every time it asks for a new block.

A program that builds 6M small live objects and then allocates 30M
short-lived ones takes about 0.4s with default blocks, and 15 to 20s
with big blocks (60 to 70s of CPU across the marking threads). With
this change it takes about 0.4s with either.

mUsedRows and mFraggedRows are uint16_t again, as is the allocator's
pointer to the fragmented-row count, and static_asserts check that both
can hold IMMIX_USEFUL_LINES, so narrowing them again fails the build.
The byte counts were fine: 508 lines of 128 bytes is 65024, which a
uint16_t holds.

(cherry picked from commit 50f1f61)
dimensionscape added a commit to dimensionscape/hxcpp that referenced this pull request Oct 2, 2026
HaxeFoundation#1402 made BlockDataInfo's mUsedRows and mFraggedRows uint8_t, which
fits the default 32k blocks (254 usable lines) but not big blocks
(508). With HXCPP_GC_BIG_BLOCKS the counts wrap, the GC underestimates
the live heap, and it ends up collecting on almost every new block.

Use uint16_t for both (and for the allocator's mFraggedRows pointer),
with static_asserts so they can't drop below IMMIX_USEFUL_LINES again.
dimensionscape added a commit to dimensionscape/hxcpp that referenced this pull request Oct 2, 2026
HaxeFoundation#1402 made BlockDataInfo's mUsedRows and mFraggedRows uint8_t, which
fits the default 32k blocks (254 usable lines) but not big blocks
(508). With HXCPP_GC_BIG_BLOCKS the counts wrap, the GC underestimates
the live heap, and it ends up collecting on almost every new block.

Use uint16_t for both (and for the allocator's mFraggedRows pointer),
with static_asserts so they can't drop below IMMIX_USEFUL_LINES again.

(cherry picked from commit 71bf02d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants