github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/slice_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 5 package runtime_test 6 7 import ( 8 "fmt" 9 "testing" 10 ) 11 12 const N = 20 13 14 func BenchmarkMakeSliceCopy(b *testing.B) { 15 const length = 32 16 var bytes = make([]byte, 8*length) 17 var ints = make([]int, length) 18 var ptrs = make([]*byte, length) 19 b.Run("mallocmove", func(b *testing.B) { 20 b.Run("Byte", func(b *testing.B) { 21 var x []byte 22 for i := 0; i < b.N; i++ { 23 x = make([]byte, len(bytes)) 24 copy(x, bytes) 25 } 26 }) 27 b.Run("Int", func(b *testing.B) { 28 var x []int 29 for i := 0; i < b.N; i++ { 30 x = make([]int, len(ints)) 31 copy(x, ints) 32 } 33 }) 34 b.Run("Ptr", func(b *testing.B) { 35 var x []*byte 36 for i := 0; i < b.N; i++ { 37 x = make([]*byte, len(ptrs)) 38 copy(x, ptrs) 39 } 40 41 }) 42 }) 43 b.Run("makecopy", func(b *testing.B) { 44 b.Run("Byte", func(b *testing.B) { 45 var x []byte 46 for i := 0; i < b.N; i++ { 47 x = make([]byte, 8*length) 48 copy(x, bytes) 49 } 50 }) 51 b.Run("Int", func(b *testing.B) { 52 var x []int 53 for i := 0; i < b.N; i++ { 54 x = make([]int, length) 55 copy(x, ints) 56 } 57 }) 58 b.Run("Ptr", func(b *testing.B) { 59 var x []*byte 60 for i := 0; i < b.N; i++ { 61 x = make([]*byte, length) 62 copy(x, ptrs) 63 } 64 65 }) 66 }) 67 b.Run("nilappend", func(b *testing.B) { 68 b.Run("Byte", func(b *testing.B) { 69 var x []byte 70 for i := 0; i < b.N; i++ { 71 x = append([]byte(nil), bytes...) 72 _ = x 73 } 74 }) 75 b.Run("Int", func(b *testing.B) { 76 var x []int 77 for i := 0; i < b.N; i++ { 78 x = append([]int(nil), ints...) 79 _ = x 80 } 81 }) 82 b.Run("Ptr", func(b *testing.B) { 83 var x []*byte 84 for i := 0; i < b.N; i++ { 85 x = append([]*byte(nil), ptrs...) 86 _ = x 87 } 88 }) 89 }) 90 } 91 92 type ( 93 struct24 struct{ a, b, c int64 } 94 struct32 struct{ a, b, c, d int64 } 95 struct40 struct{ a, b, c, d, e int64 } 96 ) 97 98 func BenchmarkMakeSlice(b *testing.B) { 99 const length = 2 100 b.Run("Byte", func(b *testing.B) { 101 var x []byte 102 for i := 0; i < b.N; i++ { 103 x = make([]byte, length, 2*length) 104 _ = x 105 } 106 }) 107 b.Run("Int16", func(b *testing.B) { 108 var x []int16 109 for i := 0; i < b.N; i++ { 110 x = make([]int16, length, 2*length) 111 _ = x 112 } 113 }) 114 b.Run("Int", func(b *testing.B) { 115 var x []int 116 for i := 0; i < b.N; i++ { 117 x = make([]int, length, 2*length) 118 _ = x 119 } 120 }) 121 b.Run("Ptr", func(b *testing.B) { 122 var x []*byte 123 for i := 0; i < b.N; i++ { 124 x = make([]*byte, length, 2*length) 125 _ = x 126 } 127 }) 128 b.Run("Struct", func(b *testing.B) { 129 b.Run("24", func(b *testing.B) { 130 var x []struct24 131 for i := 0; i < b.N; i++ { 132 x = make([]struct24, length, 2*length) 133 _ = x 134 } 135 }) 136 b.Run("32", func(b *testing.B) { 137 var x []struct32 138 for i := 0; i < b.N; i++ { 139 x = make([]struct32, length, 2*length) 140 _ = x 141 } 142 }) 143 b.Run("40", func(b *testing.B) { 144 var x []struct40 145 for i := 0; i < b.N; i++ { 146 x = make([]struct40, length, 2*length) 147 _ = x 148 } 149 }) 150 151 }) 152 } 153 154 func BenchmarkGrowSlice(b *testing.B) { 155 b.Run("Byte", func(b *testing.B) { 156 x := make([]byte, 9) 157 for i := 0; i < b.N; i++ { 158 _ = append([]byte(nil), x...) 159 } 160 }) 161 b.Run("Int16", func(b *testing.B) { 162 x := make([]int16, 9) 163 for i := 0; i < b.N; i++ { 164 _ = append([]int16(nil), x...) 165 } 166 }) 167 b.Run("Int", func(b *testing.B) { 168 x := make([]int, 9) 169 for i := 0; i < b.N; i++ { 170 _ = append([]int(nil), x...) 171 } 172 }) 173 b.Run("Ptr", func(b *testing.B) { 174 x := make([]*byte, 9) 175 for i := 0; i < b.N; i++ { 176 _ = append([]*byte(nil), x...) 177 } 178 }) 179 b.Run("Struct", func(b *testing.B) { 180 b.Run("24", func(b *testing.B) { 181 x := make([]struct24, 9) 182 for i := 0; i < b.N; i++ { 183 _ = append([]struct24(nil), x...) 184 } 185 }) 186 b.Run("32", func(b *testing.B) { 187 x := make([]struct32, 9) 188 for i := 0; i < b.N; i++ { 189 _ = append([]struct32(nil), x...) 190 } 191 }) 192 b.Run("40", func(b *testing.B) { 193 x := make([]struct40, 9) 194 for i := 0; i < b.N; i++ { 195 _ = append([]struct40(nil), x...) 196 } 197 }) 198 199 }) 200 } 201 202 var ( 203 SinkIntSlice []int 204 SinkIntPointerSlice []*int 205 ) 206 207 func BenchmarkExtendSlice(b *testing.B) { 208 var length = 4 // Use a variable to prevent stack allocation of slices. 209 b.Run("IntSlice", func(b *testing.B) { 210 s := make([]int, 0, length) 211 for i := 0; i < b.N; i++ { 212 s = append(s[:0:length/2], make([]int, length)...) 213 } 214 SinkIntSlice = s 215 }) 216 b.Run("PointerSlice", func(b *testing.B) { 217 s := make([]*int, 0, length) 218 for i := 0; i < b.N; i++ { 219 s = append(s[:0:length/2], make([]*int, length)...) 220 } 221 SinkIntPointerSlice = s 222 }) 223 b.Run("NoGrow", func(b *testing.B) { 224 s := make([]int, 0, length) 225 for i := 0; i < b.N; i++ { 226 s = append(s[:0:length], make([]int, length)...) 227 } 228 SinkIntSlice = s 229 }) 230 } 231 232 func BenchmarkAppend(b *testing.B) { 233 b.StopTimer() 234 x := make([]int, 0, N) 235 b.StartTimer() 236 for i := 0; i < b.N; i++ { 237 x = x[0:0] 238 for j := 0; j < N; j++ { 239 x = append(x, j) 240 } 241 } 242 } 243 244 func BenchmarkAppendGrowByte(b *testing.B) { 245 for i := 0; i < b.N; i++ { 246 var x []byte 247 for j := 0; j < 1<<20; j++ { 248 x = append(x, byte(j)) 249 } 250 } 251 } 252 253 func BenchmarkAppendGrowString(b *testing.B) { 254 var s string 255 for i := 0; i < b.N; i++ { 256 var x []string 257 for j := 0; j < 1<<20; j++ { 258 x = append(x, s) 259 } 260 } 261 } 262 263 func BenchmarkAppendSlice(b *testing.B) { 264 for _, length := range []int{1, 4, 7, 8, 15, 16, 32} { 265 b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) { 266 x := make([]byte, 0, N) 267 y := make([]byte, length) 268 for i := 0; i < b.N; i++ { 269 x = x[0:0] 270 x = append(x, y...) 271 } 272 }) 273 } 274 } 275 276 var ( 277 blackhole []byte 278 ) 279 280 func BenchmarkAppendSliceLarge(b *testing.B) { 281 for _, length := range []int{1 << 10, 4 << 10, 16 << 10, 64 << 10, 256 << 10, 1024 << 10} { 282 y := make([]byte, length) 283 b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) { 284 for i := 0; i < b.N; i++ { 285 blackhole = nil 286 blackhole = append(blackhole, y...) 287 } 288 }) 289 } 290 } 291 292 func BenchmarkAppendStr(b *testing.B) { 293 for _, str := range []string{ 294 "1", 295 "1234", 296 "12345678", 297 "1234567890123456", 298 "12345678901234567890123456789012", 299 } { 300 b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) { 301 x := make([]byte, 0, N) 302 for i := 0; i < b.N; i++ { 303 x = x[0:0] 304 x = append(x, str...) 305 } 306 }) 307 } 308 } 309 310 func BenchmarkAppendSpecialCase(b *testing.B) { 311 b.StopTimer() 312 x := make([]int, 0, N) 313 b.StartTimer() 314 for i := 0; i < b.N; i++ { 315 x = x[0:0] 316 for j := 0; j < N; j++ { 317 if len(x) < cap(x) { 318 x = x[:len(x)+1] 319 x[len(x)-1] = j 320 } else { 321 x = append(x, j) 322 } 323 } 324 } 325 } 326 327 var x []int 328 329 func f() int { 330 x[:1][0] = 3 331 return 2 332 } 333 334 func TestSideEffectOrder(t *testing.T) { 335 x = make([]int, 0, 10) 336 x = append(x, 1, f()) 337 if x[0] != 1 || x[1] != 2 { 338 t.Error("append failed: ", x[0], x[1]) 339 } 340 } 341 342 func TestAppendOverlap(t *testing.T) { 343 x := []byte("1234") 344 x = append(x[1:], x...) // p > q in runtimeĀ·appendslice. 345 got := string(x) 346 want := "2341234" 347 if got != want { 348 t.Errorf("overlap failed: got %q want %q", got, want) 349 } 350 } 351 352 func BenchmarkCopy(b *testing.B) { 353 for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} { 354 buf := make([]byte, 4096) 355 b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) { 356 s := make([]byte, l) 357 var n int 358 for i := 0; i < b.N; i++ { 359 n = copy(buf, s) 360 } 361 b.SetBytes(int64(n)) 362 }) 363 b.Run(fmt.Sprint(l, "String"), func(b *testing.B) { 364 s := string(make([]byte, l)) 365 var n int 366 for i := 0; i < b.N; i++ { 367 n = copy(buf, s) 368 } 369 b.SetBytes(int64(n)) 370 }) 371 } 372 } 373 374 var ( 375 sByte []byte 376 s1Ptr []uintptr 377 s2Ptr [][2]uintptr 378 s3Ptr [][3]uintptr 379 s4Ptr [][4]uintptr 380 ) 381 382 // BenchmarkAppendInPlace tests the performance of append 383 // when the result is being written back to the same slice. 384 // In order for the in-place optimization to occur, 385 // the slice must be referred to by address; 386 // using a global is an easy way to trigger that. 387 // We test the "grow" and "no grow" paths separately, 388 // but not the "normal" (occasionally grow) path, 389 // because it is a blend of the other two. 390 // We use small numbers and small sizes in an attempt 391 // to avoid benchmarking memory allocation and copying. 392 // We use scalars instead of pointers in an attempt 393 // to avoid benchmarking the write barriers. 394 // We benchmark four common sizes (byte, pointer, string/interface, slice), 395 // and one larger size. 396 func BenchmarkAppendInPlace(b *testing.B) { 397 b.Run("NoGrow", func(b *testing.B) { 398 const C = 128 399 400 b.Run("Byte", func(b *testing.B) { 401 for i := 0; i < b.N; i++ { 402 sByte = make([]byte, C) 403 for j := 0; j < C; j++ { 404 sByte = append(sByte, 0x77) 405 } 406 } 407 }) 408 409 b.Run("1Ptr", func(b *testing.B) { 410 for i := 0; i < b.N; i++ { 411 s1Ptr = make([]uintptr, C) 412 for j := 0; j < C; j++ { 413 s1Ptr = append(s1Ptr, 0x77) 414 } 415 } 416 }) 417 418 b.Run("2Ptr", func(b *testing.B) { 419 for i := 0; i < b.N; i++ { 420 s2Ptr = make([][2]uintptr, C) 421 for j := 0; j < C; j++ { 422 s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88}) 423 } 424 } 425 }) 426 427 b.Run("3Ptr", func(b *testing.B) { 428 for i := 0; i < b.N; i++ { 429 s3Ptr = make([][3]uintptr, C) 430 for j := 0; j < C; j++ { 431 s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99}) 432 } 433 } 434 }) 435 436 b.Run("4Ptr", func(b *testing.B) { 437 for i := 0; i < b.N; i++ { 438 s4Ptr = make([][4]uintptr, C) 439 for j := 0; j < C; j++ { 440 s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA}) 441 } 442 } 443 }) 444 445 }) 446 447 b.Run("Grow", func(b *testing.B) { 448 const C = 5 449 450 b.Run("Byte", func(b *testing.B) { 451 for i := 0; i < b.N; i++ { 452 sByte = make([]byte, 0) 453 for j := 0; j < C; j++ { 454 sByte = append(sByte, 0x77) 455 sByte = sByte[:cap(sByte)] 456 } 457 } 458 }) 459 460 b.Run("1Ptr", func(b *testing.B) { 461 for i := 0; i < b.N; i++ { 462 s1Ptr = make([]uintptr, 0) 463 for j := 0; j < C; j++ { 464 s1Ptr = append(s1Ptr, 0x77) 465 s1Ptr = s1Ptr[:cap(s1Ptr)] 466 } 467 } 468 }) 469 470 b.Run("2Ptr", func(b *testing.B) { 471 for i := 0; i < b.N; i++ { 472 s2Ptr = make([][2]uintptr, 0) 473 for j := 0; j < C; j++ { 474 s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88}) 475 s2Ptr = s2Ptr[:cap(s2Ptr)] 476 } 477 } 478 }) 479 480 b.Run("3Ptr", func(b *testing.B) { 481 for i := 0; i < b.N; i++ { 482 s3Ptr = make([][3]uintptr, 0) 483 for j := 0; j < C; j++ { 484 s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99}) 485 s3Ptr = s3Ptr[:cap(s3Ptr)] 486 } 487 } 488 }) 489 490 b.Run("4Ptr", func(b *testing.B) { 491 for i := 0; i < b.N; i++ { 492 s4Ptr = make([][4]uintptr, 0) 493 for j := 0; j < C; j++ { 494 s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA}) 495 s4Ptr = s4Ptr[:cap(s4Ptr)] 496 } 497 } 498 }) 499 500 }) 501 }