-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: Swiss Table maps can double size multiple times when deleting/adding elements #70886
Comments
Related Issues
Related Code Changes (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
(Ah, after stepping away, I realized my mistake with |
The rationale for leaving this as a TODO and not immediately adding a same size grow is that growth should be logarithmic. Each time the map grows from tombstones it gets harder and harder to create enough tombstones to grow again. Luckily your test seems to agree with this. While I think we'll want same size grow eventually, IMO 100M iterations to grow from 128 to 1024 is not that bad. Or rather, it seems unlikely to cause significant problems in a real production application. But its definitely good to keep this open for reports if folks do run into issues. |
Hi @prattmic, it does indeed get harder and harder, and it makes sense to have the focus be on real-world apps (including my understanding is that you've already seen the new code running very successfully against real-world apps). Regarding the 100M loop example growing from 128 slots to 1024 slots, I'll just briefly note that for that one, I happened to pick a very low load of around 10% as the starting point. If I do the same experiment starting at a table size of 128 but start instead at a ~43% load (which could hypothetically be just after a "natural" grow) or at ~87% load (just before a grow), then it takes around 100K loops and 10K loops respectively to have the tombstones push it from a 128 table size to 1024:
(I don't think that's a surprise result either -- higher starting load means the tombstones need to do less at the start to get their first grow). In any event, makes sense to see how this compares against other possible future refinements. Thanks for taking a look! |
Go version
go version go1.24rc1
Output of
go env
in your module/workspace:What did you do?
When repeatedly deleting and adding elements from a Swiss Table map but without increasing the count of elements, the map can grow multiple times (e.g., from 128 slots to 1024 slots in a ~30s test).
I think there is currently a simplification in the current implementation (compared to Abseil and the CockroachDB implementations) such that it is expected that some growth occurs in lieu of a same-sized grow or rehashing in place, but it seemed worth a tracking bug that tables can end up growing substantially larger.
Here's a sample test demonstrating this:
https://go.dev/play/p/RITVDebV5op?v=gotip
It's runnable on the playground, where it sometimes fails or passes, though the main intent is to run locally.
Using that test, here's a sample run that starts with a ~10% load (14 elements in a map with an underlying table size of 128), then loops 1M times deleting and adding a different element (while never going above 14 elements in the map). The map's underlying table grows from 128 slots to 512 slots while doing that delete/add cycle 1M times:
Those results above include using a minor hack into the runtime to report the underlying table size and print when tables grow.
If we instead loop 100M times on that same test, the map grows from 128 table slots to 1024 table slots:
If we just loop, say, 100 times, the table does not grow, as expected:
One note of caution regarding the accuracy of this as a bug report -- test pass/failure here is being reported using testing.AllocsPerRun to see if an alloc occurs, but either I'm holding it wrong or seems to be flakey or both. (I was purposefully not using a more conventional runs number like 100, but maybe that's a mistake).
CC @prattmic
What did you see happen?
8x memory used.
What did you expect to see?
Less than 8x. Using an extra ~2x memory might be OK as a near-term simplification, but 8x seems high, and the memory can grow further.
The text was updated successfully, but these errors were encountered: