1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdint.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <stdlib.h> 38 39 #include <rte_common.h> 40 #include <rte_cycles.h> 41 #include <rte_random.h> 42 #include <rte_malloc.h> 43 44 #include <rte_memcpy.h> 45 46 #include "test.h" 47 48 /* 49 * Set this to the maximum buffer size you want to test. If it is 0, then the 50 * values in the buf_sizes[] array below will be used. 51 */ 52 #define TEST_VALUE_RANGE 0 53 54 /* List of buffer sizes to test */ 55 #if TEST_VALUE_RANGE == 0 56 static size_t buf_sizes[] = { 57 0, 1, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127, 128, 129, 255, 58 256, 257, 320, 384, 511, 512, 513, 1023, 1024, 1025, 1518, 1522, 1600, 59 2048, 3072, 4096, 5120, 6144, 7168, 8192 60 }; 61 /* MUST be as large as largest packet size above */ 62 #define SMALL_BUFFER_SIZE 8192 63 #else /* TEST_VALUE_RANGE != 0 */ 64 static size_t buf_sizes[TEST_VALUE_RANGE]; 65 #define SMALL_BUFFER_SIZE TEST_VALUE_RANGE 66 #endif /* TEST_VALUE_RANGE == 0 */ 67 68 69 /* 70 * Arrays of this size are used for measuring uncached memory accesses by 71 * picking a random location within the buffer. Make this smaller if there are 72 * memory allocation errors. 73 */ 74 #define LARGE_BUFFER_SIZE (100 * 1024 * 1024) 75 76 /* How many times to run timing loop for performance tests */ 77 #define TEST_ITERATIONS 1000000 78 #define TEST_BATCH_SIZE 100 79 80 /* Data is aligned on this many bytes (power of 2) */ 81 #define ALIGNMENT_UNIT 16 82 83 84 85 /* Structure with base memcpy func pointer, and number of bytes it copies */ 86 struct base_memcpy_func { 87 void (*func)(uint8_t *dst, const uint8_t *src); 88 unsigned size; 89 }; 90 91 /* To create base_memcpy_func structure entries */ 92 #define BASE_FUNC(n) {rte_mov##n, n} 93 94 /* Max number of bytes that can be copies with a "base" memcpy functions */ 95 #define MAX_BASE_FUNC_SIZE 256 96 97 /* 98 * Test the "base" memcpy functions, that a copy fixed number of bytes. 99 */ 100 static int 101 base_func_test(void) 102 { 103 const struct base_memcpy_func base_memcpy_funcs[6] = { 104 BASE_FUNC(16), 105 BASE_FUNC(32), 106 BASE_FUNC(48), 107 BASE_FUNC(64), 108 BASE_FUNC(128), 109 BASE_FUNC(256), 110 }; 111 unsigned i, j; 112 unsigned num_funcs = sizeof(base_memcpy_funcs) / sizeof(base_memcpy_funcs[0]); 113 uint8_t dst[MAX_BASE_FUNC_SIZE]; 114 uint8_t src[MAX_BASE_FUNC_SIZE]; 115 116 for (i = 0; i < num_funcs; i++) { 117 unsigned size = base_memcpy_funcs[i].size; 118 for (j = 0; j < size; j++) { 119 dst[j] = 0; 120 src[j] = (uint8_t) rte_rand(); 121 } 122 base_memcpy_funcs[i].func(dst, src); 123 for (j = 0; j < size; j++) 124 if (dst[j] != src[j]) 125 return -1; 126 } 127 128 return 0; 129 } 130 131 /* 132 * Create two buffers, and initialise one with random values. These are copied 133 * to the second buffer and then compared to see if the copy was successful. 134 * The bytes outside the copied area are also checked to make sure they were not 135 * changed. 136 */ 137 static int 138 test_single_memcpy(unsigned int off_src, unsigned int off_dst, size_t size) 139 { 140 unsigned int i; 141 uint8_t dest[SMALL_BUFFER_SIZE + ALIGNMENT_UNIT]; 142 uint8_t src[SMALL_BUFFER_SIZE + ALIGNMENT_UNIT]; 143 void * ret; 144 145 /* Setup buffers */ 146 for (i = 0; i < SMALL_BUFFER_SIZE + ALIGNMENT_UNIT; i++) { 147 dest[i] = 0; 148 src[i] = (uint8_t) rte_rand(); 149 } 150 151 /* Do the copy */ 152 ret = rte_memcpy(dest + off_dst, src + off_src, size); 153 if (ret != (dest + off_dst)) { 154 printf("rte_memcpy() returned %p, not %p\n", 155 ret, dest + off_dst); 156 } 157 158 /* Check nothing before offset is affected */ 159 for (i = 0; i < off_dst; i++) { 160 if (dest[i] != 0) { 161 printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " 162 "[modified before start of dst].\n", 163 (unsigned)size, off_src, off_dst); 164 return -1; 165 } 166 } 167 168 /* Check everything was copied */ 169 for (i = 0; i < size; i++) { 170 if (dest[i + off_dst] != src[i + off_src]) { 171 printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " 172 "[didn't copy byte %u].\n", 173 (unsigned)size, off_src, off_dst, i); 174 return -1; 175 } 176 } 177 178 /* Check nothing after copy was affected */ 179 for (i = size; i < SMALL_BUFFER_SIZE; i++) { 180 if (dest[i + off_dst] != 0) { 181 printf("rte_memcpy() failed for %u bytes (offsets=%u,%u): " 182 "[copied too many].\n", 183 (unsigned)size, off_src, off_dst); 184 return -1; 185 } 186 } 187 return 0; 188 } 189 190 /* 191 * Check functionality for various buffer sizes and data offsets/alignments. 192 */ 193 static int 194 func_test(void) 195 { 196 unsigned int off_src, off_dst, i; 197 unsigned int num_buf_sizes = sizeof(buf_sizes) / sizeof(buf_sizes[0]); 198 int ret; 199 200 for (off_src = 0; off_src < ALIGNMENT_UNIT; off_src++) { 201 for (off_dst = 0; off_dst < ALIGNMENT_UNIT; off_dst++) { 202 for (i = 0; i < num_buf_sizes; i++) { 203 ret = test_single_memcpy(off_src, off_dst, 204 buf_sizes[i]); 205 if (ret != 0) 206 return -1; 207 } 208 } 209 } 210 return 0; 211 } 212 213 static int 214 test_memcpy(void) 215 { 216 int ret; 217 218 ret = func_test(); 219 if (ret != 0) 220 return -1; 221 ret = base_func_test(); 222 if (ret != 0) 223 return -1; 224 return 0; 225 } 226 227 static struct test_command memcpy_cmd = { 228 .command = "memcpy_autotest", 229 .callback = test_memcpy, 230 }; 231 REGISTER_TEST_COMMAND(memcpy_cmd); 232