github.com/panjjo/go@v0.0.0-20161104043856-d62b31386338/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 var ( 104 blackhole []byte 105 ) 106 107 func BenchmarkAppendSliceLarge(b *testing.B) { 108 for _, length := range []int{1 << 10, 4 << 10, 16 << 10, 64 << 10, 256 << 10, 1024 << 10} { 109 y := make([]byte, length) 110 b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) { 111 for i := 0; i < b.N; i++ { 112 blackhole = nil 113 blackhole = append(blackhole, y...) 114 } 115 }) 116 } 117 } 118 119 func BenchmarkAppendStr(b *testing.B) { 120 for _, str := range []string{ 121 "1", 122 "1234", 123 "12345678", 124 "1234567890123456", 125 "12345678901234567890123456789012", 126 } { 127 b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) { 128 x := make([]byte, 0, N) 129 for i := 0; i < b.N; i++ { 130 x = x[0:0] 131 x = append(x, str...) 132 } 133 }) 134 } 135 } 136 137 func BenchmarkAppendSpecialCase(b *testing.B) { 138 b.StopTimer() 139 x := make([]int, 0, N) 140 b.StartTimer() 141 for i := 0; i < b.N; i++ { 142 x = x[0:0] 143 for j := 0; j < N; j++ { 144 if len(x) < cap(x) { 145 x = x[:len(x)+1] 146 x[len(x)-1] = j 147 } else { 148 x = append(x, j) 149 } 150 } 151 } 152 } 153 154 var x []int 155 156 func f() int { 157 x[:1][0] = 3 158 return 2 159 } 160 161 func TestSideEffectOrder(t *testing.T) { 162 x = make([]int, 0, 10) 163 x = append(x, 1, f()) 164 if x[0] != 1 || x[1] != 2 { 165 t.Error("append failed: ", x[0], x[1]) 166 } 167 } 168 169 func TestAppendOverlap(t *testing.T) { 170 x := []byte("1234") 171 x = append(x[1:], x...) // p > q in runtimeĀ·appendslice. 172 got := string(x) 173 want := "2341234" 174 if got != want { 175 t.Errorf("overlap failed: got %q want %q", got, want) 176 } 177 } 178 179 func BenchmarkCopy(b *testing.B) { 180 for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} { 181 buf := make([]byte, 4096) 182 b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) { 183 s := make([]byte, l) 184 var n int 185 for i := 0; i < b.N; i++ { 186 n = copy(buf, s) 187 } 188 b.SetBytes(int64(n)) 189 }) 190 b.Run(fmt.Sprint(l, "String"), func(b *testing.B) { 191 s := string(make([]byte, l)) 192 var n int 193 for i := 0; i < b.N; i++ { 194 n = copy(buf, s) 195 } 196 b.SetBytes(int64(n)) 197 }) 198 } 199 } 200 201 var ( 202 sByte []byte 203 s1Ptr []uintptr 204 s2Ptr [][2]uintptr 205 s3Ptr [][3]uintptr 206 s4Ptr [][4]uintptr 207 ) 208 209 // BenchmarkAppendInPlace tests the performance of append 210 // when the result is being written back to the same slice. 211 // In order for the in-place optimization to occur, 212 // the slice must be referred to by address; 213 // using a global is an easy way to trigger that. 214 // We test the "grow" and "no grow" paths separately, 215 // but not the "normal" (occasionally grow) path, 216 // because it is a blend of the other two. 217 // We use small numbers and small sizes in an attempt 218 // to avoid benchmarking memory allocation and copying. 219 // We use scalars instead of pointers in an attempt 220 // to avoid benchmarking the write barriers. 221 // We benchmark four common sizes (byte, pointer, string/interface, slice), 222 // and one larger size. 223 func BenchmarkAppendInPlace(b *testing.B) { 224 b.Run("NoGrow", func(b *testing.B) { 225 const C = 128 226 227 b.Run("Byte", func(b *testing.B) { 228 for i := 0; i < b.N; i++ { 229 sByte = make([]byte, C) 230 for j := 0; j < C; j++ { 231 sByte = append(sByte, 0x77) 232 } 233 } 234 }) 235 236 b.Run("1Ptr", func(b *testing.B) { 237 for i := 0; i < b.N; i++ { 238 s1Ptr = make([]uintptr, C) 239 for j := 0; j < C; j++ { 240 s1Ptr = append(s1Ptr, 0x77) 241 } 242 } 243 }) 244 245 b.Run("2Ptr", func(b *testing.B) { 246 for i := 0; i < b.N; i++ { 247 s2Ptr = make([][2]uintptr, C) 248 for j := 0; j < C; j++ { 249 s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88}) 250 } 251 } 252 }) 253 254 b.Run("3Ptr", func(b *testing.B) { 255 for i := 0; i < b.N; i++ { 256 s3Ptr = make([][3]uintptr, C) 257 for j := 0; j < C; j++ { 258 s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99}) 259 } 260 } 261 }) 262 263 b.Run("4Ptr", func(b *testing.B) { 264 for i := 0; i < b.N; i++ { 265 s4Ptr = make([][4]uintptr, C) 266 for j := 0; j < C; j++ { 267 s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA}) 268 } 269 } 270 }) 271 272 }) 273 274 b.Run("Grow", func(b *testing.B) { 275 const C = 5 276 277 b.Run("Byte", func(b *testing.B) { 278 for i := 0; i < b.N; i++ { 279 sByte = make([]byte, 0) 280 for j := 0; j < C; j++ { 281 sByte = append(sByte, 0x77) 282 sByte = sByte[:cap(sByte)] 283 } 284 } 285 }) 286 287 b.Run("1Ptr", func(b *testing.B) { 288 for i := 0; i < b.N; i++ { 289 s1Ptr = make([]uintptr, 0) 290 for j := 0; j < C; j++ { 291 s1Ptr = append(s1Ptr, 0x77) 292 s1Ptr = s1Ptr[:cap(s1Ptr)] 293 } 294 } 295 }) 296 297 b.Run("2Ptr", func(b *testing.B) { 298 for i := 0; i < b.N; i++ { 299 s2Ptr = make([][2]uintptr, 0) 300 for j := 0; j < C; j++ { 301 s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88}) 302 s2Ptr = s2Ptr[:cap(s2Ptr)] 303 } 304 } 305 }) 306 307 b.Run("3Ptr", func(b *testing.B) { 308 for i := 0; i < b.N; i++ { 309 s3Ptr = make([][3]uintptr, 0) 310 for j := 0; j < C; j++ { 311 s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99}) 312 s3Ptr = s3Ptr[:cap(s3Ptr)] 313 } 314 } 315 }) 316 317 b.Run("4Ptr", func(b *testing.B) { 318 for i := 0; i < b.N; i++ { 319 s4Ptr = make([][4]uintptr, 0) 320 for j := 0; j < C; j++ { 321 s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA}) 322 s4Ptr = s4Ptr[:cap(s4Ptr)] 323 } 324 } 325 }) 326 327 }) 328 }