...

Source file src/runtime/slice_test.go

Documentation: runtime

		 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  }
	 502  

View as plain text