Use xxhash for composite checker keys instead of strings
Often when I see people's profiles, the top allocator is WriteByte, all from the checker building runtime map keys.
We stringify data to use as map keys for union types, intersection types, etc. In JS, this is cheap thanks to the "rope" optimization where the strings are never actually produced unless required (which does not include Map lookups!).
But in Go, this doesn't work so well because we do actually have to back strings with real fully-written memory, and it's not easy to do a lookup otherwise. There's no magic string type that can expand itself when read. A Go stdlib map that allows custom hashing/equality is seemingly not coming soon.
An alternative is to just hash the data and use that hash as a key. A while ago I had tried use sha256 to do this (like gopls does), but did not see much success. And, introducing crypto into the binary is a can of worms I don't want to open. So, I gave up on that idea.
We have since then added xxhash to our dependencies for incremental mode, the LSP, etc.
A 128-bit xxhash could be argued to have enough collision resistance; UUIDs are of course also 128-bit. What are the chances of a UUID-level collision happening within a single compile? 😅
This PR tries that out, swapping our key builder out for one that hashes the data as it comes in instead.
The effect seems pretty good. VS Code before:
Memory used: 3565146K
Memory allocs: 34630016
Config time: 0.130s
Parse time: 0.520s
Bind time: 0.097s
Check time: 6.276s
Emit time: 1.394s
Total time: 8.425s
And after:
Memory used: 3533519K
Memory allocs: 25587150
Config time: 0.132s
Parse time: 0.549s
Bind time: 0.085s
Check time: 6.136s
Emit time: 1.378s
Total time: 8.289s
The time in general seems unchanged, but with 35% fewer allocations.
Downside is of course that the map keys become unreadable and irreversible. Right now, they're only "unreadable" thanks to us making numbers into shorter strings. We could have a mode which preserves the data behind a build tag. Not sure about that.
Thankfully, these keys are never actually exposed through any API, so should be opaque enough.