Skip to content

Fix swissmap size calculation by aligning with Go 1.24+ internal layout#153

Open
fsul7o wants to merge 7 commits intokpango:mainfrom
fsul7o:fix-swissmap-size
Open

Fix swissmap size calculation by aligning with Go 1.24+ internal layout#153
fsul7o wants to merge 7 commits intokpango:mainfrom
fsul7o:fix-swissmap-size

Conversation

@fsul7o
Copy link
Contributor

@fsul7o fsul7o commented Feb 25, 2026

Overview

mapSize for swissmap (map_size_swiss.go) produced wildly incorrect values (e.g. 2300377391887453521) after Go 1.24 made swissmap the default implementation.

The root cause was that the hmap struct mirrored the old bucket-based runtime.hmap layout instead of the new internal/runtime/maps.Map:

Field Old (wrong) offset Actual offset
B uint8 9 — (field does not exist)
dir unsafe.Pointer 16 16 (dirPtr)
dirLen uintptr 24 24

Reading h.B actually read byte 1 of the random seed uintptr field, causing (1 << h.B) * groupSize to overflow into astronomically large values.

changes

  • Rewrote hmap to correctly mirror internal/runtime/maps.Map (Go 1.24+): used, seed, dirPtr, dirLen, globalDepth, globalShift, writing, tombstonePossible, clearSeq.
  • Added tableHdr mirroring internal/runtime/maps.table, and groupsRef mirroring internal/runtime/maps.groupsReference.
  • Rewrote mapSize:
    • Small-map path: dirLen == 0dirPtr points directly to one group.
    • Large-map path: iterate the directory pointer array, deduplicate aliased table pointers, then for each unique table account for the tableHdr itself plus (lengthMask+1) × groupSize for the groups backing array.
    • Also accounts for the directory pointer array (dirLen × ptrSize).
  • Fixed slotSize calculation: added correct final slot alignment (alignUp(..., slotAlign)) which was missing for types like map[uint8]int64.

Operation check

Before fix

% go version
go version go1.25.4 darwin/arm64

% go run example/main.go
...

2026-02-25 08:11:28     [DEBG]: length: 0
2026-02-25 08:11:28     [DEBG]: Execution No.0       :  before set memory size: 20521, lenght: 0
2026-02-25 08:11:28     [DEBG]: Execution No.0       :  after set memory size: 14922195547313836769, lenght: 4096
2026-02-25 08:11:28     [DEBG]: Execution No.0       :  after delete memory size: 14922195547313804001, lenght: 0
2026-02-25 08:11:28     [DEBG]: Execution No.0       :  after gc memory size: 14922195547313804001, lenght: 0
2026-02-25 08:11:29     [DEBG]: Execution No.1000    :  before set memory size: 14922195547313804001, lenght: 0
2026-02-25 08:11:29     [DEBG]: Execution No.1000    :  after set memory size: 14922195547313836769, lenght: 4096
2026-02-25 08:11:29     [DEBG]: Execution No.1000    :  after delete memory size: 14922195547313804001, lenght: 0
2026-02-25 08:11:29     [DEBG]: Execution No.1000    :  after gc memory size: 14922195547313804001, lenght: 0
...

After fix

% go version
go version go1.25.4 darwin/arm64

% go run example/main.go
...

2026-02-25 14:18:30     [DEBG]: length: 0
2026-02-25 14:18:30     [DEBG]: Execution No.0       :  before set memory size: 20521, lenght: 0
2026-02-25 14:18:30     [DEBG]: Execution No.0       :  after set memory size: 333961, lenght: 4096
2026-02-25 14:18:30     [DEBG]: Execution No.0       :  after delete memory size: 301193, lenght: 0
2026-02-25 14:18:30     [DEBG]: Execution No.0       :  after gc memory size: 301193, lenght: 0
2026-02-25 14:18:31     [DEBG]: Execution No.1000    :  before set memory size: 301193, lenght: 0
2026-02-25 14:18:31     [DEBG]: Execution No.1000    :  after set memory size: 333961, lenght: 4096
2026-02-25 14:18:31     [DEBG]: Execution No.1000    :  after delete memory size: 301193, lenght: 0
2026-02-25 14:18:31     [DEBG]: Execution No.1000    :  after gc memory size: 301193, lenght: 0
...

…map implementation

Signed-off-by: fsul7o <75571344+fsul7o@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 25, 2026 14:20
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates mapSize for Go’s swissmap implementation by mirroring the Go 1.24+ internal/runtime/maps layouts so map memory-size estimation remains correct now that swissmap is the default.

Changes:

  • Replaces the old bucket-era hmap mirror with a maps.Map-aligned header and adds tableHdr / groupsRef mirrors for table/group sizing.
  • Rewrites swissmap sizing logic to handle small-map (dirLen == 0) vs directory-backed maps (dirLen > 0), including deduping aliased table pointers.
  • Adjusts slot sizing logic to account for final slot alignment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: fsul7o <75571344+fsul7o@users.noreply.github.com>
…viors

Signed-off-by: fsul7o <75571344+fsul7o@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

fsul7o and others added 4 commits February 26, 2026 12:02
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: fsul7o <75571344+fsul7o@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants