xref: /isa-l/examples/ec/ec_simple_example.c (revision 9d99f8215d315fe67f178ce3849b0f40e13ee704)
1041379a6SGreg Tucker /**********************************************************************
2041379a6SGreg Tucker   Copyright(c) 2011-2018 Intel Corporation All rights reserved.
3041379a6SGreg Tucker 
4041379a6SGreg Tucker   Redistribution and use in source and binary forms, with or without
5041379a6SGreg Tucker   modification, are permitted provided that the following conditions
6041379a6SGreg Tucker   are met:
7041379a6SGreg Tucker     * Redistributions of source code must retain the above copyright
8041379a6SGreg Tucker       notice, this list of conditions and the following disclaimer.
9041379a6SGreg Tucker     * Redistributions in binary form must reproduce the above copyright
10041379a6SGreg Tucker       notice, this list of conditions and the following disclaimer in
11041379a6SGreg Tucker       the documentation and/or other materials provided with the
12041379a6SGreg Tucker       distribution.
13041379a6SGreg Tucker     * Neither the name of Intel Corporation nor the names of its
14041379a6SGreg Tucker       contributors may be used to endorse or promote products derived
15041379a6SGreg Tucker       from this software without specific prior written permission.
16041379a6SGreg Tucker 
17041379a6SGreg Tucker   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18041379a6SGreg Tucker   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19041379a6SGreg Tucker   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20041379a6SGreg Tucker   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21041379a6SGreg Tucker   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22041379a6SGreg Tucker   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23041379a6SGreg Tucker   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24041379a6SGreg Tucker   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25041379a6SGreg Tucker   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26041379a6SGreg Tucker   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27041379a6SGreg Tucker   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28041379a6SGreg Tucker **********************************************************************/
29041379a6SGreg Tucker 
30041379a6SGreg Tucker #include <stdio.h>
31041379a6SGreg Tucker #include <stdlib.h>
32041379a6SGreg Tucker #include <string.h>
33041379a6SGreg Tucker #include <getopt.h>
34041379a6SGreg Tucker #include "erasure_code.h" // use <isa-l.h> instead when linking against installed
35041379a6SGreg Tucker 
36041379a6SGreg Tucker #define MMAX 255
37041379a6SGreg Tucker #define KMAX 255
38041379a6SGreg Tucker 
39041379a6SGreg Tucker typedef unsigned char u8;
40041379a6SGreg Tucker 
41*9d99f821SMarcel Cornu int
usage(void)42*9d99f821SMarcel Cornu usage(void)
43041379a6SGreg Tucker {
44041379a6SGreg Tucker         fprintf(stderr,
45041379a6SGreg Tucker                 "Usage: ec_simple_example [options]\n"
46041379a6SGreg Tucker                 "  -h        Help\n"
47041379a6SGreg Tucker                 "  -k <val>  Number of source fragments\n"
48041379a6SGreg Tucker                 "  -p <val>  Number of parity fragments\n"
49041379a6SGreg Tucker                 "  -l <val>  Length of fragments\n"
50041379a6SGreg Tucker                 "  -e <val>  Simulate erasure on frag index val. Zero based. Can be repeated.\n"
51041379a6SGreg Tucker                 "  -r <seed> Pick random (k, p) with seed\n");
52041379a6SGreg Tucker         exit(0);
53041379a6SGreg Tucker }
54041379a6SGreg Tucker 
55*9d99f821SMarcel Cornu static int
56*9d99f821SMarcel Cornu gf_gen_decode_matrix_simple(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix,
57*9d99f821SMarcel Cornu                             u8 *temp_matrix, u8 *decode_index, u8 *frag_err_list, int nerrs, int k,
58*9d99f821SMarcel Cornu                             int m);
59041379a6SGreg Tucker 
60*9d99f821SMarcel Cornu int
main(int argc,char * argv[])61*9d99f821SMarcel Cornu main(int argc, char *argv[])
62041379a6SGreg Tucker {
63041379a6SGreg Tucker         int i, j, m, c, e, ret;
64041379a6SGreg Tucker         int k = 10, p = 4, len = 8 * 1024; // Default params
65041379a6SGreg Tucker         int nerrs = 0;
66041379a6SGreg Tucker 
67041379a6SGreg Tucker         // Fragment buffer pointers
68041379a6SGreg Tucker         u8 *frag_ptrs[MMAX];
69041379a6SGreg Tucker         u8 *recover_srcs[KMAX];
70041379a6SGreg Tucker         u8 *recover_outp[KMAX];
71041379a6SGreg Tucker         u8 frag_err_list[MMAX];
72041379a6SGreg Tucker 
73041379a6SGreg Tucker         // Coefficient matrices
74041379a6SGreg Tucker         u8 *encode_matrix, *decode_matrix;
75041379a6SGreg Tucker         u8 *invert_matrix, *temp_matrix;
76041379a6SGreg Tucker         u8 *g_tbls;
77041379a6SGreg Tucker         u8 decode_index[MMAX];
78041379a6SGreg Tucker 
79041379a6SGreg Tucker         if (argc == 1)
80041379a6SGreg Tucker                 for (i = 0; i < p; i++)
81041379a6SGreg Tucker                         frag_err_list[nerrs++] = rand() % (k + p);
82041379a6SGreg Tucker 
83041379a6SGreg Tucker         while ((c = getopt(argc, argv, "k:p:l:e:r:h")) != -1) {
84041379a6SGreg Tucker                 switch (c) {
85041379a6SGreg Tucker                 case 'k':
86041379a6SGreg Tucker                         k = atoi(optarg);
87041379a6SGreg Tucker                         break;
88041379a6SGreg Tucker                 case 'p':
89041379a6SGreg Tucker                         p = atoi(optarg);
90041379a6SGreg Tucker                         break;
91041379a6SGreg Tucker                 case 'l':
92041379a6SGreg Tucker                         len = atoi(optarg);
93041379a6SGreg Tucker                         if (len < 0)
94041379a6SGreg Tucker                                 usage();
95041379a6SGreg Tucker                         break;
96041379a6SGreg Tucker                 case 'e':
97041379a6SGreg Tucker                         e = atoi(optarg);
98041379a6SGreg Tucker                         frag_err_list[nerrs++] = e;
99041379a6SGreg Tucker                         break;
100041379a6SGreg Tucker                 case 'r':
101041379a6SGreg Tucker                         srand(atoi(optarg));
1029edac479SGreg Tucker                         k = (rand() % (MMAX - 1)) + 1; // Pick k {1 to MMAX - 1}
1039edac479SGreg Tucker                         p = (rand() % (MMAX - k)) + 1; // Pick p {1 to MMAX - k}
1049edac479SGreg Tucker 
105041379a6SGreg Tucker                         for (i = 0; i < k + p && nerrs < p; i++)
106041379a6SGreg Tucker                                 if (rand() & 1)
107041379a6SGreg Tucker                                         frag_err_list[nerrs++] = i;
108041379a6SGreg Tucker                         break;
109041379a6SGreg Tucker                 case 'h':
110041379a6SGreg Tucker                 default:
111041379a6SGreg Tucker                         usage();
112041379a6SGreg Tucker                         break;
113041379a6SGreg Tucker                 }
114041379a6SGreg Tucker         }
115041379a6SGreg Tucker         m = k + p;
116041379a6SGreg Tucker 
117041379a6SGreg Tucker         // Check for valid parameters
1184c4185baSGreg Tucker         if (m > MMAX || k > KMAX || m < 0 || p < 1 || k < 1) {
119*9d99f821SMarcel Cornu                 printf(" Input test parameter error m=%d, k=%d, p=%d, erasures=%d\n", m, k, p,
120*9d99f821SMarcel Cornu                        nerrs);
121041379a6SGreg Tucker                 usage();
122041379a6SGreg Tucker         }
123041379a6SGreg Tucker         if (nerrs > p) {
124*9d99f821SMarcel Cornu                 printf(" Number of erasures chosen exceeds power of code erasures=%d p=%d\n", nerrs,
125*9d99f821SMarcel Cornu                        p);
126041379a6SGreg Tucker                 usage();
127041379a6SGreg Tucker         }
128041379a6SGreg Tucker         for (i = 0; i < nerrs; i++) {
129041379a6SGreg Tucker                 if (frag_err_list[i] >= m) {
130041379a6SGreg Tucker                         printf(" fragment %d not in range\n", frag_err_list[i]);
131041379a6SGreg Tucker                         usage();
132041379a6SGreg Tucker                 }
133041379a6SGreg Tucker         }
134041379a6SGreg Tucker 
135041379a6SGreg Tucker         printf("ec_simple_example:\n");
136041379a6SGreg Tucker 
137041379a6SGreg Tucker         // Allocate coding matrices
138041379a6SGreg Tucker         encode_matrix = malloc(m * k);
139041379a6SGreg Tucker         decode_matrix = malloc(m * k);
140041379a6SGreg Tucker         invert_matrix = malloc(m * k);
141041379a6SGreg Tucker         temp_matrix = malloc(m * k);
142041379a6SGreg Tucker         g_tbls = malloc(k * p * 32);
143041379a6SGreg Tucker 
144*9d99f821SMarcel Cornu         if (encode_matrix == NULL || decode_matrix == NULL || invert_matrix == NULL ||
145*9d99f821SMarcel Cornu             temp_matrix == NULL || g_tbls == NULL) {
146041379a6SGreg Tucker                 printf("Test failure! Error with malloc\n");
147041379a6SGreg Tucker                 return -1;
148041379a6SGreg Tucker         }
149041379a6SGreg Tucker         // Allocate the src & parity buffers
150041379a6SGreg Tucker         for (i = 0; i < m; i++) {
151041379a6SGreg Tucker                 if (NULL == (frag_ptrs[i] = malloc(len))) {
152041379a6SGreg Tucker                         printf("alloc error: Fail\n");
153041379a6SGreg Tucker                         return -1;
154041379a6SGreg Tucker                 }
155041379a6SGreg Tucker         }
156041379a6SGreg Tucker 
157041379a6SGreg Tucker         // Allocate buffers for recovered data
158041379a6SGreg Tucker         for (i = 0; i < p; i++) {
159041379a6SGreg Tucker                 if (NULL == (recover_outp[i] = malloc(len))) {
160041379a6SGreg Tucker                         printf("alloc error: Fail\n");
161041379a6SGreg Tucker                         return -1;
162041379a6SGreg Tucker                 }
163041379a6SGreg Tucker         }
164041379a6SGreg Tucker 
165041379a6SGreg Tucker         // Fill sources with random data
166041379a6SGreg Tucker         for (i = 0; i < k; i++)
167041379a6SGreg Tucker                 for (j = 0; j < len; j++)
168041379a6SGreg Tucker                         frag_ptrs[i][j] = rand();
169041379a6SGreg Tucker 
170041379a6SGreg Tucker         printf(" encode (m,k,p)=(%d,%d,%d) len=%d\n", m, k, p, len);
171041379a6SGreg Tucker 
172041379a6SGreg Tucker         // Pick an encode matrix. A Cauchy matrix is a good choice as even
173041379a6SGreg Tucker         // large k are always invertable keeping the recovery rule simple.
174041379a6SGreg Tucker         gf_gen_cauchy1_matrix(encode_matrix, m, k);
175041379a6SGreg Tucker 
176041379a6SGreg Tucker         // Initialize g_tbls from encode matrix
177041379a6SGreg Tucker         ec_init_tables(k, p, &encode_matrix[k * k], g_tbls);
178041379a6SGreg Tucker 
179041379a6SGreg Tucker         // Generate EC parity blocks from sources
180041379a6SGreg Tucker         ec_encode_data(len, k, p, g_tbls, frag_ptrs, &frag_ptrs[k]);
181041379a6SGreg Tucker 
182041379a6SGreg Tucker         if (nerrs <= 0)
183041379a6SGreg Tucker                 return 0;
184041379a6SGreg Tucker 
185041379a6SGreg Tucker         printf(" recover %d fragments\n", nerrs);
186041379a6SGreg Tucker 
187041379a6SGreg Tucker         // Find a decode matrix to regenerate all erasures from remaining frags
188*9d99f821SMarcel Cornu         ret = gf_gen_decode_matrix_simple(encode_matrix, decode_matrix, invert_matrix, temp_matrix,
189*9d99f821SMarcel Cornu                                           decode_index, frag_err_list, nerrs, k, m);
190041379a6SGreg Tucker         if (ret != 0) {
191041379a6SGreg Tucker                 printf("Fail on generate decode matrix\n");
192041379a6SGreg Tucker                 return -1;
193041379a6SGreg Tucker         }
194041379a6SGreg Tucker         // Pack recovery array pointers as list of valid fragments
195041379a6SGreg Tucker         for (i = 0; i < k; i++)
196041379a6SGreg Tucker                 recover_srcs[i] = frag_ptrs[decode_index[i]];
197041379a6SGreg Tucker 
198041379a6SGreg Tucker         // Recover data
199041379a6SGreg Tucker         ec_init_tables(k, nerrs, decode_matrix, g_tbls);
200041379a6SGreg Tucker         ec_encode_data(len, k, nerrs, g_tbls, recover_srcs, recover_outp);
201041379a6SGreg Tucker 
202041379a6SGreg Tucker         // Check that recovered buffers are the same as original
203041379a6SGreg Tucker         printf(" check recovery of block {");
204041379a6SGreg Tucker         for (i = 0; i < nerrs; i++) {
205041379a6SGreg Tucker                 printf(" %d", frag_err_list[i]);
206041379a6SGreg Tucker                 if (memcmp(recover_outp[i], frag_ptrs[frag_err_list[i]], len)) {
207041379a6SGreg Tucker                         printf(" Fail erasure recovery %d, frag %d\n", i, frag_err_list[i]);
208041379a6SGreg Tucker                         return -1;
209041379a6SGreg Tucker                 }
210041379a6SGreg Tucker         }
211041379a6SGreg Tucker 
212041379a6SGreg Tucker         printf(" } done all: Pass\n");
213041379a6SGreg Tucker         return 0;
214041379a6SGreg Tucker }
215041379a6SGreg Tucker 
216041379a6SGreg Tucker /*
217041379a6SGreg Tucker  * Generate decode matrix from encode matrix and erasure list
218041379a6SGreg Tucker  *
219041379a6SGreg Tucker  */
220041379a6SGreg Tucker 
221*9d99f821SMarcel Cornu static int
gf_gen_decode_matrix_simple(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)222*9d99f821SMarcel Cornu gf_gen_decode_matrix_simple(u8 *encode_matrix, u8 *decode_matrix, u8 *invert_matrix,
223*9d99f821SMarcel Cornu                             u8 *temp_matrix, u8 *decode_index, u8 *frag_err_list, int nerrs, int k,
224041379a6SGreg Tucker                             int m)
225041379a6SGreg Tucker {
226041379a6SGreg Tucker         int i, j, p, r;
227041379a6SGreg Tucker         int nsrcerrs = 0;
228041379a6SGreg Tucker         u8 s, *b = temp_matrix;
229041379a6SGreg Tucker         u8 frag_in_err[MMAX];
230041379a6SGreg Tucker 
231041379a6SGreg Tucker         memset(frag_in_err, 0, sizeof(frag_in_err));
232041379a6SGreg Tucker 
233041379a6SGreg Tucker         // Order the fragments in erasure for easier sorting
234041379a6SGreg Tucker         for (i = 0; i < nerrs; i++) {
235041379a6SGreg Tucker                 if (frag_err_list[i] < k)
236041379a6SGreg Tucker                         nsrcerrs++;
237041379a6SGreg Tucker                 frag_in_err[frag_err_list[i]] = 1;
238041379a6SGreg Tucker         }
239041379a6SGreg Tucker 
240041379a6SGreg Tucker         // Construct b (matrix that encoded remaining frags) by removing erased rows
241041379a6SGreg Tucker         for (i = 0, r = 0; i < k; i++, r++) {
242041379a6SGreg Tucker                 while (frag_in_err[r])
243041379a6SGreg Tucker                         r++;
244041379a6SGreg Tucker                 for (j = 0; j < k; j++)
245041379a6SGreg Tucker                         b[k * i + j] = encode_matrix[k * r + j];
246041379a6SGreg Tucker                 decode_index[i] = r;
247041379a6SGreg Tucker         }
248041379a6SGreg Tucker 
249041379a6SGreg Tucker         // Invert matrix to get recovery matrix
250041379a6SGreg Tucker         if (gf_invert_matrix(b, invert_matrix, k) < 0)
251041379a6SGreg Tucker                 return -1;
252041379a6SGreg Tucker 
253041379a6SGreg Tucker         // Get decode matrix with only wanted recovery rows
2549edac479SGreg Tucker         for (i = 0; i < nerrs; i++) {
2559edac479SGreg Tucker                 if (frag_err_list[i] < k) // A src err
2569edac479SGreg Tucker                         for (j = 0; j < k; j++)
257*9d99f821SMarcel Cornu                                 decode_matrix[k * i + j] = invert_matrix[k * frag_err_list[i] + j];
258041379a6SGreg Tucker         }
259041379a6SGreg Tucker 
260041379a6SGreg Tucker         // For non-src (parity) erasures need to multiply encode matrix * invert
2619edac479SGreg Tucker         for (p = 0; p < nerrs; p++) {
2629edac479SGreg Tucker                 if (frag_err_list[p] >= k) { // A parity err
263041379a6SGreg Tucker                         for (i = 0; i < k; i++) {
264041379a6SGreg Tucker                                 s = 0;
265041379a6SGreg Tucker                                 for (j = 0; j < k; j++)
266041379a6SGreg Tucker                                         s ^= gf_mul(invert_matrix[j * k + i],
267041379a6SGreg Tucker                                                     encode_matrix[k * frag_err_list[p] + j]);
268041379a6SGreg Tucker                                 decode_matrix[k * p + i] = s;
269041379a6SGreg Tucker                         }
270041379a6SGreg Tucker                 }
2719edac479SGreg Tucker         }
272041379a6SGreg Tucker         return 0;
273041379a6SGreg Tucker }
274