1 /********************************************************************** 2 Copyright(c) 2011-2015 Intel Corporation All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions 6 are met: 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above copyright 10 notice, this list of conditions and the following disclaimer in 11 the documentation and/or other materials provided with the 12 distribution. 13 * Neither the name of Intel Corporation nor the names of its 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 **********************************************************************/ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> // for memset, memcmp 33 #include "erasure_code.h" 34 #include "test.h" 35 36 // By default, test multibinary version 37 #ifndef FUNCTION_UNDER_TEST 38 #define FUNCTION_UNDER_TEST ec_encode_data_update 39 #define REF_FUNCTION ec_encode_data 40 #endif 41 42 // By default, test EC(8+4) 43 #if (!defined(VECT)) 44 #define VECT 4 45 #endif 46 47 #define str(s) #s 48 #define xstr(s) str(s) 49 50 #ifndef GT_L3_CACHE 51 #define GT_L3_CACHE 32 * 1024 * 1024 /* some number > last level cache */ 52 #endif 53 54 #if !defined(COLD_TEST) && !defined(TEST_CUSTOM) 55 // Cached test, loop many times over small dataset 56 #define TEST_SOURCES 32 57 #define TEST_LEN(m) ((128 * 1024 / m) & ~(64 - 1)) 58 #define TEST_TYPE_STR "_warm" 59 #elif defined(COLD_TEST) 60 // Uncached test. Pull from large mem base. 61 #define TEST_SOURCES 32 62 #define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64 - 1)) 63 #define TEST_TYPE_STR "_cold" 64 #elif defined(TEST_CUSTOM) 65 #define TEST_TYPE_STR "_cus" 66 #endif 67 #ifndef TEST_SEED 68 #define TEST_SEED 0x1234 69 #endif 70 71 #define MMAX TEST_SOURCES 72 #define KMAX TEST_SOURCES 73 74 typedef unsigned char u8; 75 76 void 77 usage(const char *app_name) 78 { 79 fprintf(stderr, 80 "Usage: %s [options]\n" 81 " -h Help\n" 82 " -k <val> Number of source buffers\n" 83 " -p <val> Number of parity buffers\n" 84 " -e <val> Number of simulated buffers with errors (cannot be higher than p or " 85 "k)\n", 86 app_name); 87 } 88 89 void 90 dump(unsigned char *buf, int len) 91 { 92 int i; 93 for (i = 0; i < len;) { 94 printf(" %2x", 0xff & buf[i++]); 95 if (i % 32 == 0) 96 printf("\n"); 97 } 98 printf("\n"); 99 } 100 101 void 102 encode_update_test_ref(int m, int k, u8 *g_tbls, u8 **buffs, u8 *a) 103 { 104 ec_init_tables(k, m - k, &a[k * k], g_tbls); 105 REF_FUNCTION(TEST_LEN(m), k, m - k, g_tbls, buffs, &buffs[k]); 106 } 107 108 void 109 encode_update_test(int m, int k, u8 *g_tbls, u8 **perf_update_buffs, u8 *a) 110 { 111 int i; 112 113 // Make parity vects 114 ec_init_tables(k, m - k, &a[k * k], g_tbls); 115 for (i = 0; i < k; i++) { 116 FUNCTION_UNDER_TEST(TEST_LEN(m), k, m - k, i, g_tbls, perf_update_buffs[i], 117 &perf_update_buffs[k]); 118 } 119 } 120 121 int 122 decode_test(int m, int k, u8 **update_buffs, u8 **recov, u8 *a, u8 *src_in_err, u8 *src_err_list, 123 int nerrs, u8 *g_tbls, u8 **perf_update_buffs) 124 { 125 int i, j, r; 126 u8 b[MMAX * KMAX], c[MMAX * KMAX], d[MMAX * KMAX]; 127 // Construct b by removing error rows 128 for (i = 0, r = 0; i < k; i++, r++) { 129 while (src_in_err[r]) 130 r++; 131 recov[i] = update_buffs[r]; 132 for (j = 0; j < k; j++) 133 b[k * i + j] = a[k * r + j]; 134 } 135 136 if (gf_invert_matrix(b, d, k) < 0) { 137 printf("BAD MATRIX\n"); 138 return -1; 139 } 140 141 for (i = 0; i < nerrs; i++) 142 for (j = 0; j < k; j++) 143 c[k * i + j] = d[k * src_err_list[i] + j]; 144 145 // Recover data 146 ec_init_tables(k, nerrs, c, g_tbls); 147 for (i = 0; i < k; i++) { 148 FUNCTION_UNDER_TEST(TEST_LEN(m), k, nerrs, i, g_tbls, recov[i], perf_update_buffs); 149 } 150 return 0; 151 } 152 153 int 154 main(int argc, char *argv[]) 155 { 156 int i, j, check, m, k, p, nerrs, ret = -1; 157 void *buf; 158 u8 *temp_buffs[TEST_SOURCES] = { NULL }; 159 u8 *buffs[TEST_SOURCES] = { NULL }; 160 u8 *update_buffs[TEST_SOURCES] = { NULL }; 161 u8 *perf_update_buffs[TEST_SOURCES] = { NULL }; 162 u8 a[MMAX * KMAX]; 163 u8 g_tbls[KMAX * TEST_SOURCES * 32], src_in_err[TEST_SOURCES]; 164 u8 src_err_list[TEST_SOURCES], *recov[TEST_SOURCES]; 165 struct perf start; 166 167 /* Set default parameters */ 168 k = 10; 169 p = VECT; 170 nerrs = VECT; 171 172 /* Parse arguments */ 173 for (i = 1; i < argc; i++) { 174 if (strcmp(argv[i], "-k") == 0) { 175 k = atoi(argv[++i]); 176 } else if (strcmp(argv[i], "-p") == 0) { 177 p = atoi(argv[++i]); 178 } else if (strcmp(argv[i], "-e") == 0) { 179 nerrs = atoi(argv[++i]); 180 } else if (strcmp(argv[i], "-h") == 0) { 181 usage(argv[0]); 182 return 0; 183 } else { 184 usage(argv[0]); 185 return -1; 186 } 187 } 188 189 if (nerrs > k) { 190 printf("Number of errors (%d) cannot be higher than number of data buffers (%d)\n", 191 nerrs, k); 192 return -1; 193 } 194 195 if (k <= 0) { 196 printf("Number of source buffers (%d) must be > 0\n", k); 197 return -1; 198 } 199 200 if (p <= 0) { 201 printf("Number of parity buffers (%d) must be > 0\n", p); 202 return -1; 203 } 204 205 if (nerrs > p) { 206 printf("Number of errors (%d) cannot be higher than number of parity buffers " 207 "(%d)\n", 208 nerrs, p); 209 return -1; 210 } 211 212 if (nerrs <= 0) { 213 printf("Number of errors (%d) must be > 0\n", nerrs); 214 return -1; 215 } 216 217 m = k + p; 218 219 if (m > MMAX) { 220 printf("Number of total buffers (data and parity) cannot be higher than %d\n", 221 MMAX); 222 return -1; 223 } 224 225 u8 *err_list = malloc((size_t) nerrs); 226 if (err_list == NULL) { 227 printf("Error allocating list of array of error indices\n"); 228 return -1; 229 } 230 231 srand(TEST_SEED); 232 233 for (i = 0; i < nerrs;) { 234 u8 next_err = rand() % k; 235 for (j = 0; j < i; j++) 236 if (next_err == err_list[j]) 237 break; 238 if (j != i) 239 continue; 240 err_list[i++] = next_err; 241 } 242 243 printf("Testing with %u data buffers and %u parity buffers (num errors = %u, in [ ", k, p, 244 nerrs); 245 for (i = 0; i < nerrs; i++) 246 printf("%d ", err_list[i]); 247 248 printf("])\n"); 249 250 printf(xstr(FUNCTION_UNDER_TEST) "_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs); 251 252 memcpy(src_err_list, err_list, nerrs); 253 memset(src_in_err, 0, TEST_SOURCES); 254 for (i = 0; i < nerrs; i++) 255 src_in_err[src_err_list[i]] = 1; 256 257 // Allocate the arrays 258 for (i = 0; i < m; i++) { 259 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 260 printf("Error allocating buffers\n"); 261 goto exit; 262 } 263 buffs[i] = buf; 264 } 265 266 for (i = 0; i < (m - k); i++) { 267 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 268 printf("Error allocating buffers\n"); 269 goto exit; 270 } 271 temp_buffs[i] = buf; 272 memset(temp_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be 273 // zero for update function 274 } 275 276 for (i = 0; i < TEST_SOURCES; i++) { 277 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 278 printf("Error allocating buffers\n"); 279 goto exit; 280 } 281 update_buffs[i] = buf; 282 memset(update_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be 283 // zero for update function 284 } 285 for (i = 0; i < TEST_SOURCES; i++) { 286 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 287 printf("Error allocating buffers\n"); 288 goto exit; 289 } 290 perf_update_buffs[i] = buf; 291 memset(perf_update_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer 292 // to be zero for update function 293 } 294 295 // Make random data 296 for (i = 0; i < k; i++) 297 for (j = 0; j < TEST_LEN(m); j++) { 298 buffs[i][j] = rand(); 299 update_buffs[i][j] = buffs[i][j]; 300 } 301 302 gf_gen_rs_matrix(a, m, k); 303 304 encode_update_test_ref(m, k, g_tbls, buffs, a); 305 encode_update_test(m, k, g_tbls, update_buffs, a); 306 for (i = 0; i < m - k; i++) { 307 if (0 != memcmp(update_buffs[k + i], buffs[k + i], TEST_LEN(m))) { 308 printf("\nupdate_buffs%d :", i); 309 dump(update_buffs[k + i], 25); 310 printf("buffs%d :", i); 311 dump(buffs[k + i], 25); 312 goto exit; 313 } 314 } 315 316 #ifdef DO_REF_PERF 317 // Start encode test 318 BENCHMARK(&start, BENCHMARK_TIME, encode_update_test_ref(m, k, g_tbls, buffs, a)); 319 printf(xstr(REF_FUNCTION) TEST_TYPE_STR ": "); 320 perf_print(start, (long long) (TEST_LEN(m)) * (m)); 321 #endif 322 323 // Start encode test 324 BENCHMARK(&start, BENCHMARK_TIME, encode_update_test(m, k, g_tbls, perf_update_buffs, a)); 325 printf(xstr(FUNCTION_UNDER_TEST) TEST_TYPE_STR ": "); 326 perf_print(start, (long long) (TEST_LEN(m)) * (m)); 327 328 // Start encode test 329 BENCHMARK(&start, BENCHMARK_TIME, 330 // Make parity vects 331 ec_init_tables(k, m - k, &a[k * k], g_tbls); 332 FUNCTION_UNDER_TEST(TEST_LEN(m), k, m - k, 0, g_tbls, perf_update_buffs[0], 333 &perf_update_buffs[k])); 334 printf(xstr(FUNCTION_UNDER_TEST) "_single_src" TEST_TYPE_STR ": "); 335 perf_print(start, (long long) (TEST_LEN(m)) * (m - k + 1)); 336 337 // Start encode test 338 BENCHMARK(&start, BENCHMARK_TIME, 339 // Make parity vects 340 FUNCTION_UNDER_TEST(TEST_LEN(m), k, m - k, 0, g_tbls, perf_update_buffs[0], 341 &perf_update_buffs[k])); 342 printf(xstr(FUNCTION_UNDER_TEST) "_single_src_simple" TEST_TYPE_STR ": "); 343 perf_print(start, (long long) (TEST_LEN(m)) * (m - k + 1)); 344 345 for (i = k; i < m; i++) { 346 memset(update_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be 347 // zero for update function 348 } 349 for (i = 0; i < k; i++) { 350 FUNCTION_UNDER_TEST(TEST_LEN(m), k, m - k, i, g_tbls, update_buffs[i], 351 &update_buffs[k]); 352 } 353 354 decode_test(m, k, update_buffs, recov, a, src_in_err, src_err_list, nerrs, g_tbls, 355 temp_buffs); 356 BENCHMARK(&start, BENCHMARK_TIME, 357 check = decode_test(m, k, update_buffs, recov, a, src_in_err, src_err_list, nerrs, 358 g_tbls, perf_update_buffs)); 359 if (check) { 360 printf("BAD_MATRIX\n"); 361 ret = check; 362 goto exit; 363 } 364 365 for (i = 0; i < nerrs; i++) { 366 if (0 != memcmp(temp_buffs[i], update_buffs[src_err_list[i]], TEST_LEN(m))) { 367 printf("Fail error recovery (%d, %d, %d) - \n", m, k, nerrs); 368 goto exit; 369 } 370 } 371 372 printf(xstr(FUNCTION_UNDER_TEST) "_decode" TEST_TYPE_STR ": "); 373 perf_print(start, (long long) (TEST_LEN(m)) * (k + nerrs)); 374 375 printf("done all: Pass\n"); 376 377 ret = 0; 378 379 exit: 380 free(err_list); 381 for (i = 0; i < TEST_SOURCES; i++) { 382 aligned_free(buffs[i]); 383 aligned_free(temp_buffs[i]); 384 aligned_free(update_buffs[i]); 385 aligned_free(perf_update_buffs[i]); 386 } 387 return ret; 388 } 389