github.com/letsencrypt/go@v0.0.0-20160714163537-4054769a31f6/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 }