github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/runtime/append_test.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  package runtime_test
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  )
    10  
    11  const N = 20
    12  
    13  func BenchmarkMakeSlice(b *testing.B) {
    14  	var x []byte
    15  	for i := 0; i < b.N; i++ {
    16  		x = make([]byte, 32)
    17  		_ = x
    18  	}
    19  }
    20  
    21  func BenchmarkGrowSliceBytes(b *testing.B) {
    22  	b.StopTimer()
    23  	var x = make([]byte, 9)
    24  	b.StartTimer()
    25  	for i := 0; i < b.N; i++ {
    26  		_ = append([]byte(nil), x...)
    27  	}
    28  }
    29  
    30  func BenchmarkGrowSliceInts(b *testing.B) {
    31  	b.StopTimer()
    32  	var x = make([]int, 9)
    33  	b.StartTimer()
    34  	for i := 0; i < b.N; i++ {
    35  		_ = append([]int(nil), x...)
    36  	}
    37  }
    38  
    39  func BenchmarkGrowSlicePtr(b *testing.B) {
    40  	b.StopTimer()
    41  	var x = make([]*byte, 9)
    42  	b.StartTimer()
    43  	for i := 0; i < b.N; i++ {
    44  		_ = append([]*byte(nil), x...)
    45  	}
    46  }
    47  
    48  type struct24 struct{ a, b, c int64 }
    49  
    50  func BenchmarkGrowSliceStruct24Bytes(b *testing.B) {
    51  	b.StopTimer()
    52  	var x = make([]struct24, 9)
    53  	b.StartTimer()
    54  	for i := 0; i < b.N; i++ {
    55  		_ = append([]struct24(nil), x...)
    56  	}
    57  }
    58  
    59  func BenchmarkAppend(b *testing.B) {
    60  	b.StopTimer()
    61  	x := make([]int, 0, N)
    62  	b.StartTimer()
    63  	for i := 0; i < b.N; i++ {
    64  		x = x[0:0]
    65  		for j := 0; j < N; j++ {
    66  			x = append(x, j)
    67  		}
    68  	}
    69  }
    70  
    71  func BenchmarkAppendGrowByte(b *testing.B) {
    72  	for i := 0; i < b.N; i++ {
    73  		var x []byte
    74  		for j := 0; j < 1<<20; j++ {
    75  			x = append(x, byte(j))
    76  		}
    77  	}
    78  }
    79  
    80  func BenchmarkAppendGrowString(b *testing.B) {
    81  	var s string
    82  	for i := 0; i < b.N; i++ {
    83  		var x []string
    84  		for j := 0; j < 1<<20; j++ {
    85  			x = append(x, s)
    86  		}
    87  	}
    88  }
    89  
    90  func BenchmarkAppendSlice(b *testing.B) {
    91  	for _, length := range []int{1, 4, 7, 8, 15, 16, 32} {
    92  		b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) {
    93  			x := make([]byte, 0, N)
    94  			y := make([]byte, length)
    95  			for i := 0; i < b.N; i++ {
    96  				x = x[0:0]
    97  				x = append(x, y...)
    98  			}
    99  		})
   100  	}
   101  }
   102  
   103  func BenchmarkAppendStr(b *testing.B) {
   104  	for _, str := range []string{
   105  		"1",
   106  		"1234",
   107  		"12345678",
   108  		"1234567890123456",
   109  		"12345678901234567890123456789012",
   110  	} {
   111  		b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) {
   112  			x := make([]byte, 0, N)
   113  			for i := 0; i < b.N; i++ {
   114  				x = x[0:0]
   115  				x = append(x, str...)
   116  			}
   117  		})
   118  	}
   119  }
   120  
   121  func BenchmarkAppendSpecialCase(b *testing.B) {
   122  	b.StopTimer()
   123  	x := make([]int, 0, N)
   124  	b.StartTimer()
   125  	for i := 0; i < b.N; i++ {
   126  		x = x[0:0]
   127  		for j := 0; j < N; j++ {
   128  			if len(x) < cap(x) {
   129  				x = x[:len(x)+1]
   130  				x[len(x)-1] = j
   131  			} else {
   132  				x = append(x, j)
   133  			}
   134  		}
   135  	}
   136  }
   137  
   138  var x []int
   139  
   140  func f() int {
   141  	x[:1][0] = 3
   142  	return 2
   143  }
   144  
   145  func TestSideEffectOrder(t *testing.T) {
   146  	x = make([]int, 0, 10)
   147  	x = append(x, 1, f())
   148  	if x[0] != 1 || x[1] != 2 {
   149  		t.Error("append failed: ", x[0], x[1])
   150  	}
   151  }
   152  
   153  func TestAppendOverlap(t *testing.T) {
   154  	x := []byte("1234")
   155  	x = append(x[1:], x...) // p > q in runtimeĀ·appendslice.
   156  	got := string(x)
   157  	want := "2341234"
   158  	if got != want {
   159  		t.Errorf("overlap failed: got %q want %q", got, want)
   160  	}
   161  }
   162  
   163  func BenchmarkCopy(b *testing.B) {
   164  	for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} {
   165  		buf := make([]byte, 4096)
   166  		b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) {
   167  			s := make([]byte, l)
   168  			var n int
   169  			for i := 0; i < b.N; i++ {
   170  				n = copy(buf, s)
   171  			}
   172  			b.SetBytes(int64(n))
   173  		})
   174  		b.Run(fmt.Sprint(l, "String"), func(b *testing.B) {
   175  			s := string(make([]byte, l))
   176  			var n int
   177  			for i := 0; i < b.N; i++ {
   178  				n = copy(buf, s)
   179  			}
   180  			b.SetBytes(int64(n))
   181  		})
   182  	}
   183  }
   184  
   185  var (
   186  	sByte []byte
   187  	s1Ptr []uintptr
   188  	s2Ptr [][2]uintptr
   189  	s3Ptr [][3]uintptr
   190  	s4Ptr [][4]uintptr
   191  )
   192  
   193  // BenchmarkAppendInPlace tests the performance of append
   194  // when the result is being written back to the same slice.
   195  // In order for the in-place optimization to occur,
   196  // the slice must be referred to by address;
   197  // using a global is an easy way to trigger that.
   198  // We test the "grow" and "no grow" paths separately,
   199  // but not the "normal" (occasionally grow) path,
   200  // because it is a blend of the other two.
   201  // We use small numbers and small sizes in an attempt
   202  // to avoid benchmarking memory allocation and copying.
   203  // We use scalars instead of pointers in an attempt
   204  // to avoid benchmarking the write barriers.
   205  // We benchmark four common sizes (byte, pointer, string/interface, slice),
   206  // and one larger size.
   207  func BenchmarkAppendInPlace(b *testing.B) {
   208  	b.Run("NoGrow", func(b *testing.B) {
   209  		const C = 128
   210  
   211  		b.Run("Byte", func(b *testing.B) {
   212  			for i := 0; i < b.N; i++ {
   213  				sByte = make([]byte, C)
   214  				for j := 0; j < C; j++ {
   215  					sByte = append(sByte, 0x77)
   216  				}
   217  			}
   218  		})
   219  
   220  		b.Run("1Ptr", func(b *testing.B) {
   221  			for i := 0; i < b.N; i++ {
   222  				s1Ptr = make([]uintptr, C)
   223  				for j := 0; j < C; j++ {
   224  					s1Ptr = append(s1Ptr, 0x77)
   225  				}
   226  			}
   227  		})
   228  
   229  		b.Run("2Ptr", func(b *testing.B) {
   230  			for i := 0; i < b.N; i++ {
   231  				s2Ptr = make([][2]uintptr, C)
   232  				for j := 0; j < C; j++ {
   233  					s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
   234  				}
   235  			}
   236  		})
   237  
   238  		b.Run("3Ptr", func(b *testing.B) {
   239  			for i := 0; i < b.N; i++ {
   240  				s3Ptr = make([][3]uintptr, C)
   241  				for j := 0; j < C; j++ {
   242  					s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
   243  				}
   244  			}
   245  		})
   246  
   247  		b.Run("4Ptr", func(b *testing.B) {
   248  			for i := 0; i < b.N; i++ {
   249  				s4Ptr = make([][4]uintptr, C)
   250  				for j := 0; j < C; j++ {
   251  					s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
   252  				}
   253  			}
   254  		})
   255  
   256  	})
   257  
   258  	b.Run("Grow", func(b *testing.B) {
   259  		const C = 5
   260  
   261  		b.Run("Byte", func(b *testing.B) {
   262  			for i := 0; i < b.N; i++ {
   263  				sByte = make([]byte, 0)
   264  				for j := 0; j < C; j++ {
   265  					sByte = append(sByte, 0x77)
   266  					sByte = sByte[:cap(sByte)]
   267  				}
   268  			}
   269  		})
   270  
   271  		b.Run("1Ptr", func(b *testing.B) {
   272  			for i := 0; i < b.N; i++ {
   273  				s1Ptr = make([]uintptr, 0)
   274  				for j := 0; j < C; j++ {
   275  					s1Ptr = append(s1Ptr, 0x77)
   276  					s1Ptr = s1Ptr[:cap(s1Ptr)]
   277  				}
   278  			}
   279  		})
   280  
   281  		b.Run("2Ptr", func(b *testing.B) {
   282  			for i := 0; i < b.N; i++ {
   283  				s2Ptr = make([][2]uintptr, 0)
   284  				for j := 0; j < C; j++ {
   285  					s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
   286  					s2Ptr = s2Ptr[:cap(s2Ptr)]
   287  				}
   288  			}
   289  		})
   290  
   291  		b.Run("3Ptr", func(b *testing.B) {
   292  			for i := 0; i < b.N; i++ {
   293  				s3Ptr = make([][3]uintptr, 0)
   294  				for j := 0; j < C; j++ {
   295  					s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
   296  					s3Ptr = s3Ptr[:cap(s3Ptr)]
   297  				}
   298  			}
   299  		})
   300  
   301  		b.Run("4Ptr", func(b *testing.B) {
   302  			for i := 0; i < b.N; i++ {
   303  				s4Ptr = make([][4]uintptr, 0)
   304  				for j := 0; j < C; j++ {
   305  					s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
   306  					s4Ptr = s4Ptr[:cap(s4Ptr)]
   307  				}
   308  			}
   309  		})
   310  
   311  	})
   312  }