After profiling a project I've been working on for a while, I noticed that I was seeing a number of calls to runtime.cmpstring from the following function:
func (po PtrObject) Get(key string) (v TypedValue, ok bool) {
switch key {
case ".ptr":
return NewPointer(po.Ptr), true
case ".owner":
return NewPrincipal(po.Owner), true
case ".ltime":
return NewInt(int(po.Ltime)), true
case ".anonymity":
return NewInt(int(po.Anonymity)), true
}
v, ok = po.Data[key]
return
}
This struck me as odd, because as far as I can tell, it should only be using runtime.eqstring and runtime.mapaccess2_faststr (both of which also show up in the profile).
$ cat main_test.go
package main
import (
"fmt"
"testing"
)
var words = []string{"super", "califragi", "listic", "expiali", "docius"}
var wlen = len(words)
func BenchmarkSwitch(b *testing.B) {
m := 0
for i := 0; i < b.N; i++ {
switch words[i%wlen] {
case "super":
m++
case "califragi":
m++
case "listic":
m++
case "expiali":
m++
case "docius":
m++
}
}
fmt.Println(m)
}
func BenchmarkIf(b *testing.B) {
m := 0
for i := 0; i < b.N; i++ {
w := words[i%wlen]
if w == "super" {
m++
} else if w == "califragi" {
m++
} else if w == "listic" {
m++
} else if w == "expiali" {
m++
} else if w == "docius" {
m++
}
}
fmt.Println(m)
}
I would think the performance of these two should be nearly identical, but I consistently see the if version outperform the switch version:
$ go test -bench . -benchtime 30s
BenchmarkSwitch 1
100
10000
1000000
100000000
2000000000
2000000000 29.2 ns/op
BenchmarkIf 1
100
10000
1000000
100000000
2000000000
2000000000 22.9 ns/op
ok x 109.375s
Does anyone know why the if would outperform the switch in this case? Could it be that switch uses cmpstring instead of eqstring? I was unable to get a non-empty profile from these benchmarks, so I can't verify..
Cheers,
Jon