diff options
| author | Cherry Mui <cherryyz@google.com> | 2025-10-24 12:04:44 -0400 |
|---|---|---|
| committer | Cherry Mui <cherryyz@google.com> | 2025-10-24 12:40:49 -0700 |
| commit | a26f860fa4fee16f77e0ed13eb8286168b3bf097 (patch) | |
| tree | d5aae44cd02487888d4e3c68e505e7217c8a311a /src/internal/runtime | |
| parent | 747fe2efedfdc43f797b4fc1672e29ff7a01ec6a (diff) | |
| download | go-a26f860fa4fee16f77e0ed13eb8286168b3bf097.tar.xz | |
runtime: use 32-bit hash for maps on Wasm
Currently we use 64-bit hash calculations on Wasm. The 64-bit hash
calculation make intensive uses of 64x64->128 bit multiplications,
which on many 64-bit platforms are compiler intrinsics and can be
compiled to one or two instructions. This is not the case on Wasm,
so it is not very performant.
This CL makes it use 32-bit hashes on Wasm, just like other 32-bit
architectures. The 32-bit hash calculation only uses 32x32->64 bit
multiplications, which can be compiled efficiently on Wasm.
Using 32-bit hashes may increase the chance of collisions. But it
is the same as 32-bit architectures like 386. And our Wasm port
supports only 32-bit address space (like 386), so this is not too
bad.
Runtime Hash benchmark results
goos: js
goarch: wasm
pkg: runtime
│ 0h.txt │ 1h.txt │
│ sec/op │ sec/op vs base │
Hash5 20.45n ± 9% 14.06n ± 2% -31.21% (p=0.000 n=10)
Hash16 22.34n ± 7% 17.52n ± 1% -21.62% (p=0.000 n=10)
Hash64 47.47n ± 3% 28.68n ± 1% -39.59% (p=0.000 n=10)
Hash1024 475.4n ± 1% 271.4n ± 0% -42.92% (p=0.000 n=10)
Hash65536 28.42µ ± 1% 16.66µ ± 0% -41.40% (p=0.000 n=10)
HashStringSpeed 40.07n ± 7% 29.23n ± 1% -27.05% (p=0.000 n=10)
HashBytesSpeed 62.01n ± 3% 46.11n ± 4% -25.64% (p=0.000 n=10)
HashInt32Speed 24.31n ± 2% 20.39n ± 1% -16.13% (p=0.000 n=10)
HashInt64Speed 25.48n ± 7% 20.81n ± 7% -18.29% (p=0.000 n=10)
HashStringArraySpeed 87.69n ± 4% 76.65n ± 2% -12.58% (p=0.000 n=10)
FastrandHashiter 87.65n ± 1% 87.65n ± 1% ~ (p=0.896 n=10)
geomean 90.82n 67.03n -26.19%
Map benchmarks are too many to post here. The speedups are around
0-40%.
Change-Id: I2f7a68cfc446ab5a547fdb6a40aea07854516d51
Reviewed-on: https://go-review.googlesource.com/c/go/+/714600
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/internal/runtime')
| -rw-r--r-- | src/internal/runtime/maps/map.go | 6 | ||||
| -rw-r--r-- | src/internal/runtime/maps/table.go | 3 |
2 files changed, 6 insertions, 3 deletions
diff --git a/src/internal/runtime/maps/map.go b/src/internal/runtime/maps/map.go index 865a3f36c2..515558a94f 100644 --- a/src/internal/runtime/maps/map.go +++ b/src/internal/runtime/maps/map.go @@ -245,8 +245,12 @@ type Map struct { clearSeq uint64 } +// Use 64-bit hash on 64-bit systems, except on Wasm, where we use +// 32-bit hash (see runtime/hash32.go). +const Use64BitHash = goarch.PtrSize == 8 && goarch.IsWasm == 0 + func depthToShift(depth uint8) uint8 { - if goarch.PtrSize == 4 { + if !Use64BitHash { return 32 - depth } return 64 - depth diff --git a/src/internal/runtime/maps/table.go b/src/internal/runtime/maps/table.go index d9bcf23dfa..fbce099655 100644 --- a/src/internal/runtime/maps/table.go +++ b/src/internal/runtime/maps/table.go @@ -6,7 +6,6 @@ package maps import ( "internal/abi" - "internal/goarch" "internal/runtime/math" "unsafe" ) @@ -1170,7 +1169,7 @@ func (t *table) rehash(typ *abi.MapType, m *Map) { // Bitmask for the last selection bit at this depth. func localDepthMask(localDepth uint8) uintptr { - if goarch.PtrSize == 4 { + if !Use64BitHash { return uintptr(1) << (32 - localDepth) } return uintptr(1) << (64 - localDepth) |
