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