You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I write a program that need to previous append and tail append string to a []interface{}{}.
const (
tail = "tail"
)
func BenchmarkArroundHasHead(b *testing.B) {
head := "head assign to interface{} add one alloc"
benchmarkArround(b, &head)
}
func BenchmarkArroundHeadEmpty(b *testing.B) {
// empty head add to interface{} not add one alloc
head := ""
benchmarkArround(b, &head)
}
func BenchmarkArroundHeadNil(b *testing.B) {
benchmarkArround(b, nil)
}
func benchmarkArround(b *testing.B, head *string) {
a := []interface{}{"1", 2}
b.ResetTimer()
for n := 0; n < b.N; n++ {
aa := make([]interface{}, len(a)+2)
if head != nil {
aa[0] = *head
}
copy(aa[1:], a)
// const tail add to interface{} not add one alloc
aa[len(a)+1] = tail
}
}
What did you expect to see?
BenchmarkArroundHasHead-8 is 1 allocs/op.
What did you see instead?
BenchmarkArroundHasHead-8 is 2 allocs/op that make code slower.
The head is dynamic but able to make a complex process before exec Arround() method.
In other words, process head one time, use it forever.
Do we have some functions in reflect, unsafe or other packages that make the alloc not necessary? Or work as const? I see const not add one alloc, so I ask this question.
No, we don't have any way to optimize that away. An interface holds a single data pointer. To store a string in an interface it must be represented internally as a pointer to that string header. For string constants we have a string header in read-only memory, the address of which can be stored in the interface. For arbitrary strings, we need a new string header that won't be modified underfoot, and that means a string-header-sized allocation.
Of course, if you are converting the same string into an interface{} multiple times, you can store it into an interface{} once and reuse that interface value, cutting down to just one allocation before a loop instead of one inside a loop. If you changed the argument from head \*string to head interface{} the benchmark would stop allocating in the loop.
What version of Go are you using (
go version
)?go version go1.11.1 darwin/amd64
Does this issue reproduce with the latest release?
Not have a check.
What operating system and processor architecture are you using (
go env
)?GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/*/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/54/k5ygh9s15rzbjk3m1_4qmvy40000gn/T/go-build237216686=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
I write a program that need to previous append and tail append string to a
[]interface{}{}
.What did you expect to see?
BenchmarkArroundHasHead-8
is1 allocs/op
.What did you see instead?
BenchmarkArroundHasHead-8
is2 allocs/op
that make code slower.The head is dynamic but able to make a complex process before exec Arround() method.
In other words, process head one time, use it forever.
Do we have some functions in
reflect
,unsafe
or other packages that make the alloc not necessary? Or work as const? I see const not add one alloc, so I ask this question.Benchmark
The text was updated successfully, but these errors were encountered: