ESymSolverStatus MumpsSolverInterface::SymbolicFactorization() { DBG_START_METH("MumpsSolverInterface::SymbolicFactorization", dbg_verbosity); DMUMPS_STRUC_C* mumps_data = (DMUMPS_STRUC_C*)mumps_ptr_; if (HaveIpData()) { IpData().TimingStats().LinearSystemSymbolicFactorization().Start(); } mumps_data->job = 1;//symbolic ordering pass //mumps_data->icntl[1] = 6; //mumps_data->icntl[2] = 6;//QUIETLY! //mumps_data->icntl[3] = 4; mumps_data->icntl[5] = mumps_permuting_scaling_; mumps_data->icntl[6] = mumps_pivot_order_; mumps_data->icntl[7] = mumps_scaling_; mumps_data->icntl[9] = 0;//no iterative refinement iterations mumps_data->icntl[12] = 1;//avoid lapack bug, ensures proper inertia mumps_data->icntl[13] = mem_percent_; //% memory to allocate over expected mumps_data->cntl[0] = pivtol_; // Set pivot tolerance dump_matrix(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Calling MUMPS-1 for symbolic factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); dmumps_c(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Done with MUMPS-1 for symbolic factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); int error = mumps_data->info[0]; const int& mumps_permuting_scaling_used = mumps_data->infog[22]; const int& mumps_pivot_order_used = mumps_data->infog[6]; Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "MUMPS used permuting_scaling %d and pivot_order %d.\n", mumps_permuting_scaling_used, mumps_pivot_order_used); Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, " scaling will be %d.\n", mumps_data->icntl[7]); if (HaveIpData()) { IpData().TimingStats().LinearSystemSymbolicFactorization().End(); } //return appropriat value if (error == -6) {//system is singular Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "MUMPS returned INFO(1) = %d matrix is singular.\n",error); return SYMSOLVER_SINGULAR; } if (error < 0) { Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "Error=%d returned from MUMPS in Factorization.\n", error); return SYMSOLVER_FATAL_ERROR; } return SYMSOLVER_SUCCESS; }
ESymSolverStatus MumpsSolverInterface::Factorization( bool check_NegEVals, Index numberOfNegEVals) { DBG_START_METH("MumpsSolverInterface::Factorization", dbg_verbosity); DMUMPS_STRUC_C* mumps_data = (DMUMPS_STRUC_C*)mumps_ptr_; mumps_data->job = 2;//numerical factorization dump_matrix(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Calling MUMPS-2 for numerical factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); dmumps_c(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Done with MUMPS-2 for numerical factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); int error = mumps_data->info[0]; //Check for errors if (error == -8 || error == -9) {//not enough memory const Index trycount_max = 20; for (int trycount=0; trycount<trycount_max; trycount++) { Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA, "MUMPS returned INFO(1) = %d and requires more memory, reallocating. Attempt %d\n", error,trycount+1); Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA, " Increasing icntl[13] from %d to ", mumps_data->icntl[13]); double mem_percent = mumps_data->icntl[13]; mumps_data->icntl[13] = (Index)(2.0 * mem_percent); Jnlst().Printf(J_WARNING, J_LINEAR_ALGEBRA, "%d.\n", mumps_data->icntl[13]); dump_matrix(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Calling MUMPS-2 (repeated) for numerical factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); dmumps_c(mumps_data); Jnlst().Printf(J_MOREDETAILED, J_LINEAR_ALGEBRA, "Done with MUMPS-2 (repeated) for numerical factorization at cpu time %10.3f (wall %10.3f).\n", CpuTime(), WallclockTime()); error = mumps_data->info[0]; if (error != -8 && error != -9) break; } if (error == -8 || error == -9) { Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "MUMPS was not able to obtain enough memory.\n"); return SYMSOLVER_FATAL_ERROR; } } Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "Number of doubles for MUMPS to hold factorization (INFO(9)) = %d\n", mumps_data->info[8]); Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "Number of integers for MUMPS to hold factorization (INFO(10)) = %d\n", mumps_data->info[9]); if (error == -10) {//system is singular Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "MUMPS returned INFO(1) = %d matrix is singular.\n",error); return SYMSOLVER_SINGULAR; } negevals_ = mumps_data->infog[11]; if (error == -13) { Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "MUMPS returned INFO(1) =%d - out of memory when trying to allocate %d %s.\nIn some cases it helps to decrease the value of the option \"mumps_mem_percent\".\n", error, mumps_data->info[1] < 0 ? -mumps_data->info[1] : mumps_data->info[1], mumps_data->info[1] < 0 ? "MB" : "bytes"); return SYMSOLVER_FATAL_ERROR; } if (error < 0) {//some other error Jnlst().Printf(J_ERROR, J_LINEAR_ALGEBRA, "MUMPS returned INFO(1) =%d MUMPS failure.\n", error); return SYMSOLVER_FATAL_ERROR; } if (check_NegEVals && (numberOfNegEVals!=negevals_)) { Jnlst().Printf(J_DETAILED, J_LINEAR_ALGEBRA, "In MumpsSolverInterface::Factorization: negevals_ = %d, but numberOfNegEVals = %d\n", negevals_, numberOfNegEVals); return SYMSOLVER_WRONG_INERTIA; } return SYMSOLVER_SUCCESS; }
int main(int argc, char *argv[]) { int i, j, rtest, srcs, m, k, nerrs, r, err; void *buf; u8 g[TEST_SOURCES], g_tbls[TEST_SOURCES*32], src_in_err[TEST_SOURCES]; u8 *dest, *dest_ref, *temp_buff, *buffs[TEST_SOURCES]; u8 a[MMAX*KMAX], b[MMAX*KMAX], d[MMAX*KMAX]; u8 src_err_list[TEST_SOURCES], *recov[TEST_SOURCES]; int align, size; unsigned char *efence_buffs[TEST_SOURCES]; unsigned int offset; u8 *ubuffs[TEST_SOURCES]; u8 *udest_ptr; printf("gf_vect_dot_prod_sse: %dx%d ", TEST_SOURCES, TEST_LEN); mk_gf_field(); // Allocate the arrays for(i=0; i<TEST_SOURCES; i++){ if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } temp_buff = buf; // Test of all zeros for(i=0; i<TEST_SOURCES; i++) memset(buffs[i], 0, TEST_LEN); memset(dest, 0, TEST_LEN); memset(temp_buff, 0, TEST_LEN); memset(dest_ref, 0, TEST_LEN); memset(g, 0, TEST_SOURCES); for(i=0; i<TEST_SOURCES; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref); gf_vect_dot_prod_sse(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest); if (0 != memcmp(dest_ref, dest, TEST_LEN)){ printf("Fail zero vect_dot_prod_sse test\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref, 25); printf("dprod_sse:"); dump(dest, 25);; return -1; } else putchar('.'); // Rand data test for(rtest=0; rtest<RANDOMS; rtest++){ for(i=0; i<TEST_SOURCES; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); for (i=0; i<TEST_SOURCES; i++) g[i] = rand(); for(i=0; i<TEST_SOURCES; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref); gf_vect_dot_prod_sse(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest); if (0 != memcmp(dest_ref, dest, TEST_LEN)){ printf("Fail rand vect_dot_prod_sse test 1\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref, 25); printf("dprod_sse:"); dump(dest, 25); return -1; } putchar('.'); } // Rand data test with varied parameters for(rtest=0; rtest < RANDOMS; rtest++){ for (srcs = TEST_SOURCES; srcs > 0; srcs--){ for(i=0; i<srcs; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); for (i=0; i<srcs; i++) g[i] = rand(); for(i=0; i<srcs; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref); gf_vect_dot_prod_sse(TEST_LEN, srcs, g_tbls, buffs, dest); if (0 != memcmp(dest_ref, dest, TEST_LEN)){ printf("Fail rand vect_dot_prod_sse test 2\n"); dump_matrix(buffs, 5, srcs); printf("dprod_base:"); dump(dest_ref, 5); printf("dprod_sse:"); dump(dest, 5); return -1; } putchar('.'); } } // Test erasure code using gf_vect_dot_prod // Pick a first test m = 9; k = 5; if (m > MMAX || k > KMAX) return -1; gf_gen_rs_matrix(a, m, k); // Make random data for(i=0; i<k; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); // Make parity vects for (i=k; i<m; i++) { for (j=0; j<k; j++) gf_vect_mul_init(a[k*i+j], &g_tbls[j*32]); #ifndef USEREF gf_vect_dot_prod_sse(TEST_LEN, k, g_tbls, buffs, buffs[i]); #else gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], buffs, buffs[i]); #endif } // Random buffers in erasure memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } // construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) { r++; continue; } for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix((u8*)b, (u8*)d, k) < 0) printf("BAD MATRIX\n"); for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) { r++; continue; } recov[i] = buffs[r]; } // Recover data for(i=0; i<nerrs; i++){ for (j=0; j<k; j++) gf_vect_mul_init(d[k*src_err_list[i]+j], &g_tbls[j*32]); #ifndef USEREF gf_vect_dot_prod_sse(TEST_LEN, k, g_tbls, recov, temp_buff); #else gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], recov, temp_buff); #endif if (0 != memcmp(temp_buff, buffs[src_err_list[i]], TEST_LEN)){ printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf("recov %d:",src_err_list[i]); dump(temp_buff, 25); printf("orig :"); dump(buffs[src_err_list[i]],25); return -1; } } // Do more random tests for (rtest = 0; rtest < RANDOMS; rtest++){ while ((m = (rand() % MMAX)) < 2); while ((k = (rand() % KMAX)) >= m || k < 1); if (m>MMAX || k>KMAX) continue; gf_gen_rs_matrix(a, m, k); // Make random data for(i=0; i<k; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); // Make parity vects for (i=k; i<m; i++) { for (j=0; j<k; j++) gf_vect_mul_init(a[k*i+j], &g_tbls[j*32]); #ifndef USEREF gf_vect_dot_prod_sse(TEST_LEN, k, g_tbls, buffs, buffs[i]); #else gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], buffs, buffs[i]); #endif } // Random errors memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0){ // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } // construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) { r++; continue; } for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix((u8*)b, (u8*)d, k) < 0) printf("BAD MATRIX\n"); for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) { r++; continue; } recov[i] = buffs[r]; } // Recover data for(i=0; i<nerrs; i++){ for (j=0; j<k; j++) gf_vect_mul_init(d[k*src_err_list[i]+j], &g_tbls[j*32]); #ifndef USEREF gf_vect_dot_prod_sse(TEST_LEN, k, g_tbls, recov, temp_buff); #else gf_vect_dot_prod_base(TEST_LEN, k, &g_tbls[0], recov, temp_buff); #endif if (0 != memcmp(temp_buff, buffs[src_err_list[i]], TEST_LEN)){ printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\na:\n"); dump_u8xu8((u8*)a, m, k); printf("inv b:\n"); dump_u8xu8((u8*)d, k, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]],25); printf("recov %d:",src_err_list[i]); dump(temp_buff, 25); return -1; } } putchar('.'); } // Run tests at end of buffer for Electric Fence align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; for(size=EFENCE_TEST_MIN_SIZE; size<=TEST_SIZE; size+=align){ for(i=0; i<TEST_SOURCES; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); for(i=0; i<TEST_SOURCES; i++) // Line up TEST_SIZE from end efence_buffs[i] = buffs[i] + TEST_LEN - size; for (i=0; i<TEST_SOURCES; i++) g[i] = rand(); for(i=0; i<TEST_SOURCES; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref); gf_vect_dot_prod_sse(size, TEST_SOURCES, g_tbls, efence_buffs, dest); if (0 != memcmp(dest_ref, dest, size)){ printf("Fail rand vect_dot_prod_sse test 3\n"); dump_matrix(efence_buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref, align); printf("dprod_sse:"); dump(dest, align); return -1; } putchar('.'); } // Test rand ptr alignment if available for(rtest=0; rtest<RANDOMS; rtest++){ size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~15; srcs = rand() % TEST_SOURCES; if (srcs == 0) continue; offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B; // Add random offsets for(i=0; i<srcs; i++) ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); udest_ptr = dest + (rand() & (PTR_ALIGN_CHK_B - offset)); memset(dest, 0, TEST_LEN); // zero pad to check write-over for(i=0; i<srcs; i++) for(j=0; j<size; j++) ubuffs[i][j] = rand(); for (i=0; i<srcs; i++) g[i] = rand(); for(i=0; i<srcs; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref); gf_vect_dot_prod_sse(size, srcs, g_tbls, ubuffs, udest_ptr); if (memcmp(dest_ref, udest_ptr, size)){ printf("Fail rand vect_dot_prod_sse test ualign srcs=%d\n", srcs); dump_matrix(ubuffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref, 25); printf("dprod_sse:"); dump(udest_ptr, 25); return -1; } // Confirm that padding around dests is unchanged memset(dest_ref, 0, PTR_ALIGN_CHK_B); // Make reference zero buff offset = udest_ptr - dest; if (memcmp(dest, dest_ref, offset)){ printf("Fail rand ualign pad start\n"); return -1; } if (memcmp(dest + offset + size, dest_ref, PTR_ALIGN_CHK_B - offset)){ printf("Fail rand ualign pad end\n"); return -1; } putchar('.'); } // Test all size alignment align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; for(size=TEST_LEN; size>15; size-=align){ srcs = TEST_SOURCES; for(i=0; i<srcs; i++) for(j=0; j<size; j++) buffs[i][j] = rand(); for (i=0; i<srcs; i++) g[i] = rand(); for(i=0; i<srcs; i++) gf_vect_mul_init(g[i], &g_tbls[i*32]); gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref); gf_vect_dot_prod_sse(size, srcs, g_tbls, buffs, dest); if (memcmp(dest_ref, dest, size)){ printf("Fail rand vect_dot_prod_sse test ualign len=%d\n", size); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref, 25); printf("dprod_sse:"); dump(dest, 25); return -1; } } printf("done all: Pass\n"); return 0; }
int main(int argc, char *argv[]) { int i, j; void *buf; u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES]; u8 g_tbls[3 * TEST_SOURCES * 32], *dest_ptrs[3], *buffs[TEST_SOURCES]; u8 *dest1, *dest2, *dest3, *dest_ref1, *dest_ref2, *dest_ref3; struct perf start, stop; printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d\n", TEST_SOURCES, TEST_LEN); // Allocate the arrays for (i = 0; i < TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest1 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest2 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest3 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref1 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref2 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref3 = buf; dest_ptrs[0] = dest1; dest_ptrs[1] = dest2; dest_ptrs[2] = dest3; // Performance test for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); memset(dest1, 0, TEST_LEN); memset(dest2, 0, TEST_LEN); memset(dest_ref1, 0, TEST_LEN); memset(dest_ref2, 0, TEST_LEN); for (i = 0; i < TEST_SOURCES; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (j = 0; j < TEST_SOURCES; j++) { gf_vect_mul_init(g1[j], &g_tbls[j * 32]); gf_vect_mul_init(g2[j], &g_tbls[(32 * TEST_SOURCES) + (j * 32)]); gf_vect_mul_init(g3[j], &g_tbls[(64 * TEST_SOURCES) + (j * 32)]); } gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs, dest_ref2); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs, dest_ref3); #ifdef DO_REF_PERF perf_start(&start); for (i = 0; i < TEST_LOOPS / 100; i++) { for (j = 0; j < TEST_SOURCES; j++) { gf_vect_mul_init(g1[j], &g_tbls[j * 32]); gf_vect_mul_init(g2[j], &g_tbls[(32 * TEST_SOURCES) + (j * 32)]); gf_vect_mul_init(g3[j], &g_tbls[(64 * TEST_SOURCES) + (j * 32)]); } gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs, dest_ref2); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs, dest_ref3); } perf_stop(&stop); printf("gf_3vect_dot_prod_base" TEST_TYPE_STR ": "); perf_print(stop, start, (long long)TEST_LEN * (TEST_SOURCES + 3) * i); #endif FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs); perf_start(&start); for (i = 0; i < TEST_LOOPS; i++) { for (j = 0; j < TEST_SOURCES; j++) { gf_vect_mul_init(g1[j], &g_tbls[j * 32]); gf_vect_mul_init(g2[j], &g_tbls[(32 * TEST_SOURCES) + (j * 32)]); gf_vect_mul_init(g3[j], &g_tbls[(64 * TEST_SOURCES) + (j * 32)]); } FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs); } perf_stop(&stop); printf(xstr(FUNCTION_UNDER_TEST) TEST_TYPE_STR ": "); perf_print(stop, start, (long long)TEST_LEN * (TEST_SOURCES + 3) * i); if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) { printf("Fail perf " xstr(FUNCTION_UNDER_TEST) " test1\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(dest1, 25); return -1; } if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) { printf("Fail perf " xstr(FUNCTION_UNDER_TEST) " test2\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(dest2, 25); return -1; } if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) { printf("Fail perf " xstr(FUNCTION_UNDER_TEST) " test3\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(dest3, 25); return -1; } printf("pass perf check\n"); return 0; }
int main(int argc, char *argv[]) { struct thread_data *threads; struct thread_data *thread; int i, ret, ch; if (argc > 1) { if (strcmp(argv[1], "--help") == 0) { usage_error(argv[0]); } init_program_parameter(argc, argv); } program_parameter(argv[0]); create_matrix(&matrix_a); create_matrix(&matrix_b); create_matrix(&matrix_c); create_matrix(&matrix_d); random_matrix(matrix_a); random_matrix(matrix_b); nonmal_matrix_multipy(matrix_a, matrix_b, matrix_d); threads = (struct thread_data *)malloc(pthread_max * sizeof(struct thread_data)); if (threads == NULL) { unix_error("malloc threads failed"); } cpu_online = sysconf(_SC_NPROCESSORS_CONF); for(i = 0; i < pthread_max; i++) { thread = threads + i; thread->index = i; if ((ret = pthread_create(&thread->thread_id, NULL, thread_func, thread)) != 0) { posix_error(ret, "pthread_create failed"); } } for(i = 0; i < pthread_max; i++) { thread = threads + i; if ((ret = pthread_join(thread->thread_id, NULL)) != 0) { posix_error(ret, "pthread_join failed"); } } if (matrix_equal(matrix_c, matrix_d) == 0) { unix_error("runtime error"); } if (dump) { dump_matrix("matrix A", matrix_a); dump_matrix("matrix B", matrix_b); dump_matrix("matrix C", matrix_c); dump_matrix("matrix D", matrix_d); } statistics(threads); free_matrix(matrix_a); free_matrix(matrix_b); free_matrix(matrix_c); free_matrix(matrix_d); free(threads); return 0; }
int main(int argc, char *argv[]) { int i, j, rtest, srcs; void *buf; u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES]; u8 g_tbls[3 * TEST_SOURCES * 32], *dest_ptrs[3], *buffs[TEST_SOURCES]; u8 *dest1, *dest2, *dest3, *dest_ref1, *dest_ref2, *dest_ref3; int align, size; unsigned char *efence_buffs[TEST_SOURCES]; unsigned int offset; u8 *ubuffs[TEST_SOURCES]; u8 *udest_ptrs[3]; printf(xstr(FUNCTION_UNDER_TEST) "_test: %dx%d ", TEST_SOURCES, TEST_LEN); // Allocate the arrays for (i = 0; i < TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest1 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest2 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest3 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref1 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail");; return -1; } dest_ref2 = buf; if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref3 = buf; dest_ptrs[0] = dest1; dest_ptrs[1] = dest2; dest_ptrs[2] = dest3; // Test of all zeros for (i = 0; i < TEST_SOURCES; i++) memset(buffs[i], 0, TEST_LEN); memset(dest1, 0, TEST_LEN); memset(dest2, 0, TEST_LEN); memset(dest3, 0, TEST_LEN); memset(dest_ref1, 0, TEST_LEN); memset(dest_ref2, 0, TEST_LEN); memset(dest_ref3, 0, TEST_LEN); memset(g1, 2, TEST_SOURCES); memset(g2, 1, TEST_SOURCES); memset(g3, 7, TEST_SOURCES); for (i = 0; i < TEST_SOURCES; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]); gf_vect_mul_init(g3[i], &g_tbls[64 * TEST_SOURCES + i * 32]); } gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs, dest_ref2); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs, dest_ref3); FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs); if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) { printf("Fail zero" xstr(FUNCTION_UNDER_TEST) " test1\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(dest1, 25); return -1; } if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) { printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(dest2, 25); return -1; } if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) { printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test3\n"); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(dest3, 25); return -1; } putchar('.'); // Rand data test for (rtest = 0; rtest < RANDOMS; rtest++) { for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < TEST_SOURCES; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (i = 0; i < TEST_SOURCES; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]); gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]); } gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs, dest_ref2); gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs, dest_ref3); FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs); if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(dest1, 25); return -1; } if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(dest2, 25); return -1; } if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(dest3, 25); return -1; } putchar('.'); } // Rand data test with varied parameters for (rtest = 0; rtest < RANDOMS; rtest++) { for (srcs = TEST_SOURCES; srcs > 0; srcs--) { for (i = 0; i < srcs; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < srcs; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (i = 0; i < srcs; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]); gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]); } gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs, dest_ref2); gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[64 * srcs], buffs, dest_ref3); FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs); if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 srcs=%d\n", srcs); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(dest1, 25); return -1; } if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 srcs=%d\n", srcs); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(dest2, 25); return -1; } if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 srcs=%d\n", srcs); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(dest3, 25); return -1; } putchar('.'); } } // Run tests at end of buffer for Electric Fence align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) { for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end efence_buffs[i] = buffs[i] + TEST_LEN - size; for (i = 0; i < TEST_SOURCES; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (i = 0; i < TEST_SOURCES; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]); gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]); } gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1); gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], efence_buffs, dest_ref2); gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], efence_buffs, dest_ref3); FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs); if (0 != memcmp(dest_ref1, dest1, size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest); dump_matrix(efence_buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, align); printf("dprod_dut:"); dump(dest1, align); return -1; } if (0 != memcmp(dest_ref2, dest2, size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest); dump_matrix(efence_buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, align); printf("dprod_dut:"); dump(dest2, align); return -1; } if (0 != memcmp(dest_ref3, dest3, size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest); dump_matrix(efence_buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, align); printf("dprod_dut:"); dump(dest3, align); return -1; } putchar('.'); } // Test rand ptr alignment if available for (rtest = 0; rtest < RANDOMS; rtest++) { size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1); srcs = rand() % TEST_SOURCES; if (srcs == 0) continue; offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B; // Add random offsets for (i = 0; i < srcs; i++) ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset)); udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset)); udest_ptrs[2] = dest3 + (rand() & (PTR_ALIGN_CHK_B - offset)); memset(dest1, 0, TEST_LEN); // zero pad to check write-over memset(dest2, 0, TEST_LEN); memset(dest3, 0, TEST_LEN); for (i = 0; i < srcs; i++) for (j = 0; j < size; j++) ubuffs[i][j] = rand(); for (i = 0; i < srcs; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (i = 0; i < srcs; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]); gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]); } gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1); gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2); gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], ubuffs, dest_ref3); FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs); if (memcmp(dest_ref1, udest_ptrs[0], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n", srcs); dump_matrix(ubuffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(udest_ptrs[0], 25); return -1; } if (memcmp(dest_ref2, udest_ptrs[1], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n", srcs); dump_matrix(ubuffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(udest_ptrs[1], 25); return -1; } if (memcmp(dest_ref3, udest_ptrs[2], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n", srcs); dump_matrix(ubuffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(udest_ptrs[2], 25); return -1; } // Confirm that padding around dests is unchanged memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff offset = udest_ptrs[0] - dest1; if (memcmp(dest1, dest_ref1, offset)) { printf("Fail rand ualign pad1 start\n"); return -1; } if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign pad1 end\n"); return -1; } offset = udest_ptrs[1] - dest2; if (memcmp(dest2, dest_ref1, offset)) { printf("Fail rand ualign pad2 start\n"); return -1; } if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign pad2 end\n"); return -1; } offset = udest_ptrs[2] - dest3; if (memcmp(dest3, dest_ref1, offset)) { printf("Fail rand ualign pad3 start\n"); return -1; } if (memcmp(dest3 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign pad3 end\n");; return -1; } putchar('.'); } // Test all size alignment align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) { srcs = TEST_SOURCES; for (i = 0; i < srcs; i++) for (j = 0; j < size; j++) buffs[i][j] = rand(); for (i = 0; i < srcs; i++) { g1[i] = rand(); g2[i] = rand(); g3[i] = rand(); } for (i = 0; i < srcs; i++) { gf_vect_mul_init(g1[i], &g_tbls[i * 32]); gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]); gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]); } gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1); gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2); gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], buffs, dest_ref3); FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs); if (memcmp(dest_ref1, dest_ptrs[0], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n", size); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref1, 25); printf("dprod_dut:"); dump(dest_ptrs[0], 25); return -1; } if (memcmp(dest_ref2, dest_ptrs[1], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n", size); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref2, 25); printf("dprod_dut:"); dump(dest_ptrs[1], 25); return -1; } if (memcmp(dest_ref3, dest_ptrs[2], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n", size); dump_matrix(buffs, 5, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref3, 25); printf("dprod_dut:"); dump(dest_ptrs[2], 25); return -1; } } printf("Pass\n"); return 0; }
void mexFunction ( /* === Parameters ======================================================= */ int nlhs, /* number of left-hand sides */ mxArray *plhs [], /* left-hand side matrices */ int nrhs, /* number of right--hand sides */ const mxArray *prhs [] /* right-hand side matrices */ ) { /* === Local variables ================================================== */ Long *perm ; /* column ordering of M and ordering of A */ Long *A ; /* row indices of input matrix A */ Long *p ; /* column pointers of input matrix A */ Long n_col ; /* number of columns of A */ Long n_row ; /* number of rows of A */ Long full ; /* TRUE if input matrix full, FALSE if sparse */ double knobs [COLAMD_KNOBS] ; /* colamd user-controllable parameters */ double *out_perm ; /* output permutation vector */ double *out_stats ; /* output stats vector */ double *in_knobs ; /* input knobs vector */ Long i ; /* loop counter */ mxArray *Ainput ; /* input matrix handle */ Long spumoni ; /* verbosity variable */ Long stats2 [COLAMD_STATS] ;/* stats for symamd */ Long *cp, *cp_end, result, nnz, col, length ; Long *stats ; stats = stats2 ; /* === Check inputs ===================================================== */ if (nrhs < 1 || nrhs > 2 || nlhs < 0 || nlhs > 2) { mexErrMsgTxt ( "symamd: incorrect number of input and/or output arguments.") ; } if (nrhs != 2) { mexErrMsgTxt ("symamdtest: knobs are required") ; } /* for testing we require all 3 knobs */ if (mxGetNumberOfElements (prhs [1]) != 3) { mexErrMsgTxt ("symamdtest: must have all 3 knobs for testing") ; } /* === Get knobs ======================================================== */ colamd_l_set_defaults (knobs) ; spumoni = 0 ; /* check for user-passed knobs */ if (nrhs == 2) { in_knobs = mxGetPr (prhs [1]) ; i = mxGetNumberOfElements (prhs [1]) ; if (i > 0) knobs [COLAMD_DENSE_ROW] = in_knobs [0] ; if (i > 1) spumoni = (Long) in_knobs [1] ; } /* print knob settings if spumoni is set */ if (spumoni) { mexPrintf ("\nsymamd version %d.%d, %s:\n", COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE) ; if (knobs [COLAMD_DENSE_ROW] >= 0) { mexPrintf ("knobs(1): %g, rows/cols with > " "max(16,%g*sqrt(size(A,2))) entries removed\n", in_knobs [0], knobs [COLAMD_DENSE_ROW]) ; } else { mexPrintf ("knobs(1): %g, no dense rows removed\n", in_knobs [0]) ; } mexPrintf ("knobs(2): %g, statistics and knobs printed\n", in_knobs [1]) ; mexPrintf ("Testing %d\n", in_knobs [2]) ; } /* === If A is full, convert to a sparse matrix ========================= */ Ainput = (mxArray *) prhs [0] ; if (mxGetNumberOfDimensions (Ainput) != 2) { mexErrMsgTxt ("symamd: input matrix must be 2-dimensional.") ; } full = !mxIsSparse (Ainput) ; if (full) { mexCallMATLAB (1, &Ainput, 1, (mxArray **) prhs, "sparse") ; } /* === Allocate workspace for symamd ==================================== */ /* get size of matrix */ n_row = mxGetM (Ainput) ; n_col = mxGetN (Ainput) ; if (n_col != n_row) { mexErrMsgTxt ("symamd: matrix must be square.") ; } /* p = mxGetJc (Ainput) ; */ p = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; (void) memcpy (p, mxGetJc (Ainput), (n_col+1)*sizeof (Long)) ; nnz = p [n_col] ; if (spumoni > 0) { mexPrintf ("symamdtest: nnz %d\n", nnz) ; } /* A = mxGetIr (Ainput) ; */ A = (Long *) mxCalloc (nnz+1, sizeof (Long)) ; (void) memcpy (A, mxGetIr (Ainput), nnz*sizeof (Long)) ; perm = (Long *) mxCalloc (n_col+1, sizeof (Long)) ; /* === Jumble matrix ======================================================== */ /* knobs [2] FOR TESTING ONLY: Specifies how to jumble matrix 0 : No jumbling 1 : (no errors) 2 : Make first pointer non-zero 3 : Make column pointers not non-decreasing 4 : (no errors) 5 : Make row indices not strictly increasing 6 : Make a row index greater or equal to n_row 7 : Set A = NULL 8 : Set p = NULL 9 : Repeat row index 10: make row indices not sorted 11: jumble columns massively (note this changes the pattern of the matrix A.) 12: Set stats = NULL 13: Make n_col less than zero */ /* jumble appropriately */ switch ((Long) in_knobs [2]) { case 0 : if (spumoni > 0) { mexPrintf ("symamdtest: no errors expected\n") ; } result = 1 ; /* no errors */ break ; case 1 : if (spumoni > 0) { mexPrintf ("symamdtest: no errors expected (1)\n") ; } result = 1 ; break ; case 2 : if (spumoni > 0) { mexPrintf ("symamdtest: p [0] nonzero\n") ; } result = 0 ; /* p [0] must be zero */ p [0] = 1 ; break ; case 3 : if (spumoni > 0) { mexPrintf ("symamdtest: negative length last column\n") ; } result = (n_col == 0) ; /* p must be monotonically inc. */ p [n_col] = p [0] ; break ; case 4 : if (spumoni > 0) { mexPrintf ("symamdtest: no errors expected (4)\n") ; } result = 1 ; break ; case 5 : if (spumoni > 0) { mexPrintf ("symamdtest: row index out of range (-1)\n") ; } if (nnz > 0) /* row index out of range */ { result = 0 ; A [nnz-1] = -1 ; } else { if (spumoni > 0) { mexPrintf ("Note: no row indices to put out of range\n") ; } result = 1 ; } break ; case 6 : if (spumoni > 0) { mexPrintf ("symamdtest: row index out of range (ncol)\n") ; } if (nnz > 0) /* row index out of range */ { result = 0 ; A [nnz-1] = n_col ; } else { if (spumoni > 0) { mexPrintf ("Note: no row indices to put out of range\n") ; } result = 1 ; } break ; case 7 : if (spumoni > 0) { mexPrintf ("symamdtest: A not present\n") ; } result = 0 ; /* A not present */ A = (Long *) NULL ; break ; case 8 : if (spumoni > 0) { mexPrintf ("symamdtest: p not present\n") ; } result = 0 ; /* p not present */ p = (Long *) NULL ; break ; case 9 : if (spumoni > 0) { mexPrintf ("symamdtest: duplicate row index\n") ; } result = 1 ; /* duplicate row index */ for (col = 0 ; col < n_col ; col++) { length = p [col+1] - p [col] ; if (length > 1) { A [p [col+1]-2] = A [p [col+1] - 1] ; if (spumoni > 0) { mexPrintf ("Made duplicate row %d in col %d\n", A [p [col+1] - 1], col) ; } break ; } } if (spumoni > 1) { dump_matrix (A, p, n_row, n_col, nnz, col+2) ; } break ; case 10 : if (spumoni > 0) { mexPrintf ("symamdtest: unsorted column\n") ; } result = 1 ; /* jumbled columns */ for (col = 0 ; col < n_col ; col++) { length = p [col+1] - p [col] ; if (length > 1) { i = A[p [col]] ; A [p [col]] = A[p [col] + 1] ; A [p [col] + 1] = i ; if (spumoni > 0) { mexPrintf ("Unsorted column %d \n", col) ; } break ; } } if (spumoni > 1) { dump_matrix (A, p, n_row, n_col, nnz, col+2) ; } break ; case 11 : if (spumoni > 0) { mexPrintf ("symamdtest: massive jumbling\n") ; } result = 1 ; /* massive jumbling, but no errors */ srand (1) ; for (i = 0 ; i < n_col ; i++) { cp = &A [p [i]] ; cp_end = &A [p [i+1]] ; while (cp < cp_end) { *cp++ = rand() % n_row ; } } if (spumoni > 1) { dump_matrix (A, p, n_row, n_col, nnz, n_col) ; } break ; case 12 : if (spumoni > 0) { mexPrintf ("symamdtest: stats not present\n") ; } result = 0 ; /* stats not present */ stats = (Long *) NULL ; break ; case 13 : if (spumoni > 0) { mexPrintf ("symamdtest: ncol out of range\n") ; } result = 0 ; /* ncol out of range */ n_col = -1 ; break ; } /* === Order the rows and columns of A (does not destroy A) ============= */ if (!symamd_l (n_col, A, p, perm, knobs, stats, &mxCalloc, &mxFree)) { /* return p = -1 if colamd failed */ plhs [0] = mxCreateDoubleMatrix (1, 1, mxREAL) ; out_perm = mxGetPr (plhs [0]) ; out_perm [0] = -1 ; mxFree (p) ; mxFree (A) ; if (spumoni > 0 || result) { symamd_l_report (stats) ; } if (result) { mexErrMsgTxt ("symamd should have returned TRUE\n") ; } return ; /* mexErrMsgTxt ("symamd error!") ; */ } if (!result) { symamd_l_report (stats) ; mexErrMsgTxt ("symamd should have returned FALSE\n") ; } if (full) { mxDestroyArray (Ainput) ; } /* === Return the permutation vector ==================================== */ plhs [0] = mxCreateDoubleMatrix (1, n_col, mxREAL) ; out_perm = mxGetPr (plhs [0]) ; for (i = 0 ; i < n_col ; i++) { /* symamd is 0-based, but MATLAB expects this to be 1-based */ out_perm [i] = perm [i] + 1 ; } mxFree (perm) ; /* === Return the stats vector ========================================== */ /* print stats if spumoni > 0 */ if (spumoni > 0) { symamd_l_report (stats) ; } if (nlhs == 2) { plhs [1] = mxCreateDoubleMatrix (1, COLAMD_STATS, mxREAL) ; out_stats = mxGetPr (plhs [1]) ; for (i = 0 ; i < COLAMD_STATS ; i++) { out_stats [i] = stats [i] ; } /* fix stats (5) and (6), for 1-based information on jumbled matrix. */ /* note that this correction doesn't occur if symamd returns FALSE */ out_stats [COLAMD_INFO1] ++ ; out_stats [COLAMD_INFO2] ++ ; } }
/* Compute the pseudoinverse of A and store it in A_plus A+ = VS+U* A m x n V m x m S n x n U m x n */ int pseudoinverse(gsl_matrix *A, gsl_matrix *A_plus) { int rc; double temp; int m = (int)(A->size1); int n = (int)(A->size2); gsl_vector *workspace = gsl_vector_alloc(n); gsl_matrix *V = gsl_matrix_alloc(n, n); gsl_matrix *S = gsl_matrix_alloc(n, n); gsl_matrix *U_times_S_plus_trans = gsl_matrix_alloc(m, n); gsl_vector *singular_values = gsl_vector_alloc(n); int i; double tolerance = 0; rc = gsl_linalg_SV_decomp(A, V, singular_values, workspace); // NOTE: this does a thin SVD // Now A = U dump_matrix(A, "U.dat"); dump_matrix(V, "V.dat"); dump_vector(singular_values, "S.dat"); if (rc) { // ERROR return rc; } // compute tolerace as MAX(SIZE(A)) * NORM(A) * EPS(class(A)) // singular values within tolerance of 0 are considered to be 0 tolerance = MAX(m,n) * gsl_vector_get(singular_values, 0) * DBL_EPSILON; //printf("tolerance = %g\n", tolerance); // compute S+ // by taking reciprocal of nonzero entries for (i = 0 ; i < n ; i++) { temp = gsl_vector_get(singular_values, i); if (temp < tolerance) { break; // singular values are non-negative and form a non-increasing sequence } gsl_matrix_set(S, i, i, 1 / temp); } // now S = S+* // compute US+* rc = gsl_blas_dgemm(CblasNoTrans, CblasNoTrans, 1.0, A, S, 0.0, U_times_S_plus_trans); // now A = US+* if (rc) { // ERROR return rc; } // compute VS+U rc = gsl_blas_dgemm(CblasNoTrans, CblasTrans, 1.0, V, U_times_S_plus_trans, 0.0, A_plus); // now A_plus = VS+U if (rc) { // ERROR return rc; } // cleanup gsl_vector_free(workspace); gsl_matrix_free(V); gsl_matrix_free(S); gsl_matrix_free(U_times_S_plus_trans); gsl_vector_free(singular_values); return 0; }
int main(int argc, char *argv[]) { int re = 0; int i, j, p, rtest, m, k; int nerrs, nsrcerrs; void *buf; unsigned int decode_index[MMAX]; unsigned char *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES]; unsigned char *encode_matrix, *decode_matrix, *invert_matrix, *g_tbls; unsigned char src_in_err[TEST_SOURCES], src_err_list[TEST_SOURCES]; unsigned char *recov[TEST_SOURCES]; int rows, align, size; unsigned char *efence_buffs[TEST_SOURCES]; unsigned int offset; u8 *ubuffs[TEST_SOURCES]; u8 *temp_ubuffs[TEST_SOURCES]; printf("erasure_code_test: %dx%d ", TEST_SOURCES, TEST_LEN); srand(TEST_SEED); // Allocate the arrays for (i = 0; i < TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } for (i = 0; i < TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } temp_buffs[i] = buf; } // Test erasure code by encode and recovery encode_matrix = malloc(MMAX * KMAX); decode_matrix = malloc(MMAX * KMAX); invert_matrix = malloc(MMAX * KMAX); g_tbls = malloc(KMAX * TEST_SOURCES * 32); if (encode_matrix == NULL || decode_matrix == NULL || invert_matrix == NULL || g_tbls == NULL) { printf("Test failure! Error with malloc\n"); return -1; } // Pick a first test m = 9; k = 5; if (m > MMAX || k > KMAX) return -1; // Make random data for (i = 0; i < k; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); // Generate encode matrix encode_matrix // The matrix generated by gf_gen_rs_matrix // is not always invertable. gf_gen_rs_matrix(encode_matrix, m, k); // Generate g_tbls from encode matrix encode_matrix ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix encode_matrix ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]); // Choose random buffers to be in erasure memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = buffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) { printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf(" - erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((u8 *) encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((u8 *) invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((u8 *) decode_matrix, m, k); printf("recov %d:", src_err_list[i]); dump(temp_buffs[k + i], 25); printf("orig :"); dump(buffs[src_err_list[i]], 25); return -1; } } // Pick a first test m = 9; k = 5; if (m > MMAX || k > KMAX) return -1; // Make random data for (i = 0; i < k; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); // The matrix generated by gf_gen_cauchy1_matrix // is always invertable. gf_gen_cauchy1_matrix(encode_matrix, m, k); // Generate g_tbls from encode matrix encode_matrix ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix encode_matrix ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]); // Choose random buffers to be in erasure memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = buffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) { printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf(" - erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((u8 *) encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((u8 *) invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((u8 *) decode_matrix, m, k); printf("recov %d:", src_err_list[i]); dump(temp_buffs[k + i], 25); printf("orig :"); dump(buffs[src_err_list[i]], 25); return -1; } } // Do more random tests for (rtest = 0; rtest < RANDOMS; rtest++) { while ((m = (rand() % MMAX)) < 2) ; while ((k = (rand() % KMAX)) >= m || k < 1) ; if (m > MMAX || k > KMAX) continue; // Make random data for (i = 0; i < k; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); // The matrix generated by gf_gen_cauchy1_matrix // is always invertable. gf_gen_cauchy1_matrix(encode_matrix, m, k); // Make parity vects // Generate g_tbls from encode matrix a ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix a ec_encode_data(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = buffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], TEST_LEN)) { printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((u8 *) encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((u8 *) invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((u8 *) decode_matrix, m, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]], 25); printf("recov %d:", src_err_list[i]); dump(temp_buffs[k + i], 25); return -1; } } putchar('.'); } // Run tests at end of buffer for Electric Fence k = 16; align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; if (k > KMAX) return -1; for (rows = 1; rows <= 16; rows++) { m = k + rows; if (m > MMAX) return -1; // Make random data for (i = 0; i < k; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (size = EFENCE_TEST_MIN_SIZE; size <= TEST_SIZE; size += align) { for (i = 0; i < m; i++) { // Line up TEST_SIZE from end efence_buffs[i] = buffs[i] + TEST_LEN - size; } // The matrix generated by gf_gen_cauchy1_matrix // is always invertable. gf_gen_cauchy1_matrix(encode_matrix, m, k); // Make parity vects // Generate g_tbls from encode matrix a ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix a ec_encode_data(size, k, m - k, g_tbls, efence_buffs, &efence_buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = efence_buffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_buffs[k + i], efence_buffs[src_err_list[i]], size)) { printf("Efence: Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf("size = %d\n", size); printf("Test erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((u8 *) encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((u8 *) invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((u8 *) decode_matrix, m, k); printf("recov %d:", src_err_list[i]); dump(temp_buffs[k + i], align); printf("orig :"); dump(efence_buffs[src_err_list[i]], align); return -1; } } } } // Test rand ptr alignment if available for (rtest = 0; rtest < RANDOMS; rtest++) { while ((m = (rand() % MMAX)) < 2) ; while ((k = (rand() % KMAX)) >= m || k < 1) ; if (m > MMAX || k > KMAX) continue; size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~15; offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B; // Add random offsets for (i = 0; i < m; i++) { memset(buffs[i], 0, TEST_LEN); // zero pad to check write-over memset(temp_buffs[i], 0, TEST_LEN); // zero pad to check write-over ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); temp_ubuffs[i] = temp_buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); } for (i = 0; i < k; i++) for (j = 0; j < size; j++) ubuffs[i][j] = rand(); // The matrix generated by gf_gen_cauchy1_matrix // is always invertable. gf_gen_cauchy1_matrix(encode_matrix, m, k); // Make parity vects // Generate g_tbls from encode matrix a ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix a ec_encode_data(size, k, m - k, g_tbls, ubuffs, &ubuffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = ubuffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_ubuffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_ubuffs[k + i], ubuffs[src_err_list[i]], size)) { printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((unsigned char *)encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((unsigned char *)invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((unsigned char *)decode_matrix, m, k); printf("orig data:\n"); dump_matrix(ubuffs, m, 25); printf("orig :"); dump(ubuffs[src_err_list[i]], 25); printf("recov %d:", src_err_list[i]); dump(temp_ubuffs[k + i], 25); return -1; } } // Confirm that padding around dests is unchanged memset(temp_buffs[0], 0, PTR_ALIGN_CHK_B); // Make reference zero buff for (i = 0; i < m; i++) { offset = ubuffs[i] - buffs[i]; if (memcmp(buffs[i], temp_buffs[0], offset)) { printf("Fail rand ualign encode pad start\n"); return -1; } if (memcmp (buffs[i] + offset + size, temp_buffs[0], PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign encode pad end\n"); return -1; } } for (i = 0; i < nerrs; i++) { offset = temp_ubuffs[k + i] - temp_buffs[k + i]; if (memcmp(temp_buffs[k + i], temp_buffs[0], offset)) { printf("Fail rand ualign decode pad start\n"); return -1; } if (memcmp (temp_buffs[k + i] + offset + size, temp_buffs[0], PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign decode pad end\n"); return -1; } } putchar('.'); } // Test size alignment align = (LEN_ALIGN_CHK_B != 0) ? 13 : 16; for (size = TEST_LEN; size > 0; size -= align) { while ((m = (rand() % MMAX)) < 2) ; while ((k = (rand() % KMAX)) >= m || k < 1) ; if (m > MMAX || k > KMAX) continue; for (i = 0; i < k; i++) for (j = 0; j < size; j++) buffs[i][j] = rand(); // The matrix generated by gf_gen_cauchy1_matrix // is always invertable. gf_gen_cauchy1_matrix(encode_matrix, m, k); // Make parity vects // Generate g_tbls from encode matrix a ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls); // Perform matrix dot_prod for EC encoding // using g_tbls from encode matrix a ec_encode_data(size, k, m - k, g_tbls, buffs, &buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); gen_err_list(src_err_list, src_in_err, &nerrs, &nsrcerrs, k, m); // Generate decode matrix re = gf_gen_decode_matrix(encode_matrix, decode_matrix, invert_matrix, decode_index, src_err_list, src_in_err, nerrs, nsrcerrs, k, m); if (re != 0) { printf("Fail to gf_gen_decode_matrix\n"); return -1; } // Pack recovery array as list of valid sources // Its order must be the same as the order // to generate matrix b in gf_gen_decode_matrix for (i = 0; i < k; i++) { recov[i] = buffs[decode_index[i]]; } // Recover data ec_init_tables(k, nerrs, decode_matrix, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]); for (i = 0; i < nerrs; i++) { if (0 != memcmp(temp_buffs[k + i], buffs[src_err_list[i]], size)) { printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (j = 0; j < nerrs; j++) printf(" %d", src_err_list[j]); printf(" - Index = "); for (p = 0; p < k; p++) printf(" %d", decode_index[p]); printf("\nencode_matrix:\n"); dump_u8xu8((unsigned char *)encode_matrix, m, k); printf("inv b:\n"); dump_u8xu8((unsigned char *)invert_matrix, k, k); printf("\ndecode_matrix:\n"); dump_u8xu8((unsigned char *)decode_matrix, m, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]], 25); printf("recov %d:", src_err_list[i]); dump(temp_buffs[k + i], 25); return -1; } } } printf("done EC tests: Pass\n"); return 0; }
int main(int argc, char *argv[]) { int i, j, rtest, m, k, nerrs, r, err; void *buf; u8 *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES]; u8 a[MMAX*KMAX], b[MMAX*KMAX], c[MMAX*KMAX], d[MMAX*KMAX]; u8 g_tbls[KMAX*TEST_SOURCES*32], src_in_err[TEST_SOURCES]; u8 src_err_list[TEST_SOURCES], *recov[TEST_SOURCES]; struct perf start, stop; m = 32; k = 28; printf("erasure_code_sse_perf: %dx%d ", m, (TEST_LEN(m))); // Allocate the arrays for(i=0; i<TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN(m))) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } for (i=0; i<TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN(m))) { printf("alloc error: Fail"); return -1; } temp_buffs[i] = buf; } // Test erasure code by encode and recovery // Pick a first test if (m > MMAX || k > KMAX) return -1; // Make random data for(i=0; i<k; i++) for(j=0; j<(TEST_LEN(m)); j++) buffs[i][j] = rand(); memset(src_in_err, 0, TEST_SOURCES); srand(1); for (i=0, nerrs=0; i<k && nerrs<m-k; i++) { err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0) { // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } printf("Test erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\n"); perf_start(&start); for (rtest = 0; rtest < TEST_LOOPS(m); rtest++) { gf_gen_rs_matrix(a, m, k); // Make parity vects ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse((TEST_LEN(m)), k, m-k, g_tbls, buffs, &buffs[k]); } perf_stop(&stop); printf("erasure_code_sse_encode" TEST_TYPE_STR ": "); perf_print(stop,start, (long long)(TEST_LEN(m))*(m)*rtest); perf_start(&start); for (rtest = 0; rtest < TEST_LOOPS(m); rtest++) { // Construct b by removing error rows for(i=0, r=0; i<k; i++, r++) { while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix(b, d, k) < 0) { printf("BAD MATRIX\n"); return -1; } for(i=0, r=0; i<k; i++, r++) { while (src_in_err[r]) r++; recov[i] = buffs[r]; } for(i=0; i<nerrs; i++) { for(j=0; j<k; j++) { c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data_sse((TEST_LEN(m)), k, nerrs, g_tbls, recov, &temp_buffs[k]); } perf_stop(&stop); for(i=0; i<nerrs; i++) { if (0 != memcmp(temp_buffs[k+i], buffs[src_err_list[i]], (TEST_LEN(m)))) { printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (j=0; j<nerrs; j++) printf(" %d", src_err_list[j]); printf("\na:\n"); dump_u8xu8((u8*)a, m, k); printf("inv b:\n"); dump_u8xu8((u8*)d, k, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]],25); printf("recov %d:",src_err_list[i]); dump(temp_buffs[k+i], 25); return -1; } } printf("erasure_code_sse_decode" TEST_TYPE_STR ": "); perf_print(stop,start, (long long)(TEST_LEN(m))*(k+nerrs)*rtest); printf("done all: Pass\n"); return 0; }
int main(int argc, char *argv[]) { int i, j, rtest, srcs; void *buf; u8 gf[6][TEST_SOURCES]; u8 *g_tbls; u8 *dest_ref[VECT]; u8 *dest_ptrs[VECT], *buffs[TEST_SOURCES]; int vector = VECT; int align, size; unsigned char *efence_buffs[TEST_SOURCES]; unsigned int offset; u8 *ubuffs[TEST_SOURCES]; u8 *udest_ptrs[VECT]; printf("test" xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN); // Allocate the arrays for (i = 0; i < TEST_SOURCES; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } if (posix_memalign(&buf, 16, 2 * (vector * TEST_SOURCES * 32))) { printf("alloc error: Fail"); return -1; } g_tbls = buf; for (i = 0; i < vector; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ptrs[i] = buf; memset(dest_ptrs[i], 0, TEST_LEN); } for (i = 0; i < vector; i++) { if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } dest_ref[i] = buf; memset(dest_ref[i], 0, TEST_LEN); } // Test of all zeros for (i = 0; i < TEST_SOURCES; i++) memset(buffs[i], 0, TEST_LEN); switch (vector) { case 6: memset(gf[5], 0xe6, TEST_SOURCES); case 5: memset(gf[4], 4, TEST_SOURCES); case 4: memset(gf[3], 9, TEST_SOURCES); case 3: memset(gf[2], 7, TEST_SOURCES); case 2: memset(gf[1], 1, TEST_SOURCES); case 1: memset(gf[0], 2, TEST_SOURCES); break; default: return -1; } for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < vector; i++) for (j = 0; j < TEST_SOURCES; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * TEST_SOURCES) + j * 32]); } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[i * 32 * TEST_SOURCES], buffs, dest_ref[i]); for (i = 0; i < vector; i++) memset(dest_ptrs[i], 0, TEST_LEN); for (i = 0; i < TEST_SOURCES; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, i, g_tbls, buffs[i], *dest_ptrs); #else FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, i, g_tbls, buffs[i], dest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], TEST_LEN)) { printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test%d\n", i); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(dest_ptrs[i], 25); return -1; } } #if (VECT == 1) REF_FUNCTION(TEST_LEN, TEST_SOURCES, g_tbls, buffs, *dest_ref); #else REF_FUNCTION(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ref); #endif for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], TEST_LEN)) { printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test%d\n", i); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(dest_ptrs[i], 25); return -1; } } putchar('.'); // Rand data test for (rtest = 0; rtest < RANDOMS; rtest++) { for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < vector; i++) for (j = 0; j < TEST_SOURCES; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * TEST_SOURCES) + j * 32]); } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[i * 32 * TEST_SOURCES], buffs, dest_ref[i]); for (i = 0; i < vector; i++) memset(dest_ptrs[i], 0, TEST_LEN); for (i = 0; i < TEST_SOURCES; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, i, g_tbls, buffs[i], *dest_ptrs); #else FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, i, g_tbls, buffs[i], dest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test%d %d\n", i, rtest); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(dest_ptrs[i], 25); return -1; } } putchar('.'); } // Rand data test with varied parameters for (rtest = 0; rtest < RANDOMS; rtest++) { for (srcs = TEST_SOURCES; srcs > 0; srcs--) { for (i = 0; i < srcs; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < vector; i++) for (j = 0; j < srcs; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * srcs) + j * 32]); } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[i * 32 * srcs], buffs, dest_ref[i]); for (i = 0; i < vector; i++) memset(dest_ptrs[i], 0, TEST_LEN); for (i = 0; i < srcs; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(TEST_LEN, srcs, i, g_tbls, buffs[i], *dest_ptrs); #else FUNCTION_UNDER_TEST(TEST_LEN, srcs, i, g_tbls, buffs[i], dest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], TEST_LEN)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test%d srcs=%d\n", i, srcs); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(dest_ptrs[i], 25); return -1; } } putchar('.'); } } // Run tests at end of buffer for Electric Fence align = (LEN_ALIGN_CHK_B != 0) ? 1 : ALIGN_SIZE; for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) { for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < TEST_LEN; j++) buffs[i][j] = rand(); for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end efence_buffs[i] = buffs[i] + TEST_LEN - size; for (i = 0; i < vector; i++) for (j = 0; j < TEST_SOURCES; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * TEST_SOURCES) + j * 32]); } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[i * 32 * TEST_SOURCES], efence_buffs, dest_ref[i]); for (i = 0; i < vector; i++) memset(dest_ptrs[i], 0, size); for (i = 0; i < TEST_SOURCES; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(size, TEST_SOURCES, i, g_tbls, efence_buffs[i], *dest_ptrs); #else FUNCTION_UNDER_TEST(size, TEST_SOURCES, i, g_tbls, efence_buffs[i], dest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test%d size=%d\n", i, size); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], TEST_MIN_SIZE + align); printf("dprod_dut:"); dump(dest_ptrs[i], TEST_MIN_SIZE + align); return -1; } } putchar('.'); } // Test rand ptr alignment if available for (rtest = 0; rtest < RANDOMS; rtest++) { size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1); srcs = rand() % TEST_SOURCES; if (srcs == 0) continue; offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B; // Add random offsets for (i = 0; i < srcs; i++) ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); for (i = 0; i < vector; i++) { udest_ptrs[i] = dest_ptrs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); memset(dest_ptrs[i], 0, TEST_LEN); // zero pad to check write-over } for (i = 0; i < srcs; i++) for (j = 0; j < size; j++) ubuffs[i][j] = rand(); for (i = 0; i < vector; i++) for (j = 0; j < srcs; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * srcs) + j * 32]); } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(size, srcs, &g_tbls[i * 32 * srcs], ubuffs, dest_ref[i]); for (i = 0; i < srcs; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(size, srcs, i, g_tbls, ubuffs[i], *udest_ptrs); #else FUNCTION_UNDER_TEST(size, srcs, i, g_tbls, ubuffs[i], udest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], udest_ptrs[i], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test%d ualign srcs=%d\n", i, srcs); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(udest_ptrs[i], 25); return -1; } } // Confirm that padding around dests is unchanged memset(dest_ref[0], 0, PTR_ALIGN_CHK_B); // Make reference zero buff for (i = 0; i < vector; i++) { offset = udest_ptrs[i] - dest_ptrs[i]; if (memcmp(dest_ptrs[i], dest_ref[0], offset)) { printf("Fail rand ualign pad1 start\n"); return -1; } if (memcmp (dest_ptrs[i] + offset + size, dest_ref[0], PTR_ALIGN_CHK_B - offset)) { printf("Fail rand ualign pad1 end\n"); return -1; } } putchar('.'); } // Test all size alignment align = (LEN_ALIGN_CHK_B != 0) ? 1 : ALIGN_SIZE; for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) { for (i = 0; i < TEST_SOURCES; i++) for (j = 0; j < size; j++) buffs[i][j] = rand(); for (i = 0; i < vector; i++) { for (j = 0; j < TEST_SOURCES; j++) { gf[i][j] = rand(); gf_vect_mul_init(gf[i][j], &g_tbls[i * (32 * TEST_SOURCES) + j * 32]); } memset(dest_ptrs[i], 0, TEST_LEN); // zero pad to check write-over } for (i = 0; i < vector; i++) gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[i * 32 * TEST_SOURCES], buffs, dest_ref[i]); for (i = 0; i < TEST_SOURCES; i++) { #if (VECT == 1) FUNCTION_UNDER_TEST(size, TEST_SOURCES, i, g_tbls, buffs[i], *dest_ptrs); #else FUNCTION_UNDER_TEST(size, TEST_SOURCES, i, g_tbls, buffs[i], dest_ptrs); #endif } for (i = 0; i < vector; i++) { if (0 != memcmp(dest_ref[i], dest_ptrs[i], size)) { printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test%d ualign len=%d\n", i, size); dump_matrix(buffs, vector, TEST_SOURCES); printf("dprod_base:"); dump(dest_ref[i], 25); printf("dprod_dut:"); dump(dest_ptrs[i], 25); return -1; } } putchar('.'); } printf("Pass\n"); return 0; }
int matrix_invert(FILE *fp, int n, double **a) { int i, j, m, lda, *ipiv, lwork, info; double **test = NULL, **id, *work; #ifdef DEBUG_MATRIX if (fp) { fprintf(fp, "Inverting %d square matrix\n", n); test = alloc_matrix(n, n); for (i = 0; (i < n); i++) { for (j = 0; (j < n); j++) { test[i][j] = a[i][j]; } } dump_matrix(fp, "before inversion", n, a); } #endif snew(ipiv, n); lwork = n*n; snew(work, lwork); m = lda = n; info = 0; F77_FUNC(dgetrf, DGETRF) (&n, &m, a[0], &lda, ipiv, &info); #ifdef DEBUG_MATRIX if (fp) { dump_matrix(fp, "after dgetrf", n, a); } #endif if (info != 0) { return info; } F77_FUNC(dgetri, DGETRI) (&n, a[0], &lda, ipiv, work, &lwork, &info); #ifdef DEBUG_MATRIX if (fp) { dump_matrix(fp, "after dgetri", n, a); } #endif if (info != 0) { return info; } #ifdef DEBUG_MATRIX if (fp) { id = alloc_matrix(n, n); matrix_multiply(fp, n, n, test, a, id); dump_matrix(fp, "And here is the product of A and Ainv", n, id); free_matrix(id); free_matrix(test); } #endif sfree(ipiv); sfree(work); return 0; }
int main(int argc, char *argv[]) { int i, j, rtest, m, k, nerrs, r, err; void *buf; unsigned char *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES], *a, *b, *c, *d, *g_tbls; unsigned char src_in_err[TEST_SOURCES], src_err_list[TEST_SOURCES]; unsigned char *recov[TEST_SOURCES]; int rows, align, size; unsigned char *efence_buffs[TEST_SOURCES]; unsigned int offset; u8 *ubuffs[TEST_SOURCES]; u8 *temp_ubuffs[TEST_SOURCES]; printf("erasure_code_sse_test: %dx%d ", TEST_SOURCES, TEST_LEN); // Allocate the arrays for(i=0; i<TEST_SOURCES; i++){ if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } buffs[i] = buf; } for(i=0; i<TEST_SOURCES; i++){ if (posix_memalign(&buf, 64, TEST_LEN)) { printf("alloc error: Fail"); return -1; } temp_buffs[i] = buf; } // Test erasure code by encode and recovery a = malloc(MMAX*KMAX); b = malloc(MMAX*KMAX); c = malloc(MMAX*KMAX); d = malloc(MMAX*KMAX); g_tbls = malloc(KMAX*TEST_SOURCES*32); if (a == NULL || b == NULL || c == NULL || d == NULL || g_tbls == NULL) { printf("Test failure! Error with malloc\n"); return -1; } // Pick a first test m = 9; k = 5; if (m > MMAX || k > KMAX) return -1; // Make random data for(i=0; i<k; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); gf_gen_rs_matrix(a, m, k); ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse(TEST_LEN, k, m-k, g_tbls, buffs, &buffs[k]); // Choose random buffers to be in erasure memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } // Construct matrix b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } // Generate decode matrix d as matrix inverse of b if (gf_invert_matrix(b, d, k) < 0){ printf("BAD MATRIX\n"); return -1; } // Pack recovery array as list of valid sources for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; recov[i] = buffs[r]; } for(i=0; i<nerrs; i++){ for(j=0; j<k; j++){ c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]); for(i=0; i<nerrs; i++){ if (0 != memcmp(temp_buffs[k+i], buffs[src_err_list[i]], TEST_LEN)){ printf("Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf("recov %d:",src_err_list[i]); dump(temp_buffs[k+i], 25); printf("orig :"); dump(buffs[src_err_list[i]],25); return -1; } } // Do more random tests for (rtest = 0; rtest < RANDOMS; rtest++){ while ((m = (rand() % MMAX)) < 2); while ((k = (rand() % KMAX)) >= m || k < 1); if (m>MMAX || k>KMAX) continue; // Make random data for(i=0; i<k; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); gf_gen_rs_matrix(a, m, k); // Make parity vects ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse(TEST_LEN, k, m-k, g_tbls, buffs, &buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0){ // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } // Construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix(b, d, k) < 0){ printf("BAD MATRIX\n"); return -1; } for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; recov[i] = buffs[r]; } for(i=0; i<nerrs; i++){ for(j=0; j<k; j++){ c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]); for(i=0; i<nerrs; i++){ if (0 != memcmp(temp_buffs[k+i], buffs[src_err_list[i]], TEST_LEN)){ printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\na:\n"); dump_u8xu8((unsigned char*)a, m, k); printf("inv b:\n"); dump_u8xu8((unsigned char*)d, k, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]],25); printf("recov %d:",src_err_list[i]); dump(temp_buffs[k+i], 25); return -1; } } putchar('.'); } // Run tests at end of buffer for Electric Fence k = 16; align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16; if (k > KMAX) return -1; for(rows=1; rows<=16; rows++){ m = k+rows; if (m > MMAX) return -1; // Make random data for(i=0; i<k; i++) for(j=0; j<TEST_LEN; j++) buffs[i][j] = rand(); for(size=EFENCE_TEST_MIN_SIZE; size<=TEST_SIZE; size+=align){ for(i=0; i<m; i++) // Line up TEST_SIZE from end efence_buffs[i] = buffs[i] + TEST_LEN - size; gf_gen_rs_matrix(a, m, k); ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse(size, k, m-k, g_tbls, efence_buffs, &efence_buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0){ // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } // Construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } // Generate decode matrix d as matrix inverse of b if (gf_invert_matrix(b, d, k) < 0){ printf("BAD MATRIX\n"); return -1; } // Pack recovery array as list of valid sources for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; recov[i] = efence_buffs[r]; } for(i=0; i<nerrs; i++){ for(j=0; j<k; j++){ c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]); for(i=0; i<nerrs; i++){ if (0 != memcmp(temp_buffs[k+i], efence_buffs[src_err_list[i]], size)){ printf("Efence: Fail error recovery (%d, %d, %d)\n", m, k, nerrs); printf("Test erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\n"); printf("recov %d:",src_err_list[i]); dump(temp_buffs[k+i], align); printf("orig :"); dump(efence_buffs[src_err_list[i]],align); return -1; } } } } // Test rand ptr alignment if available for(rtest=0; rtest<RANDOMS; rtest++){ while ((m = (rand() % MMAX)) < 2); while ((k = (rand() % KMAX)) >= m || k < 1); if (m>MMAX || k>KMAX) continue; size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~15; offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B; // Add random offsets for(i=0; i<m; i++) { memset(buffs[i], 0, TEST_LEN); // zero pad to check write-over memset(temp_buffs[i], 0, TEST_LEN); // zero pad to check write-over ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); temp_ubuffs[i] = temp_buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset)); } for(i=0; i<k; i++) for(j=0; j<size; j++) ubuffs[i][j] = rand(); gf_gen_rs_matrix(a, m, k); // Make parity vects ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse(size, k, m-k, g_tbls, ubuffs, &ubuffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0){ // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } // Construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix(b, d, k) < 0){ printf("BAD MATRIX\n"); return -1; } for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; recov[i] = ubuffs[r]; } for(i=0; i<nerrs; i++){ for(j=0; j<k; j++){ c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_ubuffs[k]); for(i=0; i<nerrs; i++){ if (0 != memcmp(temp_ubuffs[k+i], ubuffs[src_err_list[i]], size)){ printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\na:\n"); dump_u8xu8((unsigned char*)a, m, k); printf("inv b:\n"); dump_u8xu8((unsigned char*)d, k, k); printf("orig data:\n"); dump_matrix(ubuffs, m, 25); printf("orig :"); dump(ubuffs[src_err_list[i]],25); printf("recov %d:",src_err_list[i]); dump(temp_ubuffs[k+i], 25); return -1; } } // Confirm that padding around dests is unchanged memset(temp_buffs[0], 0, PTR_ALIGN_CHK_B); // Make reference zero buff for(i=0; i<m; i++){ offset = ubuffs[i] - buffs[i]; if (memcmp(buffs[i], temp_buffs[0], offset)){ printf("Fail rand ualign encode pad start\n"); return -1; } if (memcmp(buffs[i] + offset + size, temp_buffs[0], PTR_ALIGN_CHK_B - offset)){ printf("Fail rand ualign encode pad end\n"); return -1; } } for(i=0; i<nerrs; i++){ offset = temp_ubuffs[k+i] - temp_buffs[k+i]; if (memcmp(temp_buffs[k+i], temp_buffs[0], offset)){ printf("Fail rand ualign decode pad start\n"); return -1; } if (memcmp(temp_buffs[k+i] + offset + size, temp_buffs[0], PTR_ALIGN_CHK_B - offset)){ printf("Fail rand ualign decode pad end\n"); return -1; } } putchar('.'); } // Test size alignment align = (LEN_ALIGN_CHK_B != 0) ? 13 : 16; for(size=TEST_LEN; size>0; size-=align){ while ((m = (rand() % MMAX)) < 2); while ((k = (rand() % KMAX)) >= m || k < 1); if (m>MMAX || k>KMAX) continue; for(i=0; i<k; i++) for(j=0; j<size; j++) buffs[i][j] = rand(); gf_gen_rs_matrix(a, m, k); // Make parity vects ec_init_tables(k, m-k, &a[k*k], g_tbls); ec_encode_data_sse(size, k, m-k, g_tbls, buffs, &buffs[k]); // Random errors memset(src_in_err, 0, TEST_SOURCES); for (i=0, nerrs=0; i<k && nerrs<m-k; i++){ err = 1 & rand(); src_in_err[i] = err; if (err) src_err_list[nerrs++] = i; } if (nerrs == 0){ // should have at least one error while ((err = (rand() % KMAX)) >= k) ; src_err_list[nerrs++] = err; src_in_err[err] = 1; } // Construct b by removing error rows for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; for(j=0; j<k; j++) b[k*i+j] = a[k*r+j]; } if (gf_invert_matrix(b, d, k) < 0){ printf("BAD MATRIX\n"); return -1; } for(i=0, r=0; i<k; i++, r++){ while (src_in_err[r]) r++; recov[i] = buffs[r]; } for(i=0; i<nerrs; i++){ for(j=0; j<k; j++){ c[k*i+j]=d[k*src_err_list[i]+j]; } } // Recover data ec_init_tables(k, nerrs, c, g_tbls); ec_encode_data(size, k, nerrs, g_tbls, recov, &temp_buffs[k]); for(i=0; i<nerrs; i++){ if (0 != memcmp(temp_buffs[k+i], buffs[src_err_list[i]], size)){ printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs); printf(" - erase list = "); for (i=0; i<nerrs; i++) printf(" %d", src_err_list[i]); printf("\na:\n"); dump_u8xu8((unsigned char*)a, m, k); printf("inv b:\n"); dump_u8xu8((unsigned char*)d, k, k); printf("orig data:\n"); dump_matrix(buffs, m, 25); printf("orig :"); dump(buffs[src_err_list[i]],25); printf("recov %d:",src_err_list[i]); dump(temp_buffs[k+i], 25); return -1; } } } printf("done EC tests: Pass\n"); return 0; }