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.
19 func TestMemmove(t
*testing
.T
) {
28 src
:= make([]byte, size
)
29 dst
:= make([]byte, size
)
30 for i
:= 0; i
< size
; i
++ {
31 src
[i
] = byte(128 + (i
& 127))
33 for i
:= 0; i
< size
; i
++ {
34 dst
[i
] = byte(i
& 127)
36 for n
:= 0; n
<= size
; n
++ {
37 for x
:= 0; x
<= size
-n
; x
++ { // offset in src
38 for y
:= 0; y
<= size
-n
; y
++ { // offset in dst
39 copy(dst
[y
:y
+n
], src
[x
:x
+n
])
40 for i
:= 0; i
< y
; i
++ {
41 if dst
[i
] != byte(i
&127) {
42 t
.Fatalf("prefix dst[%d] = %d", i
, dst
[i
])
45 for i
:= y
; i
< y
+n
; i
++ {
46 if dst
[i
] != byte(128+((i
-y
+x
)&127)) {
47 t
.Fatalf("copied dst[%d] = %d", i
, dst
[i
])
49 dst
[i
] = byte(i
& 127) // reset dst
51 for i
:= y
+ n
; i
< size
; i
++ {
52 if dst
[i
] != byte(i
&127) {
53 t
.Fatalf("suffix dst[%d] = %d", i
, dst
[i
])
61 func TestMemmoveAlias(t
*testing
.T
) {
70 buf
:= make([]byte, size
)
71 for i
:= 0; i
< size
; i
++ {
74 for n
:= 0; n
<= size
; n
++ {
75 for x
:= 0; x
<= size
-n
; x
++ { // src offset
76 for y
:= 0; y
<= size
-n
; y
++ { // dst offset
77 copy(buf
[y
:y
+n
], buf
[x
:x
+n
])
78 for i
:= 0; i
< y
; i
++ {
79 if buf
[i
] != byte(i
) {
80 t
.Fatalf("prefix buf[%d] = %d", i
, buf
[i
])
83 for i
:= y
; i
< y
+n
; i
++ {
84 if buf
[i
] != byte(i
-y
+x
) {
85 t
.Fatalf("copied buf[%d] = %d", i
, buf
[i
])
87 buf
[i
] = byte(i
) // reset buf
89 for i
:= y
+ n
; i
< size
; i
++ {
90 if buf
[i
] != byte(i
) {
91 t
.Fatalf("suffix buf[%d] = %d", i
, buf
[i
])
99 func TestMemmoveLarge0x180000(t
*testing
.T
) {
100 if testing
.Short() && testenv
.Builder() == "" {
106 t
.Skip("skipping large memmove test under race detector")
108 testSize(t
, 0x180000)
111 func TestMemmoveOverlapLarge0x120000(t
*testing
.T
) {
112 if testing
.Short() && testenv
.Builder() == "" {
118 t
.Skip("skipping large memmove test under race detector")
120 testOverlap(t
, 0x120000)
123 func testSize(t
*testing
.T
, size
int) {
124 src
:= make([]byte, size
)
125 dst
:= make([]byte, size
)
126 _
, _
= rand
.Read(src
)
127 _
, _
= rand
.Read(dst
)
129 ref
:= make([]byte, size
)
132 for n
:= size
- 50; n
> 1; n
>>= 1 {
133 for x
:= 0; x
<= size
-n
; x
= x
*7 + 1 { // offset in src
134 for y
:= 0; y
<= size
-n
; y
= y
*9 + 1 { // offset in dst
135 copy(dst
[y
:y
+n
], src
[x
:x
+n
])
136 copyref(ref
[y
:y
+n
], src
[x
:x
+n
])
139 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
])
146 func testOverlap(t
*testing
.T
, size
int) {
147 src
:= make([]byte, size
)
148 test
:= make([]byte, size
)
149 ref
:= make([]byte, size
)
150 _
, _
= rand
.Read(src
)
152 for n
:= size
- 50; n
> 1; n
>>= 1 {
153 for x
:= 0; x
<= size
-n
; x
= x
*7 + 1 { // offset in src
154 for y
:= 0; y
<= size
-n
; y
= y
*9 + 1 { // offset in dst
158 copy(test
[y
:y
+n
], test
[x
:x
+n
])
160 copyref(ref
[y
:y
+n
], ref
[x
:x
+n
])
162 copybw(ref
[y
:y
+n
], ref
[x
:x
+n
])
166 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
])
175 func copyref(dst
, src
[]byte) {
176 for i
, v
:= range src
{
182 func copybw(dst
, src
[]byte) {
186 for i
:= len(src
) - 1; i
>= 0; i
-- {
191 // Returns offset of difference
192 func matchLen(a
, b
[]byte, max
int) int {
195 for i
, av
:= range a
{
203 func cmpb(a
, b
[]byte) int {
204 l
:= matchLen(a
, b
, len(a
))
211 // Ensure that memmove writes pointers atomically, so the GC won't
212 // observe a partially updated pointer.
213 func TestMemmoveAtomicity(t
*testing
.T
) {
215 t
.Skip("skip under the race detector -- this test is intentionally racy")
220 for _
, backward
:= range []bool{true, false} {
221 for _
, n
:= range []int{3, 4, 5, 6, 7, 8, 9, 10, 15, 25, 49} {
224 // test copying [N]*int.
225 sz
:= uintptr(n
* PtrSize
)
226 name
:= fmt
.Sprint(sz
)
232 t
.Run(name
, func(t
*testing
.T
) {
233 // Use overlapping src and dst to force forward/backward copy.
235 src
:= s
[n
-1 : 2*n
-1]
249 sp
:= unsafe
.Pointer(&src
[0])
250 dp
:= unsafe
.Pointer(&dst
[0])
251 atomic
.StoreUint32(&ready
, 1)
252 for i
:= 0; i
< 10000; i
++ {
254 MemclrNoHeapPointers(dp
, sz
)
256 atomic
.StoreUint32(&ready
, 2)
259 for atomic
.LoadUint32(&ready
) == 0 {
263 for atomic
.LoadUint32(&ready
) != 2 {
266 if p
!= nil && p
!= &x
{
267 t
.Fatalf("got partially updated pointer %p at dst[%d], want either nil or %p", p
, i
, &x
)
276 func benchmarkSizes(b
*testing
.B
, sizes
[]int, fn
func(b
*testing
.B
, n
int)) {
277 for _
, n
:= range sizes
{
278 b
.Run(fmt
.Sprint(n
), func(b
*testing
.B
) {
285 var bufSizes
= []int{
286 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
287 32, 64, 128, 256, 512, 1024, 2048, 4096,
289 var bufSizesOverlap
= []int{
290 32, 64, 128, 256, 512, 1024, 2048, 4096,
293 func BenchmarkMemmove(b
*testing
.B
) {
294 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
297 for i
:= 0; i
< b
.N
; i
++ {
303 func BenchmarkMemmoveOverlap(b
*testing
.B
) {
304 benchmarkSizes(b
, bufSizesOverlap
, func(b
*testing
.B
, n
int) {
305 x
:= make([]byte, n
+16)
306 for i
:= 0; i
< b
.N
; i
++ {
307 copy(x
[16:n
+16], x
[:n
])
312 func BenchmarkMemmoveUnalignedDst(b
*testing
.B
) {
313 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
314 x
:= make([]byte, n
+1)
316 for i
:= 0; i
< b
.N
; i
++ {
322 func BenchmarkMemmoveUnalignedDstOverlap(b
*testing
.B
) {
323 benchmarkSizes(b
, bufSizesOverlap
, func(b
*testing
.B
, n
int) {
324 x
:= make([]byte, n
+16)
325 for i
:= 0; i
< b
.N
; i
++ {
326 copy(x
[16:n
+16], x
[1:n
+1])
331 func BenchmarkMemmoveUnalignedSrc(b
*testing
.B
) {
332 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
334 y
:= make([]byte, n
+1)
335 for i
:= 0; i
< b
.N
; i
++ {
341 func BenchmarkMemmoveUnalignedSrcOverlap(b
*testing
.B
) {
342 benchmarkSizes(b
, bufSizesOverlap
, func(b
*testing
.B
, n
int) {
343 x
:= make([]byte, n
+1)
344 for i
:= 0; i
< b
.N
; i
++ {
345 copy(x
[1:n
+1], x
[:n
])
350 func TestMemclr(t
*testing
.T
) {
355 mem
:= make([]byte, size
)
356 for i
:= 0; i
< size
; i
++ {
359 for n
:= 0; n
< size
; n
++ {
360 for x
:= 0; x
<= size
-n
; x
++ { // offset in mem
361 MemclrBytes(mem
[x
: x
+n
])
362 for i
:= 0; i
< x
; i
++ {
364 t
.Fatalf("overwrite prefix mem[%d] = %d", i
, mem
[i
])
367 for i
:= x
; i
< x
+n
; i
++ {
369 t
.Fatalf("failed clear mem[%d] = %d", i
, mem
[i
])
373 for i
:= x
+ n
; i
< size
; i
++ {
375 t
.Fatalf("overwrite suffix mem[%d] = %d", i
, mem
[i
])
382 func BenchmarkMemclr(b
*testing
.B
) {
383 for _
, n
:= range []int{5, 16, 64, 256, 4096, 65536} {
385 b
.Run(fmt
.Sprint(n
), func(b
*testing
.B
) {
387 for i
:= 0; i
< b
.N
; i
++ {
392 for _
, m
:= range []int{1, 4, 8, 16, 64} {
393 x
:= make([]byte, m
<<20)
394 b
.Run(fmt
.Sprint(m
, "M"), func(b
*testing
.B
) {
395 b
.SetBytes(int64(m
<< 20))
396 for i
:= 0; i
< b
.N
; i
++ {
403 func BenchmarkGoMemclr(b
*testing
.B
) {
404 benchmarkSizes(b
, []int{5, 16, 64, 256}, func(b
*testing
.B
, n
int) {
406 for i
:= 0; i
< b
.N
; i
++ {
414 func BenchmarkClearFat8(b
*testing
.B
) {
415 for i
:= 0; i
< b
.N
; i
++ {
420 func BenchmarkClearFat12(b
*testing
.B
) {
421 for i
:= 0; i
< b
.N
; i
++ {
426 func BenchmarkClearFat16(b
*testing
.B
) {
427 for i
:= 0; i
< b
.N
; i
++ {
432 func BenchmarkClearFat24(b
*testing
.B
) {
433 for i
:= 0; i
< b
.N
; i
++ {
438 func BenchmarkClearFat32(b
*testing
.B
) {
439 for i
:= 0; i
< b
.N
; i
++ {
444 func BenchmarkClearFat40(b
*testing
.B
) {
445 for i
:= 0; i
< b
.N
; i
++ {
450 func BenchmarkClearFat48(b
*testing
.B
) {
451 for i
:= 0; i
< b
.N
; i
++ {
456 func BenchmarkClearFat56(b
*testing
.B
) {
457 for i
:= 0; i
< b
.N
; i
++ {
462 func BenchmarkClearFat64(b
*testing
.B
) {
463 for i
:= 0; i
< b
.N
; i
++ {
468 func BenchmarkClearFat128(b
*testing
.B
) {
469 for i
:= 0; i
< b
.N
; i
++ {
470 var x
[128 / 4]uint32
474 func BenchmarkClearFat256(b
*testing
.B
) {
475 for i
:= 0; i
< b
.N
; i
++ {
476 var x
[256 / 4]uint32
480 func BenchmarkClearFat512(b
*testing
.B
) {
481 for i
:= 0; i
< b
.N
; i
++ {
482 var x
[512 / 4]uint32
486 func BenchmarkClearFat1024(b
*testing
.B
) {
487 for i
:= 0; i
< b
.N
; i
++ {
488 var x
[1024 / 4]uint32
493 func BenchmarkCopyFat8(b
*testing
.B
) {
495 for i
:= 0; i
< b
.N
; i
++ {
500 func BenchmarkCopyFat12(b
*testing
.B
) {
502 for i
:= 0; i
< b
.N
; i
++ {
507 func BenchmarkCopyFat16(b
*testing
.B
) {
509 for i
:= 0; i
< b
.N
; i
++ {
514 func BenchmarkCopyFat24(b
*testing
.B
) {
516 for i
:= 0; i
< b
.N
; i
++ {
521 func BenchmarkCopyFat32(b
*testing
.B
) {
523 for i
:= 0; i
< b
.N
; i
++ {
528 func BenchmarkCopyFat64(b
*testing
.B
) {
530 for i
:= 0; i
< b
.N
; i
++ {
535 func BenchmarkCopyFat128(b
*testing
.B
) {
536 var x
[128 / 4]uint32
537 for i
:= 0; i
< b
.N
; i
++ {
542 func BenchmarkCopyFat256(b
*testing
.B
) {
543 var x
[256 / 4]uint32
544 for i
:= 0; i
< b
.N
; i
++ {
549 func BenchmarkCopyFat512(b
*testing
.B
) {
550 var x
[512 / 4]uint32
551 for i
:= 0; i
< b
.N
; i
++ {
556 func BenchmarkCopyFat520(b
*testing
.B
) {
557 var x
[520 / 4]uint32
558 for i
:= 0; i
< b
.N
; i
++ {
563 func BenchmarkCopyFat1024(b
*testing
.B
) {
564 var x
[1024 / 4]uint32
565 for i
:= 0; i
< b
.N
; i
++ {
571 // BenchmarkIssue18740 ensures that memmove uses 4 and 8 byte load/store to move 4 and 8 bytes.
572 // It used to do 2 2-byte load/stores, which leads to a pipeline stall
573 // when we try to read the result with one 4-byte load.
574 func BenchmarkIssue18740(b
*testing
.B
) {
575 benchmarks
:= []struct {
578 f
func([]byte) uint64
580 {"2byte", 2, func(buf
[]byte) uint64 { return uint64(binary
.LittleEndian
.Uint16(buf
)) }},
581 {"4byte", 4, func(buf
[]byte) uint64 { return uint64(binary
.LittleEndian
.Uint32(buf
)) }},
582 {"8byte", 8, func(buf
[]byte) uint64 { return binary
.LittleEndian
.Uint64(buf
) }},
586 for _
, bm
:= range benchmarks
{
587 buf
:= make([]byte, bm
.nbyte
)
588 b
.Run(bm
.name
, func(b
*testing
.B
) {
589 for j
:= 0; j
< b
.N
; j
++ {
590 for i
:= 0; i
< 4096; i
+= bm
.nbyte
{