Skip to content

Instantly share code, notes, and snippets.

@hugefiver
Last active August 13, 2021 08:08
Show Gist options
  • Save hugefiver/810b42f5449f300b35301d90ae520a43 to your computer and use it in GitHub Desktop.
Save hugefiver/810b42f5449f300b35301d90ae520a43 to your computer and use it in GitHub Desktop.
package main
import (
"math/rand"
"testing"
)
const Max = 100_0000
const Offset = 100
func BenchmarkSliceCopySame(b *testing.B) {
a := []int{}
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(a, a[:Max])
}
}
func BenchmarkSliceCopy(b *testing.B) {
a := []int{}
c := make([]int, Max)
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(c, a[:Max])
}
}
func BenchmarkSliceCopySameOffset(b *testing.B) {
a := []int{}
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(a[Offset:], a[:Max-Offset])
}
}
func BenchmarkSliceCopyOffset(b *testing.B) {
a := []int{}
c := make([]int, Max)
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
copy(c[Offset:], a[:Max-Offset])
}
}
func BenchmarkSliceCopySameAppend(b *testing.B) {
a := []int{}
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
a = append(a[:0], a[:Max]...)
}
}
func BenchmarkSliceCopyAppend(b *testing.B) {
a := []int{}
c := make([]int, Max)
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
a = append(c[:0], a[:Max]...)
}
}
func BenchmarkSliceCopySameAppendOffset(b *testing.B) {
a := []int{}
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
a = append(a[:Offset], a[:Max-Offset]...)
}
}
func BenchmarkSliceCopyAppendOffset(b *testing.B) {
a := []int{}
c := make([]int, Max)
for i := 0; i < Max; i++ {
a = append(a, rand.Int())
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
a = append(c[:Offset], a[:Max-Offset]...)
}
}
@hugefiver
Copy link
Author

image

@hugefiver
Copy link
Author

func BenchmarkSliceCopySame(b *testing.B) {
	a := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		copy(a, a[:Max])
	}
}

func BenchmarkSliceCopy(b *testing.B) {
	a := make([]struct{}, Max)
	c := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		copy(c, a[:Max])
	}
}

func BenchmarkSliceCopySameOffset(b *testing.B) {
	a := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		copy(a[Offset:], a[:Max-Offset])
	}
}

func BenchmarkSliceCopyOffset(b *testing.B) {
	a := make([]struct{}, Max)
	c := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		copy(c[Offset:], a[:Max-Offset])
	}
}

func BenchmarkSliceCopySameAppend(b *testing.B) {
	a := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		a = append(a[:0], a[:Max]...)
	}
}

func BenchmarkSliceCopyAppend(b *testing.B) {
	a := make([]struct{}, Max)
	c := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		a = append(c[:0], a[:Max]...)
	}
}

func BenchmarkSliceCopySameAppendOffset(b *testing.B) {
	a := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		a = append(a[:Offset], a[:Max-Offset]...)
	}
}

func BenchmarkSliceCopyAppendOffset(b *testing.B) {
	a := make([]struct{}, Max)
	c := make([]struct{}, Max)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		a = append(c[:Offset], a[:Max-Offset]...)
	}
}

image

See source

// slicecopy is used to copy from a string or slice of pointerless elements into a slice.
func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
	if fromLen == 0 || toLen == 0 {
		return 0
	}

	n := fromLen
	if toLen < n {
		n = toLen
	}

	if width == 0 {
		return n
	}

	size := uintptr(n) * width
	if raceenabled {
		callerpc := getcallerpc()
		pc := abi.FuncPCABIInternal(slicecopy)
		racereadrangepc(fromPtr, size, callerpc, pc)
		racewriterangepc(toPtr, size, callerpc, pc)
	}
	if msanenabled {
		msanread(fromPtr, size)
		msanwrite(toPtr, size)
	}

	if size == 1 { // common case worth about 2x to do here
		// TODO: is this still worth it with new memmove impl?
		*(*byte)(toPtr) = *(*byte)(fromPtr) // known to be a byte pointer
	} else {
		memmove(toPtr, fromPtr, size)
	}
	return n
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment