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