xref: /isa-l/erasure_code/gf_vect_dot_prod_test.c (revision 9ab5a9e579c4fb4e2a3c92d73ccd6d97291d0e80)
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 FUNCTION_UNDER_TEST
37 #define FUNCTION_UNDER_TEST gf_vect_dot_prod
38 #endif
39 #ifndef TEST_MIN_SIZE
40 #define TEST_MIN_SIZE 32
41 #endif
42 
43 #define str(s)  #s
44 #define xstr(s) str(s)
45 
46 #define TEST_LEN  8192
47 #define TEST_SIZE (TEST_LEN / 2)
48 
49 #ifndef TEST_SOURCES
50 #define TEST_SOURCES 16
51 #endif
52 #ifndef RANDOMS
53 #define RANDOMS 20
54 #endif
55 
56 #define MMAX TEST_SOURCES
57 #define KMAX TEST_SOURCES
58 
59 #ifdef EC_ALIGNED_ADDR
60 // Define power of 2 range to check ptr, len alignment
61 #define PTR_ALIGN_CHK_B 0
62 #define LEN_ALIGN_CHK_B 0 // 0 for aligned only
63 #else
64 // Define power of 2 range to check ptr, len alignment
65 #define PTR_ALIGN_CHK_B 32
66 #define LEN_ALIGN_CHK_B 32 // 0 for aligned only
67 #endif
68 
69 typedef unsigned char u8;
70 
71 void
72 dump(unsigned char *buf, int len)
73 {
74         int i;
75         for (i = 0; i < len;) {
76                 printf(" %2x", 0xff & buf[i++]);
77                 if (i % 32 == 0)
78                         printf("\n");
79         }
80         printf("\n");
81 }
82 
83 void
84 dump_matrix(unsigned char **s, int k, int m)
85 {
86         int i, j;
87         for (i = 0; i < k; i++) {
88                 for (j = 0; j < m; j++) {
89                         printf(" %2x", s[i][j]);
90                 }
91                 printf("\n");
92         }
93         printf("\n");
94 }
95 
96 void
97 dump_u8xu8(unsigned char *s, int k, int m)
98 {
99         int i, j;
100         for (i = 0; i < k; i++) {
101                 for (j = 0; j < m; j++) {
102                         printf(" %2x", 0xff & s[j + (i * m)]);
103                 }
104                 printf("\n");
105         }
106         printf("\n");
107 }
108 
109 int
110 main(int argc, char *argv[])
111 {
112         int i, j, rtest, srcs, m, k, nerrs, r, err;
113         void *buf;
114         u8 g[TEST_SOURCES], g_tbls[TEST_SOURCES * 32], src_in_err[TEST_SOURCES];
115         u8 *dest, *dest_ref, *temp_buff, *buffs[TEST_SOURCES];
116         u8 a[MMAX * KMAX], b[MMAX * KMAX], d[MMAX * KMAX];
117         u8 src_err_list[TEST_SOURCES], *recov[TEST_SOURCES];
118 
119         int align, size;
120         unsigned char *efence_buffs[TEST_SOURCES];
121         unsigned int offset;
122         u8 *ubuffs[TEST_SOURCES];
123         u8 *udest_ptr;
124 
125         printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN);
126 
127         // Allocate the arrays
128         for (i = 0; i < TEST_SOURCES; i++) {
129                 if (posix_memalign(&buf, 64, TEST_LEN)) {
130                         printf("alloc error: Fail");
131                         return -1;
132                 }
133                 buffs[i] = buf;
134         }
135 
136         if (posix_memalign(&buf, 64, TEST_LEN)) {
137                 printf("alloc error: Fail");
138                 return -1;
139         }
140         dest = buf;
141 
142         if (posix_memalign(&buf, 64, TEST_LEN)) {
143                 printf("alloc error: Fail");
144                 return -1;
145         }
146         dest_ref = buf;
147 
148         if (posix_memalign(&buf, 64, TEST_LEN)) {
149                 printf("alloc error: Fail");
150                 return -1;
151         }
152         temp_buff = buf;
153 
154         // Test of all zeros
155         for (i = 0; i < TEST_SOURCES; i++)
156                 memset(buffs[i], 0, TEST_LEN);
157 
158         memset(dest, 0, TEST_LEN);
159         memset(temp_buff, 0, TEST_LEN);
160         memset(dest_ref, 0, TEST_LEN);
161         memset(g, 0, TEST_SOURCES);
162 
163         for (i = 0; i < TEST_SOURCES; i++)
164                 gf_vect_mul_init(g[i], &g_tbls[i * 32]);
165 
166         gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref);
167 
168         FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest);
169 
170         if (0 != memcmp(dest_ref, dest, TEST_LEN)) {
171                 printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " \n");
172                 dump_matrix(buffs, 5, TEST_SOURCES);
173                 printf("dprod_base:");
174                 dump(dest_ref, 25);
175                 printf("dprod:");
176                 dump(dest, 25);
177                 return -1;
178         }
179 #ifdef TEST_VERBOSE
180         else
181                 putchar('.');
182 #endif
183 
184         // Rand data test
185         for (rtest = 0; rtest < RANDOMS; rtest++) {
186                 for (i = 0; i < TEST_SOURCES; i++)
187                         for (j = 0; j < TEST_LEN; j++)
188                                 buffs[i][j] = rand();
189 
190                 for (i = 0; i < TEST_SOURCES; i++)
191                         g[i] = rand();
192 
193                 for (i = 0; i < TEST_SOURCES; i++)
194                         gf_vect_mul_init(g[i], &g_tbls[i * 32]);
195 
196                 gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref);
197                 FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest);
198 
199                 if (0 != memcmp(dest_ref, dest, TEST_LEN)) {
200                         printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " 1\n");
201                         dump_matrix(buffs, 5, TEST_SOURCES);
202                         printf("dprod_base:");
203                         dump(dest_ref, 25);
204                         printf("dprod:");
205                         dump(dest, 25);
206                         return -1;
207                 }
208 
209 #ifdef TEST_VERBOSE
210                 putchar('.');
211 #endif
212         }
213 
214         // Rand data test with varied parameters
215         for (rtest = 0; rtest < RANDOMS; rtest++) {
216                 for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
217                         for (i = 0; i < srcs; i++)
218                                 for (j = 0; j < TEST_LEN; j++)
219                                         buffs[i][j] = rand();
220 
221                         for (i = 0; i < srcs; i++)
222                                 g[i] = rand();
223 
224                         for (i = 0; i < srcs; i++)
225                                 gf_vect_mul_init(g[i], &g_tbls[i * 32]);
226 
227                         gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref);
228                         FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest);
229 
230                         if (0 != memcmp(dest_ref, dest, TEST_LEN)) {
231                                 printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test 2\n");
232                                 dump_matrix(buffs, 5, srcs);
233                                 printf("dprod_base:");
234                                 dump(dest_ref, 5);
235                                 printf("dprod:");
236                                 dump(dest, 5);
237                                 return -1;
238                         }
239 
240 #ifdef TEST_VERBOSE
241                         putchar('.');
242 #endif
243                 }
244         }
245 
246         // Test erasure code using gf_vect_dot_prod
247 
248         // Pick a first test
249         m = 9;
250         k = 5;
251         if (m > MMAX || k > KMAX)
252                 return -1;
253 
254         gf_gen_rs_matrix(a, m, k);
255 
256         // Make random data
257         for (i = 0; i < k; i++)
258                 for (j = 0; j < TEST_LEN; j++)
259                         buffs[i][j] = rand();
260 
261         // Make parity vects
262         for (i = k; i < m; i++) {
263                 for (j = 0; j < k; j++)
264                         gf_vect_mul_init(a[k * i + j], &g_tbls[j * 32]);
265 #ifndef USEREF
266                 FUNCTION_UNDER_TEST(TEST_LEN, k, g_tbls, buffs, buffs[i]);
267 #else
268                 gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], buffs, buffs[i]);
269 #endif
270         }
271 
272         // Random buffers in erasure
273         memset(src_in_err, 0, TEST_SOURCES);
274         for (i = 0, nerrs = 0; i < k && nerrs < m - k; i++) {
275                 err = 1 & rand();
276                 src_in_err[i] = err;
277                 if (err)
278                         src_err_list[nerrs++] = i;
279         }
280 
281         // construct b by removing error rows
282         for (i = 0, r = 0; i < k; i++, r++) {
283                 while (src_in_err[r]) {
284                         r++;
285                         continue;
286                 }
287                 for (j = 0; j < k; j++)
288                         b[k * i + j] = a[k * r + j];
289         }
290 
291         if (gf_invert_matrix((u8 *) b, (u8 *) d, k) < 0)
292                 printf("BAD MATRIX\n");
293 
294         for (i = 0, r = 0; i < k; i++, r++) {
295                 while (src_in_err[r]) {
296                         r++;
297                         continue;
298                 }
299                 recov[i] = buffs[r];
300         }
301 
302         // Recover data
303         for (i = 0; i < nerrs; i++) {
304                 for (j = 0; j < k; j++)
305                         gf_vect_mul_init(d[k * src_err_list[i] + j], &g_tbls[j * 32]);
306 #ifndef USEREF
307                 FUNCTION_UNDER_TEST(TEST_LEN, k, g_tbls, recov, temp_buff);
308 #else
309                 gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], recov, temp_buff);
310 #endif
311 
312                 if (0 != memcmp(temp_buff, buffs[src_err_list[i]], TEST_LEN)) {
313                         printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs);
314                         printf("recov %d:", src_err_list[i]);
315                         dump(temp_buff, 25);
316                         printf("orig   :");
317                         dump(buffs[src_err_list[i]], 25);
318                         return -1;
319                 }
320         }
321 
322         // Do more random tests
323 
324         for (rtest = 0; rtest < RANDOMS; rtest++) {
325                 while ((m = (rand() % MMAX)) < 2)
326                         ;
327                 while ((k = (rand() % KMAX)) >= m || k < 1)
328                         ;
329 
330                 if (m > MMAX || k > KMAX)
331                         continue;
332 
333                 gf_gen_rs_matrix(a, m, k);
334 
335                 // Make random data
336                 for (i = 0; i < k; i++)
337                         for (j = 0; j < TEST_LEN; j++)
338                                 buffs[i][j] = rand();
339 
340                 // Make parity vects
341                 for (i = k; i < m; i++) {
342                         for (j = 0; j < k; j++)
343                                 gf_vect_mul_init(a[k * i + j], &g_tbls[j * 32]);
344 #ifndef USEREF
345                         FUNCTION_UNDER_TEST(TEST_LEN, k, g_tbls, buffs, buffs[i]);
346 #else
347                         gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], buffs, buffs[i]);
348 #endif
349                 }
350 
351                 // Random errors
352                 memset(src_in_err, 0, TEST_SOURCES);
353                 for (i = 0, nerrs = 0; i < k && nerrs < m - k; i++) {
354                         err = 1 & rand();
355                         src_in_err[i] = err;
356                         if (err)
357                                 src_err_list[nerrs++] = i;
358                 }
359                 if (nerrs == 0) { // should have at least one error
360                         while ((err = (rand() % KMAX)) >= k)
361                                 ;
362                         src_err_list[nerrs++] = err;
363                         src_in_err[err] = 1;
364                 }
365                 // construct b by removing error rows
366                 for (i = 0, r = 0; i < k; i++, r++) {
367                         while (src_in_err[r]) {
368                                 r++;
369                                 continue;
370                         }
371                         for (j = 0; j < k; j++)
372                                 b[k * i + j] = a[k * r + j];
373                 }
374 
375                 if (gf_invert_matrix((u8 *) b, (u8 *) d, k) < 0)
376                         printf("BAD MATRIX\n");
377 
378                 for (i = 0, r = 0; i < k; i++, r++) {
379                         while (src_in_err[r]) {
380                                 r++;
381                                 continue;
382                         }
383                         recov[i] = buffs[r];
384                 }
385 
386                 // Recover data
387                 for (i = 0; i < nerrs; i++) {
388                         for (j = 0; j < k; j++)
389                                 gf_vect_mul_init(d[k * src_err_list[i] + j], &g_tbls[j * 32]);
390 #ifndef USEREF
391                         FUNCTION_UNDER_TEST(TEST_LEN, k, g_tbls, recov, temp_buff);
392 #else
393                         gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], recov, temp_buff);
394 #endif
395                         if (0 != memcmp(temp_buff, buffs[src_err_list[i]], TEST_LEN)) {
396                                 printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs);
397                                 printf(" - erase list = ");
398                                 for (i = 0; i < nerrs; i++)
399                                         printf(" %d", src_err_list[i]);
400                                 printf("\na:\n");
401                                 dump_u8xu8((u8 *) a, m, k);
402                                 printf("inv b:\n");
403                                 dump_u8xu8((u8 *) d, k, k);
404                                 printf("orig data:\n");
405                                 dump_matrix(buffs, m, 25);
406                                 printf("orig   :");
407                                 dump(buffs[src_err_list[i]], 25);
408                                 printf("recov %d:", src_err_list[i]);
409                                 dump(temp_buff, 25);
410                                 return -1;
411                         }
412                 }
413 #ifdef TEST_VERBOSE
414                 putchar('.');
415 #endif
416         }
417 
418         // Run tests at end of buffer for Electric Fence
419         align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
420         for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
421                 for (i = 0; i < TEST_SOURCES; i++)
422                         for (j = 0; j < TEST_LEN; j++)
423                                 buffs[i][j] = rand();
424 
425                 for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
426                         efence_buffs[i] = buffs[i] + TEST_LEN - size;
427 
428                 for (i = 0; i < TEST_SOURCES; i++)
429                         g[i] = rand();
430 
431                 for (i = 0; i < TEST_SOURCES; i++)
432                         gf_vect_mul_init(g[i], &g_tbls[i * 32]);
433 
434                 gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref);
435                 FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest);
436 
437                 if (0 != memcmp(dest_ref, dest, size)) {
438                         printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test 3\n");
439                         dump_matrix(efence_buffs, 5, TEST_SOURCES);
440                         printf("dprod_base:");
441                         dump(dest_ref, align);
442                         printf("dprod:");
443                         dump(dest, align);
444                         return -1;
445                 }
446 
447 #ifdef TEST_VERBOSE
448                 putchar('.');
449 #endif
450         }
451 
452         // Test rand ptr alignment if available
453 
454         for (rtest = 0; rtest < RANDOMS; rtest++) {
455                 size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
456                 srcs = rand() % TEST_SOURCES;
457                 if (srcs == 0)
458                         continue;
459 
460                 offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
461                 // Add random offsets
462                 for (i = 0; i < srcs; i++)
463                         ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
464 
465                 udest_ptr = dest + (rand() & (PTR_ALIGN_CHK_B - offset));
466 
467                 memset(dest, 0, TEST_LEN); // zero pad to check write-over
468 
469                 for (i = 0; i < srcs; i++)
470                         for (j = 0; j < size; j++)
471                                 ubuffs[i][j] = rand();
472 
473                 for (i = 0; i < srcs; i++)
474                         g[i] = rand();
475 
476                 for (i = 0; i < srcs; i++)
477                         gf_vect_mul_init(g[i], &g_tbls[i * 32]);
478 
479                 gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref);
480 
481                 FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptr);
482 
483                 if (memcmp(dest_ref, udest_ptr, size)) {
484                         printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " ualign srcs=%d\n", srcs);
485                         dump_matrix(ubuffs, 5, TEST_SOURCES);
486                         printf("dprod_base:");
487                         dump(dest_ref, 25);
488                         printf("dprod:");
489                         dump(udest_ptr, 25);
490                         return -1;
491                 }
492                 // Confirm that padding around dests is unchanged
493                 memset(dest_ref, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
494                 offset = udest_ptr - dest;
495 
496                 if (memcmp(dest, dest_ref, offset)) {
497                         printf("Fail rand ualign pad start\n");
498                         return -1;
499                 }
500                 if (memcmp(dest + offset + size, dest_ref, PTR_ALIGN_CHK_B - offset)) {
501                         printf("Fail rand ualign pad end\n");
502                         return -1;
503                 }
504 
505 #ifdef TEST_VERBOSE
506                 putchar('.');
507 #endif
508         }
509 
510         // Test all size alignment
511         align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
512 
513         for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
514                 srcs = TEST_SOURCES;
515 
516                 for (i = 0; i < srcs; i++)
517                         for (j = 0; j < size; j++)
518                                 buffs[i][j] = rand();
519 
520                 for (i = 0; i < srcs; i++)
521                         g[i] = rand();
522 
523                 for (i = 0; i < srcs; i++)
524                         gf_vect_mul_init(g[i], &g_tbls[i * 32]);
525 
526                 gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref);
527 
528                 FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest);
529 
530                 if (memcmp(dest_ref, dest, size)) {
531                         printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " ualign len=%d\n", size);
532                         dump_matrix(buffs, 5, TEST_SOURCES);
533                         printf("dprod_base:");
534                         dump(dest_ref, 25);
535                         printf("dprod:");
536                         dump(dest, 25);
537                         return -1;
538                 }
539         }
540 
541         printf("done all: Pass\n");
542         return 0;
543 }
544