Skip to content

cmd/compile: treat "d = append(make([]T, 0, len(s)), s...)" as "d = make([]T, len(s)); copy(d, s)" #46079

@zigo101

Description

@zigo101

What version of Go are you using (go version)?

$ go version
go version go1.16.3 linux/amd64

Does this issue reproduce with the latest release?

Yes.

What did you do?

package main

import (
	"testing"
)

type T = int

var sMakeCopy128 []T
func Benchmark_MakeCopy_128(b *testing.B) {
	s := make([]T, 128)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeCopy128 = make([]T, len(s))
		copy(sMakeCopy128, s)
	}
}

var sMakeAppend128 []T
func Benchmark_MakeAppend_128(b *testing.B) {
	s := make([]T, 128)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeAppend128 = append(make([]T, 0, len(s)), s...)
	}
}

var sMakeCopy1024 []T
func Benchmark_MakeCopy_1024(b *testing.B) {
	s := make([]T, 1024)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeCopy1024 = make([]T, len(s))
		copy(sMakeCopy1024, s)
	}
}

var sMakeAppend1024 []T
func Benchmark_MakeAppend_1024(b *testing.B) {
	s := make([]T, 1024)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeAppend1024 = append(make([]T, 0, len(s)), s...)
	}
}

var sMakeCopy8192 []T
func Benchmark_MakeCopy_8192(b *testing.B) {
	s := make([]T, 8192)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeCopy8192 = make([]T, len(s))
		copy(sMakeCopy8192, s)
	}
}

var sMakeAppend8192 []T
func Benchmark_MakeAppend_8192(b *testing.B) {
	s := make([]T, 8192)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeAppend8192 = append(make([]T, 0, len(s)), s...)
	}
}

var sMakeCopy65536 []T
func Benchmark_MakeCopy_65536(b *testing.B) {
	s := make([]T, 65536)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeCopy65536 = make([]T, len(s))
		copy(sMakeCopy65536, s)
	}
}

var sMakeAppend65536 []T
func Benchmark_MakeAppend_65536(b *testing.B) {
	s := make([]T, 65536)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		sMakeAppend65536 = append(make([]T, 0, len(s)), s...)
	}
}

What did you expect to see?

No performance difference between the two ways.

What did you see instead?

The larger the length of the slices, the bigger performance difference between the two.

$ go test -bench=. -benchmem -benchtime=3s
goos: linux
goarch: amd64
pkg: a.b/c/ttt
cpu: Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
Benchmark_MakeCopy_128-4       	14257712	       254.3 ns/op	    1024 B/op	       1 allocs/op
Benchmark_MakeAppend_128-4     	13141005	       268.5 ns/op	    1024 B/op	       1 allocs/op
Benchmark_MakeCopy_1024-4      	 1885544	      1928 ns/op	    8192 B/op	       1 allocs/op
Benchmark_MakeAppend_1024-4    	 1663520	      2369 ns/op	    8192 B/op	       1 allocs/op
Benchmark_MakeCopy_8192-4      	  268628	     14040 ns/op	   65536 B/op	       1 allocs/op
Benchmark_MakeAppend_8192-4    	  196272	     18757 ns/op	   65536 B/op	       1 allocs/op
Benchmark_MakeCopy_65536-4     	   36700	    100680 ns/op	  524291 B/op	       1 allocs/op
Benchmark_MakeAppend_65536-4   	   24723	    136324 ns/op	  524288 B/op	       1 allocs/op

[Edit]: it looks the allocated bytes/op is the not same for the last two benchmarks. Bug or some inaccuracy?

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsFixThe path to resolution is known, but the work has not been done.Performancecompiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions