Repository navigation
perf: Provide ThinMap, a map that uses ThinVec when the length is small - #23228
Conversation
9fed540 to
2f73e51
Compare
This comment has been minimized.
This comment has been minimized.
2f73e51 to
4a439c7
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
4a439c7 to
c0230be
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
c0230be to
534ed04
Compare
This comment has been minimized.
This comment has been minimized.
| // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map | ||
| // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected). | ||
| expr_map: FxHashMap<ExprSource, ExprOrPatIdPacked>, | ||
| expr_map: ThinFxHashMap<ExprSource, ExprOrPatIdPacked>, |
There was a problem hiding this comment.
I would expect this one to contain quite a lot of elements on average?
There was a problem hiding this comment.
I think it's not because of anon consts. I do not know for sure but I did only replace when I have data to back it.
|
|
||
| types_map_back: ArenaMap<TypeRefId, TypeSource>, | ||
| types_map: FxHashMap<TypeSource, TypeRefId>, | ||
| types_map: ThinFxHashMap<TypeSource, TypeRefId>, |
| @@ -119,15 +118,15 @@ struct ExpressionOnlyStore { | |||
| labels: Arena<Label>, | |||
There was a problem hiding this comment.
A related change I've been wanting to look into has been splitting Arena into a "live" and "finalized" Arena (backed by Vec or Box<[T]> respectively), as almost all if not all arena uses we have are actually never touched again after construction
There was a problem hiding this comment.
This I investigated in the past and it didn't save much memory (HashMap is a lot more bytes on the stack than 1 usize) and it's also much more complicated because it needs a builder. You closed that issue after that.
This comment has been minimized.
This comment has been minimized.
It saves memory by being only one machine word inline and compact (no extra capacity) outline, while also being even faster if the length is commonly small because linear search is faster for small lengths. When measuring `analysis-stats`, this saves 40mb on self, 77mb on buck2 and 142mb on omicron. It's also *faster*: 3ginstructions saved on self and buck2, and 30ginstructions on omicron (walltime is too noisy). The memory effect is also likely to appear in IDE scenarios almost as well, because a major part is def maps, and I speculate that unnamed consts also play a role (because the amount of almost-empty expression stores seem too high for real bodies). Not all maps were changed to use this, only those that measurements show are commonly small. The threshold was at least ~95% of the maps of this kind fitting into the thin schema (that is, have at most 10 elements). I also switched some `IndexMap`s to `HashMap`s where I believe the order does not matter.
534ed04 to
8a1c6d9
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
It saves memory by being only one machine word inline and compact (no extra capacity) outline, while also being even faster if the length is commonly small because linear search is faster for small lengths.
When measuring
analysis-stats, this saves 40mb on self, 77mb on buck2 and 142mb on omicron. It's also faster: 3ginstructions saved on self and buck2, and 30ginstructions on omicron (walltime is too noisy). The memory effect is also likely to appear in IDE scenarios almost as well, because a major part is def maps, and I speculate that unnamed consts also play a role (because the amount of almost-empty expression stores seem too high for real bodies).Not all maps were changed to use this, only those that measurements show are commonly small. The threshold was at least ~95% of the maps of this kind fitting into the thin schema (that is, have at most 10 elements).
I also switched some
IndexMaps toHashMaps where I believe the order does not matter.I made
ThinMapgeneric over the map type to support bothHashMapandIndexMap. However at the end the number ofIndexMaps was very small. I still can support both, but I wonder if I should or just make it non-generic and simplify the code. Currently I left it neither supportingIndexMaps nor removing the trait; will appreciate opinions.ThinMap(andThinSet) could very well be in their own crate, I just found no suitable crate on crates.io (also, the API isn't polished enough for an external crate).