package main
import "testing"
const N = 1615119
// It is strange that if N is large enough,
// the one line implementations are fast as the others.
// And if N is odd number, the InsertOneline_Disassemble
// implementation is about 10% faster than the others.
func init() {
println("==================== N =", N)
}
func InsertOneline(s []int, k int, vs ...int) []int {
return append(s[:k], append(vs, s[k:]...)...)
}
func InsertOneline_Disassemble(s []int, k int, vs ...int) []int {
z := append(vs, s[k:]...)
return append(s[:k], z...)
}
func InsertVerbose(s []int, k int, vs ...int) []int {
if n := len(s) + len(vs); n <= cap(s) {
s2 := s[:n]
copy(s2[k+len(vs):], s[k:])
copy(s2[k:], vs)
return s2
}
s2 := make([]int, len(s) + len(vs))
copy(s2, s[:k])
copy(s2[k:], vs)
copy(s2[k+len(vs):], s[k:])
return s2
}
func InsertVerbose_b(s []int, k int, vs ...int) []int {
if n := len(s) + len(vs); n <= cap(s) {
s2 := s[:n]
copy(s2[k+len(vs):], s[k:])
copy(s2[k:], vs)
return s2
}
s2 := make([]int, 0, len(s) + len(vs))
s2 = append(s2, s[:k]...)
s2 = append(s2, vs...)
s2 = append(s2, s[k:]...)
return s2
}
func InsertVerbose_c(s []int, k int, vs ...int) []int {
if n := len(s) + len(vs); n <= cap(s) {
s2 := s[:n]
copy(s2[k+len(vs):], s[k:])
copy(s2[k:], vs)
return s2
}
s2 := append([]int(nil), make([]int, len(s) + len(vs))...)[:0]
s2 = append(s2, s[:k]...)
s2 = append(s2, vs...)
s2 = append(s2, s[k:]...)
return s2
}
var s1 []int
func Benchmark_InsertOneline(b *testing.B) {
var x = make([]int, N)
var y = make([]int, N/2)
var k = N/5
b.ResetTimer()
for i := 0; i < b.N; i++ {
s1 = InsertOneline(x, k, y...)
}
}
var s1b []int
func Benchmark_InsertOneline_Disassemble(b *testing.B) {
var x = make([]int, N)
var y = make([]int, N/2)
var k = N/2
b.ResetTimer()
for i := 0; i < b.N; i++ {
s1b = InsertOneline_Disassemble(x, k, y...)
}
}
var s2 []int
func Benchmark_InsertVerbose(b *testing.B) {
var x = make([]int, N)
var y = make([]int, N/2)
var k = N/2
b.ResetTimer()
for i := 0; i < b.N; i++ {
s2 = InsertVerbose(x, k, y...)
}
}
var s3 []int
func Benchmark_InsertVerbose_b(b *testing.B) {
var x = make([]int, N)
var y = make([]int, N/2)
var k = N/2
b.ResetTimer()
for i := 0; i < b.N; i++ {
s3 = InsertVerbose_b(x, k, y...)
}
}
var s4 []int
func Benchmark_InsertVerbose_c(b *testing.B) {
var x = make([]int, N)
var y = make([]int, N/2)
var k = N/2
b.ResetTimer()
for i := 0; i < b.N; i++ {
s4 = InsertVerbose_c(x, k, y...)
}
}
The result:
$ go test -bench=. -benchtime=3s
==================== N = 1615119
goos: linux
goarch: amd64
pkg: a.y/bench/sliceinsert
cpu: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
Benchmark_InsertOneline-4 693 4741509 ns/op
Benchmark_InsertOneline_Disassemble-4 871 4194142 ns/op
Benchmark_InsertVerbose-4 764 4627334 ns/op
Benchmark_InsertVerbose_b-4 769 4958537 ns/op
Benchmark_InsertVerbose_c-4 661 4855514 ns/op