github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/memmove_test.go (about) 1 // Copyright 2013 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 "crypto/rand" 9 "encoding/binary" 10 "fmt" 11 "internal/race" 12 "internal/testenv" 13 . "runtime" 14 "testing" 15 ) 16 17 func TestMemmove(t *testing.T) { 18 t.Parallel() 19 size := 256 20 if testing.Short() { 21 size = 128 + 16 22 } 23 src := make([]byte, size) 24 dst := make([]byte, size) 25 for i := 0; i < size; i++ { 26 src[i] = byte(128 + (i & 127)) 27 } 28 for i := 0; i < size; i++ { 29 dst[i] = byte(i & 127) 30 } 31 for n := 0; n <= size; n++ { 32 for x := 0; x <= size-n; x++ { // offset in src 33 for y := 0; y <= size-n; y++ { // offset in dst 34 copy(dst[y:y+n], src[x:x+n]) 35 for i := 0; i < y; i++ { 36 if dst[i] != byte(i&127) { 37 t.Fatalf("prefix dst[%d] = %d", i, dst[i]) 38 } 39 } 40 for i := y; i < y+n; i++ { 41 if dst[i] != byte(128+((i-y+x)&127)) { 42 t.Fatalf("copied dst[%d] = %d", i, dst[i]) 43 } 44 dst[i] = byte(i & 127) // reset dst 45 } 46 for i := y + n; i < size; i++ { 47 if dst[i] != byte(i&127) { 48 t.Fatalf("suffix dst[%d] = %d", i, dst[i]) 49 } 50 } 51 } 52 } 53 } 54 } 55 56 func TestMemmoveAlias(t *testing.T) { 57 t.Parallel() 58 size := 256 59 if testing.Short() { 60 size = 128 + 16 61 } 62 buf := make([]byte, size) 63 for i := 0; i < size; i++ { 64 buf[i] = byte(i) 65 } 66 for n := 0; n <= size; n++ { 67 for x := 0; x <= size-n; x++ { // src offset 68 for y := 0; y <= size-n; y++ { // dst offset 69 copy(buf[y:y+n], buf[x:x+n]) 70 for i := 0; i < y; i++ { 71 if buf[i] != byte(i) { 72 t.Fatalf("prefix buf[%d] = %d", i, buf[i]) 73 } 74 } 75 for i := y; i < y+n; i++ { 76 if buf[i] != byte(i-y+x) { 77 t.Fatalf("copied buf[%d] = %d", i, buf[i]) 78 } 79 buf[i] = byte(i) // reset buf 80 } 81 for i := y + n; i < size; i++ { 82 if buf[i] != byte(i) { 83 t.Fatalf("suffix buf[%d] = %d", i, buf[i]) 84 } 85 } 86 } 87 } 88 } 89 } 90 91 func TestMemmoveLarge0x180000(t *testing.T) { 92 if testing.Short() && testenv.Builder() == "" { 93 t.Skip("-short") 94 } 95 96 t.Parallel() 97 if race.Enabled { 98 t.Skip("skipping large memmove test under race detector") 99 } 100 testSize(t, 0x180000) 101 } 102 103 func TestMemmoveOverlapLarge0x120000(t *testing.T) { 104 if testing.Short() && testenv.Builder() == "" { 105 t.Skip("-short") 106 } 107 108 t.Parallel() 109 if race.Enabled { 110 t.Skip("skipping large memmove test under race detector") 111 } 112 testOverlap(t, 0x120000) 113 } 114 115 func testSize(t *testing.T, size int) { 116 src := make([]byte, size) 117 dst := make([]byte, size) 118 _, _ = rand.Read(src) 119 _, _ = rand.Read(dst) 120 121 ref := make([]byte, size) 122 copyref(ref, dst) 123 124 for n := size - 50; n > 1; n >>= 1 { 125 for x := 0; x <= size-n; x = x*7 + 1 { // offset in src 126 for y := 0; y <= size-n; y = y*9 + 1 { // offset in dst 127 copy(dst[y:y+n], src[x:x+n]) 128 copyref(ref[y:y+n], src[x:x+n]) 129 p := cmpb(dst, ref) 130 if p >= 0 { 131 t.Fatalf("Copy failed, copying from src[%d:%d] to dst[%d:%d].\nOffset %d is different, %v != %v", x, x+n, y, y+n, p, dst[p], ref[p]) 132 } 133 } 134 } 135 } 136 } 137 138 func testOverlap(t *testing.T, size int) { 139 src := make([]byte, size) 140 test := make([]byte, size) 141 ref := make([]byte, size) 142 _, _ = rand.Read(src) 143 144 for n := size - 50; n > 1; n >>= 1 { 145 for x := 0; x <= size-n; x = x*7 + 1 { // offset in src 146 for y := 0; y <= size-n; y = y*9 + 1 { // offset in dst 147 // Reset input 148 copyref(test, src) 149 copyref(ref, src) 150 copy(test[y:y+n], test[x:x+n]) 151 if y <= x { 152 copyref(ref[y:y+n], ref[x:x+n]) 153 } else { 154 copybw(ref[y:y+n], ref[x:x+n]) 155 } 156 p := cmpb(test, ref) 157 if p >= 0 { 158 t.Fatalf("Copy failed, copying from src[%d:%d] to dst[%d:%d].\nOffset %d is different, %v != %v", x, x+n, y, y+n, p, test[p], ref[p]) 159 } 160 } 161 } 162 } 163 164 } 165 166 // Forward copy. 167 func copyref(dst, src []byte) { 168 for i, v := range src { 169 dst[i] = v 170 } 171 } 172 173 // Backwards copy 174 func copybw(dst, src []byte) { 175 if len(src) == 0 { 176 return 177 } 178 for i := len(src) - 1; i >= 0; i-- { 179 dst[i] = src[i] 180 } 181 } 182 183 // Returns offset of difference 184 func matchLen(a, b []byte, max int) int { 185 a = a[:max] 186 b = b[:max] 187 for i, av := range a { 188 if b[i] != av { 189 return i 190 } 191 } 192 return max 193 } 194 195 func cmpb(a, b []byte) int { 196 l := matchLen(a, b, len(a)) 197 if l == len(a) { 198 return -1 199 } 200 return l 201 } 202 203 func benchmarkSizes(b *testing.B, sizes []int, fn func(b *testing.B, n int)) { 204 for _, n := range sizes { 205 b.Run(fmt.Sprint(n), func(b *testing.B) { 206 b.SetBytes(int64(n)) 207 fn(b, n) 208 }) 209 } 210 } 211 212 var bufSizes = []int{ 213 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 214 32, 64, 128, 256, 512, 1024, 2048, 4096, 215 } 216 217 func BenchmarkMemmove(b *testing.B) { 218 benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { 219 x := make([]byte, n) 220 y := make([]byte, n) 221 for i := 0; i < b.N; i++ { 222 copy(x, y) 223 } 224 }) 225 } 226 227 func BenchmarkMemmoveUnalignedDst(b *testing.B) { 228 benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { 229 x := make([]byte, n+1) 230 y := make([]byte, n) 231 for i := 0; i < b.N; i++ { 232 copy(x[1:], y) 233 } 234 }) 235 } 236 237 func BenchmarkMemmoveUnalignedSrc(b *testing.B) { 238 benchmarkSizes(b, bufSizes, func(b *testing.B, n int) { 239 x := make([]byte, n) 240 y := make([]byte, n+1) 241 for i := 0; i < b.N; i++ { 242 copy(x, y[1:]) 243 } 244 }) 245 } 246 247 func TestMemclr(t *testing.T) { 248 size := 512 249 if testing.Short() { 250 size = 128 + 16 251 } 252 mem := make([]byte, size) 253 for i := 0; i < size; i++ { 254 mem[i] = 0xee 255 } 256 for n := 0; n < size; n++ { 257 for x := 0; x <= size-n; x++ { // offset in mem 258 MemclrBytes(mem[x : x+n]) 259 for i := 0; i < x; i++ { 260 if mem[i] != 0xee { 261 t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i]) 262 } 263 } 264 for i := x; i < x+n; i++ { 265 if mem[i] != 0 { 266 t.Fatalf("failed clear mem[%d] = %d", i, mem[i]) 267 } 268 mem[i] = 0xee 269 } 270 for i := x + n; i < size; i++ { 271 if mem[i] != 0xee { 272 t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i]) 273 } 274 } 275 } 276 } 277 } 278 279 func BenchmarkMemclr(b *testing.B) { 280 for _, n := range []int{5, 16, 64, 256, 4096, 65536} { 281 x := make([]byte, n) 282 b.Run(fmt.Sprint(n), func(b *testing.B) { 283 b.SetBytes(int64(n)) 284 for i := 0; i < b.N; i++ { 285 MemclrBytes(x) 286 } 287 }) 288 } 289 for _, m := range []int{1, 4, 8, 16, 64} { 290 x := make([]byte, m<<20) 291 b.Run(fmt.Sprint(m, "M"), func(b *testing.B) { 292 b.SetBytes(int64(m << 20)) 293 for i := 0; i < b.N; i++ { 294 MemclrBytes(x) 295 } 296 }) 297 } 298 } 299 300 func BenchmarkGoMemclr(b *testing.B) { 301 benchmarkSizes(b, []int{5, 16, 64, 256}, func(b *testing.B, n int) { 302 x := make([]byte, n) 303 for i := 0; i < b.N; i++ { 304 for j := range x { 305 x[j] = 0 306 } 307 } 308 }) 309 } 310 311 func BenchmarkClearFat8(b *testing.B) { 312 for i := 0; i < b.N; i++ { 313 var x [8 / 4]uint32 314 _ = x 315 } 316 } 317 func BenchmarkClearFat12(b *testing.B) { 318 for i := 0; i < b.N; i++ { 319 var x [12 / 4]uint32 320 _ = x 321 } 322 } 323 func BenchmarkClearFat16(b *testing.B) { 324 for i := 0; i < b.N; i++ { 325 var x [16 / 4]uint32 326 _ = x 327 } 328 } 329 func BenchmarkClearFat24(b *testing.B) { 330 for i := 0; i < b.N; i++ { 331 var x [24 / 4]uint32 332 _ = x 333 } 334 } 335 func BenchmarkClearFat32(b *testing.B) { 336 for i := 0; i < b.N; i++ { 337 var x [32 / 4]uint32 338 _ = x 339 } 340 } 341 func BenchmarkClearFat40(b *testing.B) { 342 for i := 0; i < b.N; i++ { 343 var x [40 / 4]uint32 344 _ = x 345 } 346 } 347 func BenchmarkClearFat48(b *testing.B) { 348 for i := 0; i < b.N; i++ { 349 var x [48 / 4]uint32 350 _ = x 351 } 352 } 353 func BenchmarkClearFat56(b *testing.B) { 354 for i := 0; i < b.N; i++ { 355 var x [56 / 4]uint32 356 _ = x 357 } 358 } 359 func BenchmarkClearFat64(b *testing.B) { 360 for i := 0; i < b.N; i++ { 361 var x [64 / 4]uint32 362 _ = x 363 } 364 } 365 func BenchmarkClearFat128(b *testing.B) { 366 for i := 0; i < b.N; i++ { 367 var x [128 / 4]uint32 368 _ = x 369 } 370 } 371 func BenchmarkClearFat256(b *testing.B) { 372 for i := 0; i < b.N; i++ { 373 var x [256 / 4]uint32 374 _ = x 375 } 376 } 377 func BenchmarkClearFat512(b *testing.B) { 378 for i := 0; i < b.N; i++ { 379 var x [512 / 4]uint32 380 _ = x 381 } 382 } 383 func BenchmarkClearFat1024(b *testing.B) { 384 for i := 0; i < b.N; i++ { 385 var x [1024 / 4]uint32 386 _ = x 387 } 388 } 389 390 func BenchmarkCopyFat8(b *testing.B) { 391 var x [8 / 4]uint32 392 for i := 0; i < b.N; i++ { 393 y := x 394 _ = y 395 } 396 } 397 func BenchmarkCopyFat12(b *testing.B) { 398 var x [12 / 4]uint32 399 for i := 0; i < b.N; i++ { 400 y := x 401 _ = y 402 } 403 } 404 func BenchmarkCopyFat16(b *testing.B) { 405 var x [16 / 4]uint32 406 for i := 0; i < b.N; i++ { 407 y := x 408 _ = y 409 } 410 } 411 func BenchmarkCopyFat24(b *testing.B) { 412 var x [24 / 4]uint32 413 for i := 0; i < b.N; i++ { 414 y := x 415 _ = y 416 } 417 } 418 func BenchmarkCopyFat32(b *testing.B) { 419 var x [32 / 4]uint32 420 for i := 0; i < b.N; i++ { 421 y := x 422 _ = y 423 } 424 } 425 func BenchmarkCopyFat64(b *testing.B) { 426 var x [64 / 4]uint32 427 for i := 0; i < b.N; i++ { 428 y := x 429 _ = y 430 } 431 } 432 func BenchmarkCopyFat128(b *testing.B) { 433 var x [128 / 4]uint32 434 for i := 0; i < b.N; i++ { 435 y := x 436 _ = y 437 } 438 } 439 func BenchmarkCopyFat256(b *testing.B) { 440 var x [256 / 4]uint32 441 for i := 0; i < b.N; i++ { 442 y := x 443 _ = y 444 } 445 } 446 func BenchmarkCopyFat512(b *testing.B) { 447 var x [512 / 4]uint32 448 for i := 0; i < b.N; i++ { 449 y := x 450 _ = y 451 } 452 } 453 func BenchmarkCopyFat1024(b *testing.B) { 454 var x [1024 / 4]uint32 455 for i := 0; i < b.N; i++ { 456 y := x 457 _ = y 458 } 459 } 460 461 func BenchmarkIssue18740(b *testing.B) { 462 // This tests that memmove uses one 4-byte load/store to move 4 bytes. 463 // It used to do 2 2-byte load/stores, which leads to a pipeline stall 464 // when we try to read the result with one 4-byte load. 465 var buf [4]byte 466 for j := 0; j < b.N; j++ { 467 s := uint32(0) 468 for i := 0; i < 4096; i += 4 { 469 copy(buf[:], g[i:]) 470 s += binary.LittleEndian.Uint32(buf[:]) 471 } 472 sink = uint64(s) 473 } 474 } 475 476 // TODO: 2 byte and 8 byte benchmarks also. 477 478 var g [4096]byte