xref: /isa-l/examples/ec/ec_piggyback_example.c (revision 9d99f8215d315fe67f178ce3849b0f40e13ee704)
1aaeedf60SGreg Tucker /**********************************************************************
2aaeedf60SGreg Tucker   Copyright(c) 2011-2018 Intel Corporation All rights reserved.
3aaeedf60SGreg Tucker 
4aaeedf60SGreg Tucker   Redistribution and use in source and binary forms, with or without
5aaeedf60SGreg Tucker   modification, are permitted provided that the following conditions
6aaeedf60SGreg Tucker   are met:
7aaeedf60SGreg Tucker     * Redistributions of source code must retain the above copyright
8aaeedf60SGreg Tucker       notice, this list of conditions and the following disclaimer.
9aaeedf60SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
10aaeedf60SGreg Tucker       notice, this list of conditions and the following disclaimer in
11aaeedf60SGreg Tucker       the documentation and/or other materials provided with the
12aaeedf60SGreg Tucker       distribution.
13aaeedf60SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
14aaeedf60SGreg Tucker       contributors may be used to endorse or promote products derived
15aaeedf60SGreg Tucker       from this software without specific prior written permission.
16aaeedf60SGreg Tucker 
17aaeedf60SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18aaeedf60SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19aaeedf60SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20aaeedf60SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21aaeedf60SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22aaeedf60SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23aaeedf60SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24aaeedf60SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25aaeedf60SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26aaeedf60SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27aaeedf60SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28aaeedf60SGreg Tucker **********************************************************************/
29aaeedf60SGreg Tucker 
30aaeedf60SGreg Tucker #include <stdio.h>
31aaeedf60SGreg Tucker #include <stdlib.h>
32aaeedf60SGreg Tucker #include <string.h>
33aaeedf60SGreg Tucker #include <getopt.h>
34aaeedf60SGreg Tucker #include "erasure_code.h" // use <isa-l.h> instead when linking against installed
35aaeedf60SGreg Tucker #include "test.h"
36aaeedf60SGreg Tucker 
37aaeedf60SGreg Tucker #define MMAX 255
38aaeedf60SGreg Tucker #define KMAX 255
39aaeedf60SGreg Tucker 
40aaeedf60SGreg Tucker typedef unsigned char u8;
41aaeedf60SGreg Tucker int verbose = 0;
42aaeedf60SGreg Tucker 
43*9d99f821SMarcel Cornu int
usage(void)44*9d99f821SMarcel Cornu usage(void)
45aaeedf60SGreg Tucker {
46aaeedf60SGreg Tucker         fprintf(stderr,
47aaeedf60SGreg Tucker                 "Usage: ec_piggyback_example [options]\n"
48aaeedf60SGreg Tucker                 "  -h        Help\n"
49aaeedf60SGreg Tucker                 "  -k <val>  Number of source fragments\n"
50aaeedf60SGreg Tucker                 "  -p <val>  Number of parity fragments\n"
51aaeedf60SGreg Tucker                 "  -l <val>  Length of fragments\n"
52aaeedf60SGreg Tucker                 "  -e <val>  Simulate erasure on frag index val. Zero based. Can be repeated.\n"
53aaeedf60SGreg Tucker                 "  -v        Verbose\n"
54aaeedf60SGreg Tucker                 "  -b        Run timed benchmark\n"
55aaeedf60SGreg Tucker                 "  -s        Toggle use of sparse matrix opt\n"
56aaeedf60SGreg Tucker                 "  -r <seed> Pick random (k, p) with seed\n");
57aaeedf60SGreg Tucker         exit(0);
58aaeedf60SGreg Tucker }
59aaeedf60SGreg Tucker 
60aaeedf60SGreg Tucker // Cauchy-based matrix
61*9d99f821SMarcel Cornu void
gf_gen_full_pb_cauchy_matrix(u8 * a,int m,int k)62*9d99f821SMarcel Cornu gf_gen_full_pb_cauchy_matrix(u8 *a, int m, int k)
63aaeedf60SGreg Tucker {
64aaeedf60SGreg Tucker         int i, j, p = m - k;
65aaeedf60SGreg Tucker 
661500db75SColin Ian King         // Identity matrix in top k x k to indicate a symmetric code
67aaeedf60SGreg Tucker         memset(a, 0, k * m);
68aaeedf60SGreg Tucker         for (i = 0; i < k; i++)
69aaeedf60SGreg Tucker                 a[k * i + i] = 1;
70aaeedf60SGreg Tucker 
71aaeedf60SGreg Tucker         for (i = k; i < (k + p / 2); i++) {
72aaeedf60SGreg Tucker                 for (j = 0; j < k / 2; j++)
73aaeedf60SGreg Tucker                         a[k * i + j] = gf_inv(i ^ j);
74aaeedf60SGreg Tucker                 for (; j < k; j++)
75aaeedf60SGreg Tucker                         a[k * i + j] = 0;
76aaeedf60SGreg Tucker         }
77aaeedf60SGreg Tucker         for (; i < m; i++) {
78aaeedf60SGreg Tucker                 for (j = 0; j < k / 2; j++)
79aaeedf60SGreg Tucker                         a[k * i + j] = 0;
80aaeedf60SGreg Tucker                 for (; j < k; j++)
81aaeedf60SGreg Tucker                         a[k * i + j] = gf_inv((i - p / 2) ^ (j - k / 2));
82aaeedf60SGreg Tucker         }
83aaeedf60SGreg Tucker 
84aaeedf60SGreg Tucker         // Fill in mixture of B parity depending on a few localized A sources
85aaeedf60SGreg Tucker         int r = 0, c = 0;
86aaeedf60SGreg Tucker         int repeat_len = k / (p - 2);
87aaeedf60SGreg Tucker         int parity_rows = p / 2;
88aaeedf60SGreg Tucker 
89aaeedf60SGreg Tucker         for (i = 1 + k + parity_rows; i < m; i++, r++) {
90aaeedf60SGreg Tucker                 if (r == (parity_rows - 1) - ((k / 2 % (parity_rows - 1))))
91aaeedf60SGreg Tucker                         repeat_len++;
92aaeedf60SGreg Tucker 
93aaeedf60SGreg Tucker                 for (j = 0; j < repeat_len; j++, c++)
94aaeedf60SGreg Tucker                         a[k * i + c] = gf_inv((k + 1) ^ c);
95aaeedf60SGreg Tucker         }
96aaeedf60SGreg Tucker }
97aaeedf60SGreg Tucker 
98aaeedf60SGreg Tucker // Vandermonde based matrix - not recommended due to limits when invertable
99*9d99f821SMarcel Cornu void
gf_gen_full_pb_vand_matrix(u8 * a,int m,int k)100*9d99f821SMarcel Cornu gf_gen_full_pb_vand_matrix(u8 *a, int m, int k)
101aaeedf60SGreg Tucker {
102aaeedf60SGreg Tucker         int i, j, p = m - k;
103aaeedf60SGreg Tucker         unsigned char q, gen = 1;
104aaeedf60SGreg Tucker 
1051500db75SColin Ian King         // Identity matrix in top k x k to indicate a symmetric code
106aaeedf60SGreg Tucker         memset(a, 0, k * m);
107aaeedf60SGreg Tucker         for (i = 0; i < k; i++)
108aaeedf60SGreg Tucker                 a[k * i + i] = 1;
109aaeedf60SGreg Tucker 
110aaeedf60SGreg Tucker         for (i = k; i < (k + (p / 2)); i++) {
111aaeedf60SGreg Tucker                 q = 1;
112aaeedf60SGreg Tucker                 for (j = 0; j < k / 2; j++) {
113aaeedf60SGreg Tucker                         a[k * i + j] = q;
114aaeedf60SGreg Tucker                         q = gf_mul(q, gen);
115aaeedf60SGreg Tucker                 }
116aaeedf60SGreg Tucker                 for (; j < k; j++)
117aaeedf60SGreg Tucker                         a[k * i + j] = 0;
118aaeedf60SGreg Tucker                 gen = gf_mul(gen, 2);
119aaeedf60SGreg Tucker         }
120aaeedf60SGreg Tucker         gen = 1;
121aaeedf60SGreg Tucker         for (; i < m; i++) {
122aaeedf60SGreg Tucker                 q = 1;
123aaeedf60SGreg Tucker                 for (j = 0; j < k / 2; j++) {
124aaeedf60SGreg Tucker                         a[k * i + j] = 0;
125aaeedf60SGreg Tucker                 }
126aaeedf60SGreg Tucker                 for (; j < k; j++) {
127aaeedf60SGreg Tucker                         a[k * i + j] = q;
128aaeedf60SGreg Tucker                         q = gf_mul(q, gen);
129aaeedf60SGreg Tucker                 }
130aaeedf60SGreg Tucker                 gen = gf_mul(gen, 2);
131aaeedf60SGreg Tucker         }
132aaeedf60SGreg Tucker 
133aaeedf60SGreg Tucker         // Fill in mixture of B parity depending on a few localized A sources
134aaeedf60SGreg Tucker         int r = 0, c = 0;
135aaeedf60SGreg Tucker         int repeat_len = k / (p - 2);
136aaeedf60SGreg Tucker         int parity_rows = p / 2;
137aaeedf60SGreg Tucker 
138aaeedf60SGreg Tucker         for (i = 1 + k + parity_rows; i < m; i++, r++) {
139aaeedf60SGreg Tucker                 if (r == (parity_rows - 1) - ((k / 2 % (parity_rows - 1))))
140aaeedf60SGreg Tucker                         repeat_len++;
141aaeedf60SGreg Tucker 
142aaeedf60SGreg Tucker                 for (j = 0; j < repeat_len; j++)
143aaeedf60SGreg Tucker                         a[k * i + c++] = 1;
144aaeedf60SGreg Tucker         }
145aaeedf60SGreg Tucker }
146aaeedf60SGreg Tucker 
147*9d99f821SMarcel Cornu void
print_matrix(int m,int k,unsigned char * s,const char * msg)148*9d99f821SMarcel Cornu print_matrix(int m, int k, unsigned char *s, const char *msg)
149aaeedf60SGreg Tucker {
150aaeedf60SGreg Tucker         int i, j;
151aaeedf60SGreg Tucker 
152aaeedf60SGreg Tucker         printf("%s:\n", msg);
153aaeedf60SGreg Tucker         for (i = 0; i < m; i++) {
154aaeedf60SGreg Tucker                 printf("%3d- ", i);
155aaeedf60SGreg Tucker                 for (j = 0; j < k; j++) {
156aaeedf60SGreg Tucker                         printf(" %2x", 0xff & s[j + (i * k)]);
157aaeedf60SGreg Tucker                 }
158aaeedf60SGreg Tucker                 printf("\n");
159aaeedf60SGreg Tucker         }
160aaeedf60SGreg Tucker         printf("\n");
161aaeedf60SGreg Tucker }
162aaeedf60SGreg Tucker 
163*9d99f821SMarcel Cornu void
print_list(int n,unsigned char * s,const char * msg)164*9d99f821SMarcel Cornu print_list(int n, unsigned char *s, const char *msg)
165aaeedf60SGreg Tucker {
166aaeedf60SGreg Tucker         int i;
167aaeedf60SGreg Tucker         if (!verbose)
168aaeedf60SGreg Tucker                 return;
169aaeedf60SGreg Tucker 
170aaeedf60SGreg Tucker         printf("%s: ", msg);
171aaeedf60SGreg Tucker         for (i = 0; i < n; i++)
172aaeedf60SGreg Tucker                 printf(" %d", s[i]);
173aaeedf60SGreg Tucker         printf("\n");
174aaeedf60SGreg Tucker }
175aaeedf60SGreg Tucker 
176*9d99f821SMarcel Cornu static int
177*9d99f821SMarcel Cornu gf_gen_decode_matrix(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix, u8 *temp_matrix,
178*9d99f821SMarcel Cornu                      u8 *decode_index, u8 *frag_err_list, int nerrs, int k, int m);
179aaeedf60SGreg Tucker 
180*9d99f821SMarcel Cornu int
main(int argc,char * argv[])181*9d99f821SMarcel Cornu main(int argc, char *argv[])
182aaeedf60SGreg Tucker {
183aaeedf60SGreg Tucker         int i, j, m, c, e, ret;
184aaeedf60SGreg Tucker         int k = 10, p = 4, len = 8 * 1024; // Default params
185aaeedf60SGreg Tucker         int nerrs = 0;
186aaeedf60SGreg Tucker         int benchmark = 0;
187aaeedf60SGreg Tucker         int sparse_matrix_opt = 1;
188aaeedf60SGreg Tucker 
189aaeedf60SGreg Tucker         // Fragment buffer pointers
190aaeedf60SGreg Tucker         u8 *frag_ptrs[MMAX];
191aaeedf60SGreg Tucker         u8 *parity_ptrs[KMAX];
192aaeedf60SGreg Tucker         u8 *recover_srcs[KMAX];
193aaeedf60SGreg Tucker         u8 *recover_outp[KMAX];
194aaeedf60SGreg Tucker         u8 frag_err_list[MMAX];
195aaeedf60SGreg Tucker 
196aaeedf60SGreg Tucker         // Coefficient matrices
197aaeedf60SGreg Tucker         u8 *encode_matrix, *decode_matrix;
198aaeedf60SGreg Tucker         u8 *invert_matrix, *temp_matrix;
199aaeedf60SGreg Tucker         u8 *g_tbls;
200aaeedf60SGreg Tucker         u8 decode_index[MMAX];
201aaeedf60SGreg Tucker 
202aaeedf60SGreg Tucker         if (argc == 1)
203aaeedf60SGreg Tucker                 for (i = 0; i < p; i++)
204aaeedf60SGreg Tucker                         frag_err_list[nerrs++] = rand() % (k + p);
205aaeedf60SGreg Tucker 
206aaeedf60SGreg Tucker         while ((c = getopt(argc, argv, "k:p:l:e:r:hvbs")) != -1) {
207aaeedf60SGreg Tucker                 switch (c) {
208aaeedf60SGreg Tucker                 case 'k':
209aaeedf60SGreg Tucker                         k = atoi(optarg);
210aaeedf60SGreg Tucker                         break;
211aaeedf60SGreg Tucker                 case 'p':
212aaeedf60SGreg Tucker                         p = atoi(optarg);
213aaeedf60SGreg Tucker                         break;
214aaeedf60SGreg Tucker                 case 'l':
215aaeedf60SGreg Tucker                         len = atoi(optarg);
216aaeedf60SGreg Tucker                         if (len < 0)
217aaeedf60SGreg Tucker                                 usage();
218aaeedf60SGreg Tucker                         break;
219aaeedf60SGreg Tucker                 case 'e':
220aaeedf60SGreg Tucker                         e = atoi(optarg);
221aaeedf60SGreg Tucker                         frag_err_list[nerrs++] = e;
222aaeedf60SGreg Tucker                         break;
223aaeedf60SGreg Tucker                 case 'r':
224aaeedf60SGreg Tucker                         srand(atoi(optarg));
225aaeedf60SGreg Tucker                         k = (rand() % MMAX) / 4;
226aaeedf60SGreg Tucker                         k = (k < 2) ? 2 : k;
227aaeedf60SGreg Tucker                         p = (rand() % (MMAX - k)) / 4;
228aaeedf60SGreg Tucker                         p = (p < 2) ? 2 : p;
229aaeedf60SGreg Tucker                         for (i = 0; i < k && nerrs < p; i++)
230aaeedf60SGreg Tucker                                 if (rand() & 1)
231aaeedf60SGreg Tucker                                         frag_err_list[nerrs++] = i;
232aaeedf60SGreg Tucker                         break;
233aaeedf60SGreg Tucker                 case 'v':
234aaeedf60SGreg Tucker                         verbose++;
235aaeedf60SGreg Tucker                         break;
236aaeedf60SGreg Tucker                 case 'b':
237aaeedf60SGreg Tucker                         benchmark = 1;
238aaeedf60SGreg Tucker                         break;
239aaeedf60SGreg Tucker                 case 's':
240aaeedf60SGreg Tucker                         sparse_matrix_opt = !sparse_matrix_opt;
241aaeedf60SGreg Tucker                         break;
242aaeedf60SGreg Tucker                 case 'h':
243aaeedf60SGreg Tucker                 default:
244aaeedf60SGreg Tucker                         usage();
245aaeedf60SGreg Tucker                         break;
246aaeedf60SGreg Tucker                 }
247aaeedf60SGreg Tucker         }
248aaeedf60SGreg Tucker         m = k + p;
249aaeedf60SGreg Tucker 
250aaeedf60SGreg Tucker         // Check for valid parameters
251aaeedf60SGreg Tucker         if (m > (MMAX / 2) || k > (KMAX / 2) || m < 0 || p < 2 || k < 1) {
252*9d99f821SMarcel Cornu                 printf(" Input test parameter error m=%d, k=%d, p=%d, erasures=%d\n", m, k, p,
253*9d99f821SMarcel Cornu                        nerrs);
254aaeedf60SGreg Tucker                 usage();
255aaeedf60SGreg Tucker         }
256aaeedf60SGreg Tucker         if (nerrs > p) {
257*9d99f821SMarcel Cornu                 printf(" Number of erasures chosen exceeds power of code erasures=%d p=%d\n", nerrs,
258*9d99f821SMarcel Cornu                        p);
259aaeedf60SGreg Tucker         }
260aaeedf60SGreg Tucker         for (i = 0; i < nerrs; i++) {
261aaeedf60SGreg Tucker                 if (frag_err_list[i] >= m)
262aaeedf60SGreg Tucker                         printf(" fragment %d not in range\n", frag_err_list[i]);
263aaeedf60SGreg Tucker         }
264aaeedf60SGreg Tucker 
265aaeedf60SGreg Tucker         printf("ec_piggyback_example:\n");
266aaeedf60SGreg Tucker 
267aaeedf60SGreg Tucker         /*
268aaeedf60SGreg Tucker          * One simple way to implement piggyback codes is to keep a 2x wide matrix
269aaeedf60SGreg Tucker          * that covers the how each parity is related to both A and B sources.  This
270aaeedf60SGreg Tucker          * keeps it easy to generalize in parameters m,k and the resulting sparse
271aaeedf60SGreg Tucker          * matrix multiplication can be optimized by pre-removal of zero items.
272aaeedf60SGreg Tucker          */
273aaeedf60SGreg Tucker 
274aaeedf60SGreg Tucker         int k2 = 2 * k;
275aaeedf60SGreg Tucker         int p2 = 2 * p;
276aaeedf60SGreg Tucker         int m2 = k2 + p2;
277aaeedf60SGreg Tucker         int nerrs2 = nerrs;
278aaeedf60SGreg Tucker 
279aaeedf60SGreg Tucker         encode_matrix = malloc(m2 * k2);
280aaeedf60SGreg Tucker         decode_matrix = malloc(m2 * k2);
281aaeedf60SGreg Tucker         invert_matrix = malloc(m2 * k2);
282aaeedf60SGreg Tucker         temp_matrix = malloc(m2 * k2);
283aaeedf60SGreg Tucker         g_tbls = malloc(k2 * p2 * 32);
284aaeedf60SGreg Tucker 
285*9d99f821SMarcel Cornu         if (encode_matrix == NULL || decode_matrix == NULL || invert_matrix == NULL ||
286*9d99f821SMarcel Cornu             temp_matrix == NULL || g_tbls == NULL) {
287aaeedf60SGreg Tucker                 printf("Test failure! Error with malloc\n");
288aaeedf60SGreg Tucker                 return -1;
289aaeedf60SGreg Tucker         }
290aaeedf60SGreg Tucker         // Allocate the src fragments
291aaeedf60SGreg Tucker         for (i = 0; i < k; i++) {
292aaeedf60SGreg Tucker                 if (NULL == (frag_ptrs[i] = malloc(len))) {
293aaeedf60SGreg Tucker                         printf("alloc error: Fail\n");
294aaeedf60SGreg Tucker                         return -1;
295aaeedf60SGreg Tucker                 }
296aaeedf60SGreg Tucker         }
297aaeedf60SGreg Tucker         // Allocate the parity fragments
298aaeedf60SGreg Tucker         for (i = 0; i < p2; i++) {
299aaeedf60SGreg Tucker                 if (NULL == (parity_ptrs[i] = malloc(len / 2))) {
300aaeedf60SGreg Tucker                         printf("alloc error: Fail\n");
301aaeedf60SGreg Tucker                         return -1;
302aaeedf60SGreg Tucker                 }
303aaeedf60SGreg Tucker         }
304aaeedf60SGreg Tucker 
305aaeedf60SGreg Tucker         // Allocate buffers for recovered data
306aaeedf60SGreg Tucker         for (i = 0; i < p2; i++) {
307aaeedf60SGreg Tucker                 if (NULL == (recover_outp[i] = malloc(len / 2))) {
308aaeedf60SGreg Tucker                         printf("alloc error: Fail\n");
309aaeedf60SGreg Tucker                         return -1;
310aaeedf60SGreg Tucker                 }
311aaeedf60SGreg Tucker         }
312aaeedf60SGreg Tucker 
313aaeedf60SGreg Tucker         // Fill sources with random data
314aaeedf60SGreg Tucker         for (i = 0; i < k; i++)
315aaeedf60SGreg Tucker                 for (j = 0; j < len; j++)
316aaeedf60SGreg Tucker                         frag_ptrs[i][j] = rand();
317aaeedf60SGreg Tucker 
318aaeedf60SGreg Tucker         printf(" encode (m,k,p)=(%d,%d,%d) len=%d\n", m, k, p, len);
319aaeedf60SGreg Tucker 
320aaeedf60SGreg Tucker         // Pick an encode matrix.
321aaeedf60SGreg Tucker         gf_gen_full_pb_cauchy_matrix(encode_matrix, m2, k2);
322aaeedf60SGreg Tucker 
323aaeedf60SGreg Tucker         if (verbose)
324aaeedf60SGreg Tucker                 print_matrix(m2, k2, encode_matrix, "encode matrix");
325aaeedf60SGreg Tucker 
326aaeedf60SGreg Tucker         // Initialize g_tbls from encode matrix
327aaeedf60SGreg Tucker         ec_init_tables(k2, p2, &encode_matrix[k2 * k2], g_tbls);
328aaeedf60SGreg Tucker 
329aaeedf60SGreg Tucker         // Fold A and B into single list of fragments
330aaeedf60SGreg Tucker         for (i = 0; i < k; i++)
331aaeedf60SGreg Tucker                 frag_ptrs[i + k] = &frag_ptrs[i][len / 2];
332aaeedf60SGreg Tucker 
333aaeedf60SGreg Tucker         if (!sparse_matrix_opt) {
334aaeedf60SGreg Tucker                 // Standard encode using no assumptions on the encode matrix
335aaeedf60SGreg Tucker 
336aaeedf60SGreg Tucker                 // Generate EC parity blocks from sources
337aaeedf60SGreg Tucker                 ec_encode_data(len / 2, k2, p2, g_tbls, frag_ptrs, parity_ptrs);
338aaeedf60SGreg Tucker 
339aaeedf60SGreg Tucker                 if (benchmark) {
340699bb5bdSRoy Oursler                         struct perf start;
341699bb5bdSRoy Oursler                         BENCHMARK(&start, BENCHMARK_TIME,
342*9d99f821SMarcel Cornu                                   ec_encode_data(len / 2, k2, p2, g_tbls, frag_ptrs, parity_ptrs));
343aaeedf60SGreg Tucker                         printf("ec_piggyback_encode_std: ");
344699bb5bdSRoy Oursler                         perf_print(start, m2 * len / 2);
345aaeedf60SGreg Tucker                 }
346aaeedf60SGreg Tucker         } else {
347aaeedf60SGreg Tucker                 // Sparse matrix optimization - use fact that input matrix is sparse
348aaeedf60SGreg Tucker 
349aaeedf60SGreg Tucker                 // Keep an encode matrix with some zero elements removed
350aaeedf60SGreg Tucker                 u8 *encode_matrix_faster, *g_tbls_faster;
351aaeedf60SGreg Tucker                 encode_matrix_faster = malloc(m * k);
352aaeedf60SGreg Tucker                 g_tbls_faster = malloc(k * p * 32);
353aaeedf60SGreg Tucker                 if (encode_matrix_faster == NULL || g_tbls_faster == NULL) {
354aaeedf60SGreg Tucker                         printf("Test failure! Error with malloc\n");
355aaeedf60SGreg Tucker                         return -1;
356aaeedf60SGreg Tucker                 }
357aaeedf60SGreg Tucker 
358aaeedf60SGreg Tucker                 /*
359aaeedf60SGreg Tucker                  * Pack with only the part that we know are non-zero.  Alternatively
360aaeedf60SGreg Tucker                  * we could search and keep track of non-zero elements but for
361aaeedf60SGreg Tucker                  * simplicity we just skip the lower quadrant.
362aaeedf60SGreg Tucker                  */
363aaeedf60SGreg Tucker                 for (i = k, j = k2; i < m; i++, j++)
364aaeedf60SGreg Tucker                         memcpy(&encode_matrix_faster[k * i], &encode_matrix[k2 * j], k);
365aaeedf60SGreg Tucker 
366aaeedf60SGreg Tucker                 if (verbose) {
367*9d99f821SMarcel Cornu                         print_matrix(p, k, &encode_matrix_faster[k * k], "encode via sparse-opt");
368aaeedf60SGreg Tucker                         print_matrix(p2 / 2, k2, &encode_matrix[(k2 + p2 / 2) * k2],
369aaeedf60SGreg Tucker                                      "encode via sparse-opt");
370aaeedf60SGreg Tucker                 }
371aaeedf60SGreg Tucker                 // Initialize g_tbls from encode matrix
372aaeedf60SGreg Tucker                 ec_init_tables(k, p, &encode_matrix_faster[k * k], g_tbls_faster);
373aaeedf60SGreg Tucker 
374aaeedf60SGreg Tucker                 // Generate EC parity blocks from sources
375aaeedf60SGreg Tucker                 ec_encode_data(len / 2, k, p, g_tbls_faster, frag_ptrs, parity_ptrs);
376*9d99f821SMarcel Cornu                 ec_encode_data(len / 2, k2, p, &g_tbls[k2 * p * 32], frag_ptrs, &parity_ptrs[p]);
377aaeedf60SGreg Tucker 
378aaeedf60SGreg Tucker                 if (benchmark) {
379699bb5bdSRoy Oursler                         struct perf start;
380699bb5bdSRoy Oursler                         BENCHMARK(&start, BENCHMARK_TIME,
381aaeedf60SGreg Tucker                                   ec_encode_data(len / 2, k, p, g_tbls_faster, frag_ptrs,
382aaeedf60SGreg Tucker                                                  parity_ptrs);
383*9d99f821SMarcel Cornu                                   ec_encode_data(len / 2, k2, p, &g_tbls[k2 * p * 32], frag_ptrs,
384*9d99f821SMarcel Cornu                                                  &parity_ptrs[p]));
385aaeedf60SGreg Tucker                         printf("ec_piggyback_encode_sparse: ");
386699bb5bdSRoy Oursler                         perf_print(start, m2 * len / 2);
387aaeedf60SGreg Tucker                 }
388aaeedf60SGreg Tucker         }
389aaeedf60SGreg Tucker 
390aaeedf60SGreg Tucker         if (nerrs <= 0)
391aaeedf60SGreg Tucker                 return 0;
392aaeedf60SGreg Tucker 
393aaeedf60SGreg Tucker         printf(" recover %d fragments\n", nerrs);
394aaeedf60SGreg Tucker 
395aaeedf60SGreg Tucker         // Set frag pointers to correspond to parity
396aaeedf60SGreg Tucker         for (i = k2; i < m2; i++)
397aaeedf60SGreg Tucker                 frag_ptrs[i] = parity_ptrs[i - k2];
398aaeedf60SGreg Tucker 
399aaeedf60SGreg Tucker         print_list(nerrs2, frag_err_list, " frag err list");
400aaeedf60SGreg Tucker 
401aaeedf60SGreg Tucker         // Find a decode matrix to regenerate all erasures from remaining frags
402*9d99f821SMarcel Cornu         ret = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, temp_matrix,
403*9d99f821SMarcel Cornu                                    decode_index, frag_err_list, nerrs2, k2, m2);
404aaeedf60SGreg Tucker 
405aaeedf60SGreg Tucker         if (ret != 0) {
406aaeedf60SGreg Tucker                 printf("Fail on generate decode matrix\n");
407aaeedf60SGreg Tucker                 return -1;
408aaeedf60SGreg Tucker         }
409aaeedf60SGreg Tucker         // Pack recovery array pointers as list of valid fragments
410aaeedf60SGreg Tucker         for (i = 0; i < k2; i++)
411aaeedf60SGreg Tucker                 if (decode_index[i] < k2)
412aaeedf60SGreg Tucker                         recover_srcs[i] = frag_ptrs[decode_index[i]];
413aaeedf60SGreg Tucker                 else
414aaeedf60SGreg Tucker                         recover_srcs[i] = parity_ptrs[decode_index[i] - k2];
415aaeedf60SGreg Tucker 
416aaeedf60SGreg Tucker         print_list(k2, decode_index, " decode index");
417aaeedf60SGreg Tucker 
418aaeedf60SGreg Tucker         // Recover data
419aaeedf60SGreg Tucker         ec_init_tables(k2, nerrs2, decode_matrix, g_tbls);
420aaeedf60SGreg Tucker         ec_encode_data(len / 2, k2, nerrs2, g_tbls, recover_srcs, recover_outp);
421aaeedf60SGreg Tucker 
422aaeedf60SGreg Tucker         if (benchmark) {
423699bb5bdSRoy Oursler                 struct perf start;
424699bb5bdSRoy Oursler                 BENCHMARK(&start, BENCHMARK_TIME,
425*9d99f821SMarcel Cornu                           ec_encode_data(len / 2, k2, nerrs2, g_tbls, recover_srcs, recover_outp));
426aaeedf60SGreg Tucker                 printf("ec_piggyback_decode: ");
427699bb5bdSRoy Oursler                 perf_print(start, (k2 + nerrs2) * len / 2);
428aaeedf60SGreg Tucker         }
429aaeedf60SGreg Tucker         // Check that recovered buffers are the same as original
430aaeedf60SGreg Tucker         printf(" check recovery of block {");
431aaeedf60SGreg Tucker         for (i = 0; i < nerrs2; i++) {
432aaeedf60SGreg Tucker                 printf(" %d", frag_err_list[i]);
433aaeedf60SGreg Tucker                 if (memcmp(recover_outp[i], frag_ptrs[frag_err_list[i]], len / 2)) {
434aaeedf60SGreg Tucker                         printf(" Fail erasure recovery %d, frag %d\n", i, frag_err_list[i]);
435aaeedf60SGreg Tucker                         return -1;
436aaeedf60SGreg Tucker                 }
437aaeedf60SGreg Tucker         }
438aaeedf60SGreg Tucker         printf(" } done all: Pass\n");
439aaeedf60SGreg Tucker 
440aaeedf60SGreg Tucker         return 0;
441aaeedf60SGreg Tucker }
442aaeedf60SGreg Tucker 
443aaeedf60SGreg Tucker // Generate decode matrix from encode matrix and erasure list
444aaeedf60SGreg Tucker 
445*9d99f821SMarcel Cornu static int
gf_gen_decode_matrix(u8 * encode_matrix,u8 * decode_matrix,u8 * invert_matrix,u8 * temp_matrix,u8 * decode_index,u8 * frag_err_list,int nerrs,int k,int m)446*9d99f821SMarcel Cornu gf_gen_decode_matrix(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix, u8 *temp_matrix,
447aaeedf60SGreg Tucker                      u8 *decode_index, u8 *frag_err_list, int nerrs, int k, int m)
448aaeedf60SGreg Tucker {
449aaeedf60SGreg Tucker         int i, j, p, r;
450aaeedf60SGreg Tucker         int nsrcerrs = 0;
451aaeedf60SGreg Tucker         u8 s, *b = temp_matrix;
452aaeedf60SGreg Tucker         u8 frag_in_err[MMAX];
453aaeedf60SGreg Tucker 
454aaeedf60SGreg Tucker         memset(frag_in_err, 0, sizeof(frag_in_err));
455aaeedf60SGreg Tucker 
456aaeedf60SGreg Tucker         // Order the fragments in erasure for easier sorting
457aaeedf60SGreg Tucker         for (i = 0; i < nerrs; i++) {
458aaeedf60SGreg Tucker                 if (frag_err_list[i] < k)
459aaeedf60SGreg Tucker                         nsrcerrs++;
460aaeedf60SGreg Tucker                 frag_in_err[frag_err_list[i]] = 1;
461aaeedf60SGreg Tucker         }
462aaeedf60SGreg Tucker 
463aaeedf60SGreg Tucker         // Construct b (matrix that encoded remaining frags) by removing erased rows
464aaeedf60SGreg Tucker         for (i = 0, r = 0; i < k; i++, r++) {
465aaeedf60SGreg Tucker                 while (frag_in_err[r])
466aaeedf60SGreg Tucker                         r++;
467aaeedf60SGreg Tucker                 for (j = 0; j < k; j++)
468aaeedf60SGreg Tucker                         b[k * i + j] = encode_matrix[k * r + j];
469aaeedf60SGreg Tucker                 decode_index[i] = r;
470aaeedf60SGreg Tucker         }
471aaeedf60SGreg Tucker         if (verbose > 1)
472aaeedf60SGreg Tucker                 print_matrix(k, k, b, "matrix to invert");
473aaeedf60SGreg Tucker 
474aaeedf60SGreg Tucker         // Invert matrix to get recovery matrix
475aaeedf60SGreg Tucker         if (gf_invert_matrix(b, invert_matrix, k) < 0)
476aaeedf60SGreg Tucker                 return -1;
477aaeedf60SGreg Tucker 
478aaeedf60SGreg Tucker         if (verbose > 2)
479aaeedf60SGreg Tucker                 print_matrix(k, k, invert_matrix, "matrix inverted");
480aaeedf60SGreg Tucker 
481aaeedf60SGreg Tucker         // Get decode matrix with only wanted recovery rows
482aaeedf60SGreg Tucker         for (i = 0; i < nsrcerrs; i++) {
483aaeedf60SGreg Tucker                 for (j = 0; j < k; j++) {
484aaeedf60SGreg Tucker                         decode_matrix[k * i + j] = invert_matrix[k * frag_err_list[i] + j];
485aaeedf60SGreg Tucker                 }
486aaeedf60SGreg Tucker         }
487aaeedf60SGreg Tucker 
488aaeedf60SGreg Tucker         // For non-src (parity) erasures need to multiply encode matrix * invert
489aaeedf60SGreg Tucker         for (p = nsrcerrs; p < nerrs; p++) {
490aaeedf60SGreg Tucker                 for (i = 0; i < k; i++) {
491aaeedf60SGreg Tucker                         s = 0;
492aaeedf60SGreg Tucker                         for (j = 0; j < k; j++)
493aaeedf60SGreg Tucker                                 s ^= gf_mul(invert_matrix[j * k + i],
494aaeedf60SGreg Tucker                                             encode_matrix[k * frag_err_list[p] + j]);
495aaeedf60SGreg Tucker 
496aaeedf60SGreg Tucker                         decode_matrix[k * p + i] = s;
497aaeedf60SGreg Tucker                 }
498aaeedf60SGreg Tucker         }
499aaeedf60SGreg Tucker         if (verbose > 1)
500aaeedf60SGreg Tucker                 print_matrix(nerrs, k, decode_matrix, "decode matrix");
501aaeedf60SGreg Tucker         return 0;
502aaeedf60SGreg Tucker }
503