Home | History | Annotate | Download | only in runtime
      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
    479