Skip to content

Instantly share code, notes, and snippets.

@ncdc
Last active November 4, 2021 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ncdc/65ca2bfdcd7ba56dc144f50937831a43 to your computer and use it in GitHub Desktop.
Save ncdc/65ca2bfdcd7ba56dc144f50937831a43 to your computer and use it in GitHub Desktop.
Go map benchmarks - string vs struct keys
package mapbenchmark
import (
"math/rand"
"strconv"
"testing"
)
type structKey struct {
one string
two string
}
const numKeys = 1000000
func BenchmarkStringKeyGet(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStringKeyGetInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStringKeyRange(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkStringKeyRangeInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkStringKeyPut(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
k = append(k, key)
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStringKeyPutInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
k = append(k, key)
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
func newStructKey(i int) structKey {
return structKey{
one: strconv.Itoa(i),
two: strconv.Itoa(i + 1),
}
}
func BenchmarkStructKeyGet(b *testing.B) {
b.ReportAllocs()
m := make(map[structKey]string)
k := make([]structKey, 0)
for i := 0; i < numKeys; i++ {
key := newStructKey(i)
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStructKeyGetIntefface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]structKey, 0)
for i := 0; i < numKeys; i++ {
key := newStructKey(i)
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStructKeyRange(b *testing.B) {
b.ReportAllocs()
m := make(map[structKey]string)
for i := 0; i < numKeys; i++ {
key := newStructKey(i)
m[key] = "value" + strconv.Itoa(i)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkStructKeyRangeInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
for i := 0; i < numKeys; i++ {
key := newStructKey(i)
m[key] = "value" + strconv.Itoa(i)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkStructKeyPut(b *testing.B) {
b.ReportAllocs()
m := make(map[structKey]string)
k := make([]structKey, 0)
for i := 0; i < numKeys; i++ {
k = append(k, newStructKey(i))
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
func BenchmarkStructKeyPutInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]structKey, 0)
for i := 0; i < numKeys; i++ {
k = append(k, newStructKey(i))
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
goos: darwin
goarch: amd64
pkg: map-key-benchmarks
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkStringKeyGet-12 10713081 112.0 ns/op 0 B/op 0 allocs/op
BenchmarkStringKeyGetInterface-12 6465774 186.3 ns/op 0 B/op 0 allocs/op
BenchmarkStringKeyRange-12 145 8210280 ns/op 0 B/op 0 allocs/op
BenchmarkStringKeyRangeInterface-12 147 8085765 ns/op 0 B/op 0 allocs/op
BenchmarkStringKeyPut-12 9652598 124.0 ns/op 8 B/op 0 allocs/op
BenchmarkStringKeyPutInterface-12 3594646 314.0 ns/op 38 B/op 1 allocs/op
BenchmarkStructKeyGet-12 9254334 132.2 ns/op 0 B/op 0 allocs/op
BenchmarkStructKeyGetIntefface-12 7211918 164.3 ns/op 0 B/op 0 allocs/op
BenchmarkStructKeyRange-12 69 17300422 ns/op 0 B/op 0 allocs/op
BenchmarkStructKeyRangeInterface-12 69 15344843 ns/op 0 B/op 0 allocs/op
BenchmarkStructKeyPut-12 4984252 227.1 ns/op 47 B/op 0 allocs/op
BenchmarkStructKeyPutInterface-12 2829900 359.4 ns/op 89 B/op 1 allocs/op
package stringkey
import (
"math/rand"
"strconv"
"strings"
"testing"
)
const numKeys = 1000000
func BenchmarkKeyGet(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.Logf("l=%d", l)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkKeyGetInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.Logf("l=%d", l)
b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, ok := m[k[i]]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkKeyRange(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
}
b.Logf("l=%d", len(m))
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkKeyRangeInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
}
b.Logf("l=%d", len(m))
b.ResetTimer()
for n := 0; n < b.N; n++ {
for kk, vv := range m {
_ = kk
_ = vv
}
}
}
func BenchmarkKeyPut(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
k = append(k, key)
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
func BenchmarkKeyPutInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys))
k = append(k, key)
}
i := 0
l := len(k)
b.ResetTimer()
for n := 0; n < b.N; n++ {
m[k[i]] = "value"
i++
if i >= l {
i = 0
}
}
}
func splitKey(key string) (string, string) {
parts := strings.Split(key, "/")
switch len(parts) {
case 1:
return "", parts[0]
case 2:
return parts[0], parts[1]
}
panic("invalid key")
}
func joinKey(namespace, name string) string {
if namespace != "" {
return namespace + "/" + name
}
return name
}
func BenchmarkControllerAccess(b *testing.B) {
b.ReportAllocs()
m := make(map[string]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys)) + "/" + strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.Logf("l=%d", l)
b.ResetTimer()
for n := 0; n < b.N; n++ {
key := k[i]
namespace, name := splitKey(key)
joined := joinKey(namespace, name)
if _, ok := m[joined]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
func BenchmarkControllerAccessInterface(b *testing.B) {
b.ReportAllocs()
m := make(map[interface{}]string)
k := make([]string, 0)
for i := 0; i < numKeys; i++ {
key := strconv.Itoa(rand.Intn(numKeys)) + "/" + strconv.Itoa(rand.Intn(numKeys))
m[key] = "value" + strconv.Itoa(i)
k = append(k, key)
}
i := 0
l := len(m)
b.Logf("l=%d", l)
b.ResetTimer()
for n := 0; n < b.N; n++ {
key := k[i]
namespace, name := splitKey(key)
joined := joinKey(namespace, name)
if _, ok := m[joined]; !ok {
b.FailNow()
}
i++
if i >= l {
i = 0
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment