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 #ifndef GT_L3_CACHE 37 #define GT_L3_CACHE 32 * 1024 * 1024 /* some number > last level cache */ 38 #endif 39 40 #if !defined(COLD_TEST) && !defined(TEST_CUSTOM) 41 // Cached test, loop many times over small dataset 42 #define TEST_SOURCES 32 43 #define TEST_LEN(m) ((128 * 1024 / m) & ~(64 - 1)) 44 #define TEST_TYPE_STR "_warm" 45 #elif defined(COLD_TEST) 46 // Uncached test. Pull from large mem base. 47 #define TEST_SOURCES 32 48 #define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64 - 1)) 49 #define TEST_TYPE_STR "_cold" 50 #elif defined(TEST_CUSTOM) 51 #define TEST_TYPE_STR "_cus" 52 #endif 53 #ifndef TEST_SEED 54 #define TEST_SEED 0x1234 55 #endif 56 57 #define MMAX TEST_SOURCES 58 #define KMAX TEST_SOURCES 59 60 #define BAD_MATRIX -1 61 62 typedef unsigned char u8; 63 64 void 65 usage(const char *app_name) 66 { 67 fprintf(stderr, 68 "Usage: %s [options]\n" 69 " -h Help\n" 70 " -k <val> Number of source buffers\n" 71 " -p <val> Number of parity buffers\n" 72 " -e <val> Number of simulated buffers with errors (cannot be higher than p or " 73 "k)\n", 74 app_name); 75 } 76 77 void 78 ec_encode_perf(int m, int k, u8 *a, u8 *g_tbls, u8 **buffs, struct perf *start) 79 { 80 ec_init_tables(k, m - k, &a[k * k], g_tbls); 81 BENCHMARK(start, BENCHMARK_TIME, 82 ec_encode_data(TEST_LEN(m), k, m - k, g_tbls, buffs, &buffs[k])); 83 } 84 85 int 86 ec_decode_perf(int m, int k, u8 *a, u8 *g_tbls, u8 **buffs, u8 *src_in_err, u8 *src_err_list, 87 int nerrs, u8 **temp_buffs, struct perf *start) 88 { 89 int i, j, r; 90 u8 b[MMAX * KMAX], c[MMAX * KMAX], d[MMAX * KMAX]; 91 u8 *recov[TEST_SOURCES]; 92 93 // Construct b by removing error rows 94 for (i = 0, r = 0; i < k; i++, r++) { 95 while (src_in_err[r]) 96 r++; 97 recov[i] = buffs[r]; 98 for (j = 0; j < k; j++) 99 b[k * i + j] = a[k * r + j]; 100 } 101 102 if (gf_invert_matrix(b, d, k) < 0) 103 return BAD_MATRIX; 104 105 for (i = 0; i < nerrs; i++) 106 for (j = 0; j < k; j++) 107 c[k * i + j] = d[k * src_err_list[i] + j]; 108 109 // Recover data 110 ec_init_tables(k, nerrs, c, g_tbls); 111 BENCHMARK(start, BENCHMARK_TIME, 112 ec_encode_data(TEST_LEN(m), k, nerrs, g_tbls, recov, temp_buffs)); 113 114 return 0; 115 } 116 117 int 118 main(int argc, char *argv[]) 119 { 120 int i, j, m, k, p, nerrs, check, ret = -1; 121 void *buf; 122 u8 *temp_buffs[TEST_SOURCES] = { NULL }; 123 u8 *buffs[TEST_SOURCES] = { NULL }; 124 u8 a[MMAX * KMAX]; 125 u8 g_tbls[KMAX * TEST_SOURCES * 32], src_in_err[TEST_SOURCES]; 126 u8 src_err_list[TEST_SOURCES]; 127 struct perf start; 128 129 /* Set default parameters */ 130 k = 8; 131 p = 6; 132 nerrs = 4; 133 134 /* Parse arguments */ 135 for (i = 1; i < argc; i++) { 136 if (strcmp(argv[i], "-k") == 0) { 137 k = atoi(argv[++i]); 138 } else if (strcmp(argv[i], "-p") == 0) { 139 p = atoi(argv[++i]); 140 } else if (strcmp(argv[i], "-e") == 0) { 141 nerrs = atoi(argv[++i]); 142 } else if (strcmp(argv[i], "-h") == 0) { 143 usage(argv[0]); 144 return 0; 145 } else { 146 usage(argv[0]); 147 return -1; 148 } 149 } 150 151 if (nerrs > k) { 152 printf("Number of errors (%d) cannot be higher than number of data buffers (%d)\n", 153 nerrs, k); 154 return -1; 155 } 156 157 if (k <= 0) { 158 printf("Number of source buffers (%d) must be > 0\n", k); 159 return -1; 160 } 161 162 if (p <= 0) { 163 printf("Number of parity buffers (%d) must be > 0\n", p); 164 return -1; 165 } 166 167 if (nerrs <= 0) { 168 printf("Number of errors (%d) must be > 0\n", nerrs); 169 return -1; 170 } 171 172 if (nerrs > p) { 173 printf("Number of errors (%d) cannot be higher than number of parity buffers " 174 "(%d)\n", 175 nerrs, p); 176 return -1; 177 } 178 179 m = k + p; 180 181 if (m > MMAX) { 182 printf("Number of total buffers (data and parity) cannot be higher than %d\n", 183 MMAX); 184 return -1; 185 } 186 187 u8 *err_list = malloc((size_t) nerrs); 188 if (err_list == NULL) { 189 printf("Error allocating list of array of error indices\n"); 190 return -1; 191 } 192 193 srand(TEST_SEED); 194 195 for (i = 0; i < nerrs;) { 196 u8 next_err = rand() % k; 197 for (j = 0; j < i; j++) 198 if (next_err == err_list[j]) 199 break; 200 if (j != i) 201 continue; 202 err_list[i++] = next_err; 203 } 204 205 printf("Testing with %u data buffers and %u parity buffers (num errors = %u, in [ ", k, p, 206 nerrs); 207 for (i = 0; i < nerrs; i++) 208 printf("%d ", (int) err_list[i]); 209 210 printf("])\n"); 211 212 printf("erasure_code_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs); 213 214 memcpy(src_err_list, err_list, nerrs); 215 memset(src_in_err, 0, TEST_SOURCES); 216 for (i = 0; i < nerrs; i++) 217 src_in_err[src_err_list[i]] = 1; 218 219 // Allocate the arrays 220 for (i = 0; i < m; i++) { 221 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 222 printf("Error allocating buffers\n"); 223 goto exit; 224 } 225 buffs[i] = buf; 226 } 227 228 for (i = 0; i < p; i++) { 229 if (posix_memalign(&buf, 64, TEST_LEN(m))) { 230 printf("Error allocating buffers\n"); 231 goto exit; 232 } 233 temp_buffs[i] = buf; 234 } 235 236 // Make random data 237 for (i = 0; i < k; i++) 238 for (j = 0; j < TEST_LEN(m); j++) 239 buffs[i][j] = rand(); 240 241 gf_gen_rs_matrix(a, m, k); 242 243 // Start encode test 244 ec_encode_perf(m, k, a, g_tbls, buffs, &start); 245 printf("erasure_code_encode" TEST_TYPE_STR ": "); 246 perf_print(start, (long long) (TEST_LEN(m)) * (m)); 247 248 // Start decode test 249 check = ec_decode_perf(m, k, a, g_tbls, buffs, src_in_err, src_err_list, nerrs, temp_buffs, 250 &start); 251 252 if (check == BAD_MATRIX) { 253 printf("BAD MATRIX\n"); 254 ret = check; 255 goto exit; 256 } 257 258 for (i = 0; i < nerrs; i++) { 259 if (0 != memcmp(temp_buffs[i], buffs[src_err_list[i]], TEST_LEN(m))) { 260 printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); 261 goto exit; 262 } 263 } 264 265 printf("erasure_code_decode" TEST_TYPE_STR ": "); 266 perf_print(start, (long long) (TEST_LEN(m)) * (k + nerrs)); 267 268 printf("done all: Pass\n"); 269 270 ret = 0; 271 272 exit: 273 free(err_list); 274 for (i = 0; i < TEST_SOURCES; i++) { 275 aligned_free(buffs[i]); 276 aligned_free(temp_buffs[i]); 277 } 278 return ret; 279 } 280