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.
17 func TestMemmove(t
*testing
.T
) {
23 src
:= make([]byte, size
)
24 dst
:= make([]byte, size
)
25 for i
:= 0; i
< size
; i
++ {
26 src
[i
] = byte(128 + (i
& 127))
28 for i
:= 0; i
< size
; i
++ {
29 dst
[i
] = byte(i
& 127)
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
])
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
])
44 dst
[i
] = byte(i
& 127) // reset dst
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
])
56 func TestMemmoveAlias(t
*testing
.T
) {
62 buf
:= make([]byte, size
)
63 for i
:= 0; i
< size
; i
++ {
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
])
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
])
79 buf
[i
] = byte(i
) // reset buf
81 for i
:= y
+ n
; i
< size
; i
++ {
82 if buf
[i
] != byte(i
) {
83 t
.Fatalf("suffix buf[%d] = %d", i
, buf
[i
])
91 func TestMemmoveLarge0x180000(t
*testing
.T
) {
92 if testing
.Short() && testenv
.Builder() == "" {
98 t
.Skip("skipping large memmove test under race detector")
100 testSize(t
, 0x180000)
103 func TestMemmoveOverlapLarge0x120000(t
*testing
.T
) {
104 if testing
.Short() && testenv
.Builder() == "" {
110 t
.Skip("skipping large memmove test under race detector")
112 testOverlap(t
, 0x120000)
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
)
121 ref
:= make([]byte, size
)
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
])
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
])
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
)
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
150 copy(test
[y
:y
+n
], test
[x
:x
+n
])
152 copyref(ref
[y
:y
+n
], ref
[x
:x
+n
])
154 copybw(ref
[y
:y
+n
], ref
[x
:x
+n
])
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
])
167 func copyref(dst
, src
[]byte) {
168 for i
, v
:= range src
{
174 func copybw(dst
, src
[]byte) {
178 for i
:= len(src
) - 1; i
>= 0; i
-- {
183 // Returns offset of difference
184 func matchLen(a
, b
[]byte, max
int) int {
187 for i
, av
:= range a
{
195 func cmpb(a
, b
[]byte) int {
196 l
:= matchLen(a
, b
, len(a
))
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
) {
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,
217 func BenchmarkMemmove(b
*testing
.B
) {
218 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
221 for i
:= 0; i
< b
.N
; i
++ {
227 func BenchmarkMemmoveUnalignedDst(b
*testing
.B
) {
228 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
229 x
:= make([]byte, n
+1)
231 for i
:= 0; i
< b
.N
; i
++ {
237 func BenchmarkMemmoveUnalignedSrc(b
*testing
.B
) {
238 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
240 y
:= make([]byte, n
+1)
241 for i
:= 0; i
< b
.N
; i
++ {
247 func TestMemclr(t
*testing
.T
) {
252 mem
:= make([]byte, size
)
253 for i
:= 0; i
< size
; i
++ {
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
++ {
261 t
.Fatalf("overwrite prefix mem[%d] = %d", i
, mem
[i
])
264 for i
:= x
; i
< x
+n
; i
++ {
266 t
.Fatalf("failed clear mem[%d] = %d", i
, mem
[i
])
270 for i
:= x
+ n
; i
< size
; i
++ {
272 t
.Fatalf("overwrite suffix mem[%d] = %d", i
, mem
[i
])
279 func BenchmarkMemclr(b
*testing
.B
) {
280 for _
, n
:= range []int{5, 16, 64, 256, 4096, 65536} {
282 b
.Run(fmt
.Sprint(n
), func(b
*testing
.B
) {
284 for i
:= 0; i
< b
.N
; i
++ {
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
++ {
300 func BenchmarkGoMemclr(b
*testing
.B
) {
301 benchmarkSizes(b
, []int{5, 16, 64, 256}, func(b
*testing
.B
, n
int) {
303 for i
:= 0; i
< b
.N
; i
++ {
311 func BenchmarkClearFat8(b
*testing
.B
) {
312 for i
:= 0; i
< b
.N
; i
++ {
317 func BenchmarkClearFat12(b
*testing
.B
) {
318 for i
:= 0; i
< b
.N
; i
++ {
323 func BenchmarkClearFat16(b
*testing
.B
) {
324 for i
:= 0; i
< b
.N
; i
++ {
329 func BenchmarkClearFat24(b
*testing
.B
) {
330 for i
:= 0; i
< b
.N
; i
++ {
335 func BenchmarkClearFat32(b
*testing
.B
) {
336 for i
:= 0; i
< b
.N
; i
++ {
341 func BenchmarkClearFat40(b
*testing
.B
) {
342 for i
:= 0; i
< b
.N
; i
++ {
347 func BenchmarkClearFat48(b
*testing
.B
) {
348 for i
:= 0; i
< b
.N
; i
++ {
353 func BenchmarkClearFat56(b
*testing
.B
) {
354 for i
:= 0; i
< b
.N
; i
++ {
359 func BenchmarkClearFat64(b
*testing
.B
) {
360 for i
:= 0; i
< b
.N
; i
++ {
365 func BenchmarkClearFat128(b
*testing
.B
) {
366 for i
:= 0; i
< b
.N
; i
++ {
367 var x
[128 / 4]uint32
371 func BenchmarkClearFat256(b
*testing
.B
) {
372 for i
:= 0; i
< b
.N
; i
++ {
373 var x
[256 / 4]uint32
377 func BenchmarkClearFat512(b
*testing
.B
) {
378 for i
:= 0; i
< b
.N
; i
++ {
379 var x
[512 / 4]uint32
383 func BenchmarkClearFat1024(b
*testing
.B
) {
384 for i
:= 0; i
< b
.N
; i
++ {
385 var x
[1024 / 4]uint32
390 func BenchmarkCopyFat8(b
*testing
.B
) {
392 for i
:= 0; i
< b
.N
; i
++ {
397 func BenchmarkCopyFat12(b
*testing
.B
) {
399 for i
:= 0; i
< b
.N
; i
++ {
404 func BenchmarkCopyFat16(b
*testing
.B
) {
406 for i
:= 0; i
< b
.N
; i
++ {
411 func BenchmarkCopyFat24(b
*testing
.B
) {
413 for i
:= 0; i
< b
.N
; i
++ {
418 func BenchmarkCopyFat32(b
*testing
.B
) {
420 for i
:= 0; i
< b
.N
; i
++ {
425 func BenchmarkCopyFat64(b
*testing
.B
) {
427 for i
:= 0; i
< b
.N
; i
++ {
432 func BenchmarkCopyFat128(b
*testing
.B
) {
433 var x
[128 / 4]uint32
434 for i
:= 0; i
< b
.N
; i
++ {
439 func BenchmarkCopyFat256(b
*testing
.B
) {
440 var x
[256 / 4]uint32
441 for i
:= 0; i
< b
.N
; i
++ {
446 func BenchmarkCopyFat512(b
*testing
.B
) {
447 var x
[512 / 4]uint32
448 for i
:= 0; i
< b
.N
; i
++ {
453 func BenchmarkCopyFat1024(b
*testing
.B
) {
454 var x
[1024 / 4]uint32
455 for i
:= 0; i
< b
.N
; i
++ {
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.
466 for j
:= 0; j
< b
.N
; j
++ {
468 for i
:= 0; i
< 4096; i
+= 4 {
470 s
+= binary
.LittleEndian
.Uint32(buf
[:])
476 // TODO: 2 byte and 8 byte benchmarks also.