Skip to content

Commit

Permalink
Speed up built-in string hash function (#106)
Browse files Browse the repository at this point in the history
  • Loading branch information
puzpuzpuz authored Sep 26, 2023
1 parent ace0f0f commit c3b5020
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-32-bit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.20.x]
go-version: [1.21.x]
name: Build with Go ${{ matrix.go-version }} 32-bit
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.20.x]
go-version: [1.21.x]
name: Build with Go ${{ matrix.go-version }}
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.20.x]
go-version: [1.21.x]
name: Build with Go ${{ matrix.go-version }}
steps:
- uses: actions/checkout@v3
Expand Down
6 changes: 6 additions & 0 deletions export_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package xsync

import "hash/maphash"

const (
EntriesPerMapBucket = entriesPerMapBucket
MapLoadFactor = mapLoadFactor
Expand Down Expand Up @@ -48,6 +50,10 @@ func DisableAssertions() {
assertionsEnabled = false
}

func HashString(seed maphash.Seed, s string) uint64 {
return hashString(seed, s)
}

func Fastrand() uint32 {
return fastrand()
}
Expand Down
16 changes: 12 additions & 4 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package xsync

import (
"hash/maphash"
"reflect"
"runtime"
"unsafe"
_ "unsafe"
)

Expand Down Expand Up @@ -44,12 +46,18 @@ func parallelism() uint32 {

// hashString calculates a hash of s with the given seed.
func hashString(seed maphash.Seed, s string) uint64 {
var h maphash.Hash
h.SetSeed(seed)
h.WriteString(s)
return h.Sum64()
seed64 := *(*uint64)(unsafe.Pointer(&seed))
if s == "" {
return seed64
}
strh := (*reflect.StringHeader)(unsafe.Pointer(&s))
return uint64(memhash(unsafe.Pointer(strh.Data), uintptr(seed64), uintptr(strh.Len)))
}

//go:noescape
//go:linkname memhash runtime.memhash
func memhash(p unsafe.Pointer, h, s uintptr) uintptr

//go:noescape
//go:linkname fastrand runtime.fastrand
func fastrand() uint32
25 changes: 24 additions & 1 deletion util_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package xsync_test

import (
"hash/maphash"
"math/rand"
"testing"

Expand All @@ -25,7 +26,7 @@ func TestNextPowOf2(t *testing.T) {
// This test is here to catch potential problems
// with fastrand-related changes.
func TestFastrand(t *testing.T) {
count := 10000
count := 100
set := make(map[uint32]struct{}, count)

for i := 0; i < count; i++ {
Expand All @@ -51,3 +52,25 @@ func BenchmarkRand(b *testing.B) {
}
// about 12 ns/op on x86-64
}

func BenchmarkMapHashString(b *testing.B) {
fn := func(seed maphash.Seed, s string) uint64 {
var h maphash.Hash
h.SetSeed(seed)
h.WriteString(s)
return h.Sum64()
}
seed := maphash.MakeSeed()
for i := 0; i < b.N; i++ {
_ = fn(seed, benchmarkKeyPrefix)
}
// about 13ns/op on x86-64
}

func BenchmarkHashString(b *testing.B) {
seed := maphash.MakeSeed()
for i := 0; i < b.N; i++ {
_ = HashString(seed, benchmarkKeyPrefix)
}
// about 4ns/op on x86-64
}

0 comments on commit c3b5020

Please sign in to comment.