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.
16 func TestMemmove(t
*testing
.T
) {
22 src
:= make([]byte, size
)
23 dst
:= make([]byte, size
)
24 for i
:= 0; i
< size
; i
++ {
25 src
[i
] = byte(128 + (i
& 127))
27 for i
:= 0; i
< size
; i
++ {
28 dst
[i
] = byte(i
& 127)
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
])
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
])
43 dst
[i
] = byte(i
& 127) // reset dst
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
])
55 func TestMemmoveAlias(t
*testing
.T
) {
61 buf
:= make([]byte, size
)
62 for i
:= 0; i
< size
; i
++ {
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
])
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
])
78 buf
[i
] = byte(i
) // reset buf
80 for i
:= y
+ n
; i
< size
; i
++ {
81 if buf
[i
] != byte(i
) {
82 t
.Fatalf("suffix buf[%d] = %d", i
, buf
[i
])
90 func TestMemmoveLarge0x180000(t
*testing
.T
) {
93 t
.Skip("skipping large memmove test under race detector")
98 func TestMemmoveOverlapLarge0x120000(t
*testing
.T
) {
101 t
.Skip("skipping large memmove test under race detector")
103 testOverlap(t
, 0x120000)
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
)
112 ref
:= make([]byte, size
)
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
])
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
])
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
)
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
141 copy(test
[y
:y
+n
], test
[x
:x
+n
])
143 copyref(ref
[y
:y
+n
], ref
[x
:x
+n
])
145 copybw(ref
[y
:y
+n
], ref
[x
:x
+n
])
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
])
158 func copyref(dst
, src
[]byte) {
159 for i
, v
:= range src
{
165 func copybw(dst
, src
[]byte) {
169 for i
:= len(src
) - 1; i
>= 0; i
-- {
174 // Returns offset of difference
175 func matchLen(a
, b
[]byte, max
int) int {
178 for i
, av
:= range a
{
186 func cmpb(a
, b
[]byte) int {
187 l
:= matchLen(a
, b
, len(a
))
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
) {
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,
208 func BenchmarkMemmove(b
*testing
.B
) {
209 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
212 for i
:= 0; i
< b
.N
; i
++ {
218 func BenchmarkMemmoveUnalignedDst(b
*testing
.B
) {
219 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
220 x
:= make([]byte, n
+1)
222 for i
:= 0; i
< b
.N
; i
++ {
228 func BenchmarkMemmoveUnalignedSrc(b
*testing
.B
) {
229 benchmarkSizes(b
, bufSizes
, func(b
*testing
.B
, n
int) {
231 y
:= make([]byte, n
+1)
232 for i
:= 0; i
< b
.N
; i
++ {
238 func TestMemclr(t
*testing
.T
) {
243 mem
:= make([]byte, size
)
244 for i
:= 0; i
< size
; i
++ {
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
++ {
252 t
.Fatalf("overwrite prefix mem[%d] = %d", i
, mem
[i
])
255 for i
:= x
; i
< x
+n
; i
++ {
257 t
.Fatalf("failed clear mem[%d] = %d", i
, mem
[i
])
261 for i
:= x
+ n
; i
< size
; i
++ {
263 t
.Fatalf("overwrite suffix mem[%d] = %d", i
, mem
[i
])
270 func BenchmarkMemclr(b
*testing
.B
) {
271 for _
, n
:= range []int{5, 16, 64, 256, 4096, 65536} {
273 b
.Run(fmt
.Sprint(n
), func(b
*testing
.B
) {
275 for i
:= 0; i
< b
.N
; i
++ {
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
++ {
291 func BenchmarkGoMemclr(b
*testing
.B
) {
292 benchmarkSizes(b
, []int{5, 16, 64, 256}, func(b
*testing
.B
, n
int) {
294 for i
:= 0; i
< b
.N
; i
++ {
302 func BenchmarkClearFat8(b
*testing
.B
) {
303 for i
:= 0; i
< b
.N
; i
++ {
308 func BenchmarkClearFat12(b
*testing
.B
) {
309 for i
:= 0; i
< b
.N
; i
++ {
314 func BenchmarkClearFat16(b
*testing
.B
) {
315 for i
:= 0; i
< b
.N
; i
++ {
320 func BenchmarkClearFat24(b
*testing
.B
) {
321 for i
:= 0; i
< b
.N
; i
++ {
326 func BenchmarkClearFat32(b
*testing
.B
) {
327 for i
:= 0; i
< b
.N
; i
++ {
332 func BenchmarkClearFat40(b
*testing
.B
) {
333 for i
:= 0; i
< b
.N
; i
++ {
338 func BenchmarkClearFat48(b
*testing
.B
) {
339 for i
:= 0; i
< b
.N
; i
++ {
344 func BenchmarkClearFat56(b
*testing
.B
) {
345 for i
:= 0; i
< b
.N
; i
++ {
350 func BenchmarkClearFat64(b
*testing
.B
) {
351 for i
:= 0; i
< b
.N
; i
++ {
356 func BenchmarkClearFat128(b
*testing
.B
) {
357 for i
:= 0; i
< b
.N
; i
++ {
358 var x
[128 / 4]uint32
362 func BenchmarkClearFat256(b
*testing
.B
) {
363 for i
:= 0; i
< b
.N
; i
++ {
364 var x
[256 / 4]uint32
368 func BenchmarkClearFat512(b
*testing
.B
) {
369 for i
:= 0; i
< b
.N
; i
++ {
370 var x
[512 / 4]uint32
374 func BenchmarkClearFat1024(b
*testing
.B
) {
375 for i
:= 0; i
< b
.N
; i
++ {
376 var x
[1024 / 4]uint32
381 func BenchmarkCopyFat8(b
*testing
.B
) {
383 for i
:= 0; i
< b
.N
; i
++ {
388 func BenchmarkCopyFat12(b
*testing
.B
) {
390 for i
:= 0; i
< b
.N
; i
++ {
395 func BenchmarkCopyFat16(b
*testing
.B
) {
397 for i
:= 0; i
< b
.N
; i
++ {
402 func BenchmarkCopyFat24(b
*testing
.B
) {
404 for i
:= 0; i
< b
.N
; i
++ {
409 func BenchmarkCopyFat32(b
*testing
.B
) {
411 for i
:= 0; i
< b
.N
; i
++ {
416 func BenchmarkCopyFat64(b
*testing
.B
) {
418 for i
:= 0; i
< b
.N
; i
++ {
423 func BenchmarkCopyFat128(b
*testing
.B
) {
424 var x
[128 / 4]uint32
425 for i
:= 0; i
< b
.N
; i
++ {
430 func BenchmarkCopyFat256(b
*testing
.B
) {
431 var x
[256 / 4]uint32
432 for i
:= 0; i
< b
.N
; i
++ {
437 func BenchmarkCopyFat512(b
*testing
.B
) {
438 var x
[512 / 4]uint32
439 for i
:= 0; i
< b
.N
; i
++ {
444 func BenchmarkCopyFat1024(b
*testing
.B
) {
445 var x
[1024 / 4]uint32
446 for i
:= 0; i
< b
.N
; i
++ {
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.
457 for j
:= 0; j
< b
.N
; j
++ {
459 for i
:= 0; i
< 4096; i
+= 4 {
461 s
+= binary
.LittleEndian
.Uint32(buf
[:])
467 // TODO: 2 byte and 8 byte benchmarks also.