xref: /isa-l/erasure_code/erasure_code_update_perf.c (revision 07f8028743e20a585675e51e0fcbba2455e84cd5)
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