Val,
That's a lot of speculation!
The original benchmark applies to the original question:
prefix := verylongstring[:3]
If we change the parameters of the benchmark then we expect to get different results. For example, read the Go gc compiler code. There's a stack/heap optimization for 32 bytes or less.
cmd/gc: allocate buffers for non-escaped strings on stack
commit e6fac08146df323eb95f46508bef937cdfb802fd
https://go.googlesource.com/go/+/e6fac08146df323eb95f46508bef937cdfb802fdhttps://go-review.googlesource.com/c/go/+/31203 byte prefix:
BenchmarkNil-4 10000000 173 ns/op 16 B/op 2 allocs/op
BenchmarkLiteral-4 10000000 171 ns/op 16 B/op 2 allocs/op
BenchmarkConvert-4 20000000 76.9 ns/op 3 B/op 1 allocs/op
BenchmarkCopy-4 20000000 67.1 ns/op 3 B/op 1 allocs/op
BenchmarkLoop-4 20000000 65.7 ns/op 3 B/op 1 allocs/op
32 byte prefix:
BenchmarkNil-4 5000000 235 ns/op 64 B/op 2 allocs/op
BenchmarkLiteral-4 10000000 232 ns/op 64 B/op 2 allocs/op
BenchmarkConvert-4 10000000 129 ns/op 32 B/op 1 allocs/op
BenchmarkCopy-4 10000000 118 ns/op 32 B/op 1 allocs/op
BenchmarkLoop-4 10000000 183 ns/op 32 B/op 1 allocs/op
33 byte prefix:
BenchmarkNil-4 5000000 295 ns/op 96 B/op 2 allocs/op
BenchmarkLiteral-4 5000000 285 ns/op 96 B/op 2 allocs/op
BenchmarkConvert-4 5000000 251 ns/op 96 B/op 2 allocs/op
BenchmarkCopy-4 10000000 143 ns/op 48 B/op 1 allocs/op
BenchmarkLoop-4 10000000 188 ns/op 48 B/op 1 allocs/op
256 byte prefix:
BenchmarkNil-4 2000000 661 ns/op 512 B/op 2 allocs/op
BenchmarkLiteral-4 2000000 665 ns/op 512 B/op 2 allocs/op
BenchmarkConvert-4 2000000 659 ns/op 512 B/op 2 allocs/op
BenchmarkCopy-4 5000000 369 ns/op 256 B/op 1 allocs/op
BenchmarkLoop-4 2000000 883 ns/op 256 B/op 1 allocs/op
$ go version
go version devel +33484a6 Tue Aug 22 08:09:42 2017 +0000 linux/amd64
$ go test -run=! -bench=. -benchmem strslice_test.go
goos: linux
goarch: amd64
$ cat strslice_test.go
package main
import (
"strings"
"testing"
)
const pfxLen = 3 // 3, 32, 33, 256
var (
s = strings.Repeat("a very, very long string", 4096)
prefix string
)
func BenchmarkNil(b *testing.B) {
for i := 0; i < b.N; i++ {
prefix = string(append([]byte(nil), s[:pfxLen]...))
}
}
func BenchmarkLiteral(b *testing.B) {
for i := 0; i < b.N; i++ {
prefix = string(append([]byte{}, s[:pfxLen]...))
}
}
func BenchmarkConvert(b *testing.B) {
for i := 0; i < b.N; i++ {
prefix = string([]byte(s[:pfxLen]))
}
}
func BenchmarkCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
buffer := make([]byte, pfxLen)
copy(buffer, s)
prefix = string(buffer)
}
}
func BenchmarkLoop(b *testing.B) {
for i := 0; i < b.N; i++ {
buffer := make([]byte, pfxLen)
for i := 0; i < len(buffer); i++ {
buffer[i] = s[i]
}
prefix = string(buffer)
}
}
$
Peter