Skip to content

Commit c70dfaf

Browse files
committed
so/maps: fix initial size calc
1 parent 10738cc commit c70dfaf

5 files changed

Lines changed: 66 additions & 7 deletions

File tree

bench/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,21 @@ So's built-in map is faster than Go's, but I wouldn't call it the winner because
4646

4747
| Benchmark | Go | So (mimalloc) | So (arena) | So (built-in) | Winner |
4848
| --------- | ------: | ------------: | ---------: | ------------: | ------------- |
49-
| Set | 35580ns | 56696ns | 57661ns | 3242ns | Go - 0.6x |
49+
| Set | 35580ns | 56696ns | 57661ns | n/a | Go - 0.6x |
50+
| Set (pre) | 9608ns | 8821ns | 8767ns | 3242ns | ~same |
5051
| Get | 5573ns | 1638ns | 1583ns | 2733ns | **So** - 3.4x |
5152
| Delete | 23892ns | 38556ns | 38821ns | n/a | Go - 0.6x |
5253

5354
### String keys
5455

5556
So lookups are on par with Go, while modifications are 1.5x slower.
5657

57-
| Benchmark | Go | So (mimalloc) | So (arena) | So (built-in) | Winner |
58-
| --------- | ------: | ------------: | ---------: | ------------: | --------- |
59-
| Set | 48677ns | 71879ns | 63500ns | 6970ns | Go - 0.7x |
60-
| Get | 8990ns | 10206ns | 10083ns | 10735ns | Go - 0.9x |
61-
| Delete | 33878ns | 50111ns | 49507ns | n/a | Go - 0.7x |
58+
| Benchmark | Go | So (mimalloc) | So (arena) | So (built-in) | Winner |
59+
| --------- | ------: | ------------: | ---------: | ------------: | ------------- |
60+
| Set | 48677ns | 71879ns | 63500ns | n/a | Go - 0.7x |
61+
| Set (pre) | 14620ns | 12313ns | 12115ns | 6970ns | **So** - 1.2x |
62+
| Get | 8990ns | 10206ns | 10083ns | 10735ns | Go - 0.9x |
63+
| Delete | 33878ns | 50111ns | 49507ns | n/a | Go - 0.7x |
6264

6365
Apple M1 • Go 1.26.1 • [details](./maps/README.md)
6466

bench/maps/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ pkg: solod.dev/bench/maps
1717
cpu: Apple M1
1818
1919
Benchmark_IntSet-8 31677 35580 ns/op 74264 B/op 20 allocs/op
20+
Benchmark_IntPre-8 124159 9608 ns/op 36944 B/op 5 allocs/op
2021
Benchmark_IntGet-8 218179 5573 ns/op 0 B/op 0 allocs/op
2122
Benchmark_IntDel-8 50260 23892 ns/op 36944 B/op 5 allocs/op
2223
2324
Benchmark_StrSet-8 24082 48677 ns/op 108760 B/op 20 allocs/op
25+
Benchmark_StrPre-8 80437 14620 ns/op 54608 B/op 5 allocs/op
2426
Benchmark_StrGet-8 134481 8990 ns/op 0 B/op 0 allocs/op
2527
Benchmark_StrDel-8 34094 33878 ns/op 54608 B/op 5 allocs/op
2628
```
@@ -29,10 +31,12 @@ So (mimalloc):
2931

3032
```text
3133
Benchmark_IntSet 20305 56696 ns/op 98112 B/op 27 allocs/op
34+
Benchmark_IntPre 137866 8821 ns/op 49152 B/op 3 allocs/op
3235
Benchmark_IntGet 734978 1638 ns/op 0 B/op 0 allocs/op
3336
Benchmark_IntDel 30958 38556 ns/op 73728 B/op 6 allocs/op
3437
3538
Benchmark_StrSet 18986 71879 ns/op 130816 B/op 27 allocs/op
39+
Benchmark_StrPre 97383 12313 ns/op 65536 B/op 3 allocs/op
3640
Benchmark_StrGet 117218 10206 ns/op 0 B/op 0 allocs/op
3741
Benchmark_StrDel 23670 50111 ns/op 98304 B/op 6 allocs/op
3842
```
@@ -41,10 +45,12 @@ So (arena):
4145

4246
```text
4347
Benchmark_IntSet 21157 57661 ns/op 98112 B/op 27 allocs/op
48+
Benchmark_IntPre 137257 8767 ns/op 49152 B/op 3 allocs/op
4449
Benchmark_IntGet 752787 1583 ns/op 0 B/op 0 allocs/op
4550
Benchmark_IntDel 30339 38821 ns/op 73728 B/op 6 allocs/op
4651
4752
Benchmark_StrSet 18884 63500 ns/op 130816 B/op 27 allocs/op
53+
Benchmark_StrPre 99547 12115 ns/op 65536 B/op 3 allocs/op
4854
Benchmark_StrGet 119041 10083 ns/op 0 B/op 0 allocs/op
4955
Benchmark_StrDel 24212 49507 ns/op 98304 B/op 6 allocs/op
5056
```

bench/maps/bench.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ func StdIntSet(b *testing.B) {
5454
}
5555
}
5656

57+
func StdIntPre(b *testing.B) {
58+
a := b.Allocator()
59+
for b.Loop() {
60+
m := maps.New[int, int](a, nKeys)
61+
for i := range nKeys {
62+
m.Set(i, i)
63+
}
64+
m.Free()
65+
if arena != nil {
66+
arena.Reset()
67+
}
68+
}
69+
}
70+
5771
func StdIntGet(b *testing.B) {
5872
m := maps.New[int, int](nil, nKeys)
5973
for i := range nKeys {
@@ -98,6 +112,20 @@ func StdStrSet(b *testing.B) {
98112
}
99113
}
100114

115+
func StdStrPre(b *testing.B) {
116+
a := b.Allocator()
117+
for b.Loop() {
118+
m := maps.New[string, int](a, nKeys)
119+
for i := range nKeys {
120+
m.Set(strKeys[i], i)
121+
}
122+
m.Free()
123+
if arena != nil {
124+
arena.Reset()
125+
}
126+
}
127+
}
128+
101129
func StdStrGet(b *testing.B) {
102130
m := maps.New[string, int](nil, nKeys)
103131
for i := range nKeys {
@@ -186,9 +214,11 @@ func main() {
186214

187215
benchs := []testing.Benchmark{
188216
{Name: "IntSet", F: StdIntSet},
217+
{Name: "IntPre", F: StdIntPre},
189218
{Name: "IntGet", F: StdIntGet},
190219
{Name: "IntDel", F: StdIntDel},
191220
{Name: "StrSet", F: StdStrSet},
221+
{Name: "StrPre", F: StdStrPre},
192222
{Name: "StrGet", F: StdStrGet},
193223
{Name: "StrDel", F: StdStrDel},
194224
}

bench/maps/bench_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ func Benchmark_IntSet(b *testing.B) {
2121
}
2222
}
2323

24+
func Benchmark_IntPre(b *testing.B) {
25+
b.ReportAllocs()
26+
for b.Loop() {
27+
m := make(map[int]int, nKeys)
28+
for i := range nKeys {
29+
m[i] = i
30+
}
31+
}
32+
}
33+
2434
func Benchmark_IntGet(b *testing.B) {
2535
b.ReportAllocs()
2636
m := make(map[int]int, nKeys)
@@ -57,6 +67,16 @@ func Benchmark_StrSet(b *testing.B) {
5767
}
5868
}
5969

70+
func Benchmark_StrPre(b *testing.B) {
71+
b.ReportAllocs()
72+
for b.Loop() {
73+
m := make(map[string]int, nKeys)
74+
for i := range nKeys {
75+
m[strKeys[i]] = i
76+
}
77+
}
78+
}
79+
6080
func Benchmark_StrGet(b *testing.B) {
6181
b.ReportAllocs()
6282
m := make(map[string]int, nKeys)

so/maps/bytemap.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ type ByteMap struct {
5151
func NewByteMap(a mem.Allocator, size, ksize, vsize int) ByteMap {
5252
m := ByteMap{a: a, ksize: ksize, vsize: vsize, seed: seed()}
5353
sz := 8
54-
for sz < size {
54+
// The map must be large enough to hold size entries without resizing.
55+
for int(float64(sz)*loadFactor) < size {
5556
sz *= 2
5657
}
5758
m.hdib = mem.AllocSlice[uint64](m.a, sz, sz)

0 commit comments

Comments
 (0)