diff --git a/Makefile.am b/Makefile.am
index 336ec460..4cb80bd2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,8 @@ snapraid_SOURCES = \
raid/intz.c \
raid/x86z.c \
raid/sort.c \
+ raid/memory.c \
+ raid/test.c \
snapraid.c \
tommy.c \
util.c \
@@ -43,6 +45,9 @@ noinst_HEADERS = \
raid/internal.h \
raid/cpu.h \
raid/gf.h \
+ raid/combo.h \
+ raid/memory.h \
+ raid/test.h \
portable.h \
snapraid.h \
util.h \
@@ -69,7 +74,6 @@ noinst_HEADERS = \
tommyhashdyn.c \
tommylist.c \
fnmatch.h \
- combo.h \
import.h \
mingw.h \
unix.h
diff --git a/check.c b/check.c
index 245a8dc5..cea1be3e 100644
--- a/check.c
+++ b/check.c
@@ -24,7 +24,7 @@
#include "parity.h"
#include "handle.h"
#include "raid/raid.h"
-#include "combo.h"
+#include "raid/combo.h"
/****************************************************************************/
/* check */
diff --git a/combo.h b/combo.h
deleted file mode 100644
index 847daab6..00000000
--- a/combo.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2013 Andrea Mazzoleni
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef __COMBO_H
-#define __COMBO_H
-
-#include
-
-/**
- * Get the first combination of r of n elements.
- *
- * Typical use is with combination_next() in the form :
- *
- * int i[R];
- * combination_first(R, N, i);
- * do {
- * code using i[0], i[1], ..., i[R-1]
- * } while (combination_next(R, N, i));
- *
- * It's equivalent at the code :
- *
- * for(i[0]=0;i[0]= h) {
-
- /* if we are at the first level, we have finished */
- if (i == 0)
- return 0;
-
- /* increase the previous position */
- --i;
- --h;
- goto recurse;
- }
-
- ++i;
-
- /* initialize all the next positions, if any */
- while (i < r) {
- c[i] = c[i-1] + 1; /* each position start at the next value of the previous one */
- ++i;
- }
-
- return 1;
-}
-#endif
diff --git a/raid/combo.h b/raid/combo.h
new file mode 100644
index 00000000..566e191b
--- /dev/null
+++ b/raid/combo.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2013 Andrea Mazzoleni
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __COMBO_H
+#define __COMBO_H
+
+#include
+
+/**
+ * Get the first permutation with repetition of r of n elements.
+ *
+ * Typical use is with permutation_next() in the form :
+ *
+ * int i[R];
+ * permutation_first(R, N, i);
+ * do {
+ * code using i[0], i[1], ..., i[R-1]
+ * } while (permutation_next(R, N, i));
+ *
+ * It's equivalent at the code :
+ *
+ * for(i[0]=0;i[0]= n) {
+
+ /* if we are at the first level, we have finished */
+ if (i == 0)
+ return 0;
+
+ /* increase the previous position */
+ --i;
+ goto recurse;
+ }
+
+ ++i;
+
+ /* initialize all the next positions, if any */
+ while (i < r) {
+ c[i] = 0;
+ ++i;
+ }
+
+ return 1;
+}
+
+/**
+ * Get the first combination without repetition of r of n elements.
+ *
+ * Typical use is with combination_next() in the form :
+ *
+ * int i[R];
+ * combination_first(R, N, i);
+ * do {
+ * code using i[0], i[1], ..., i[R-1]
+ * } while (combination_next(R, N, i));
+ *
+ * It's equivalent at the code :
+ *
+ * for(i[0]=0;i[0]= h) {
+
+ /* if we are at the first level, we have finished */
+ if (i == 0)
+ return 0;
+
+ /* increase the previous position */
+ --i;
+ --h;
+ goto recurse;
+ }
+
+ ++i;
+
+ /* initialize all the next positions, if any */
+ while (i < r) {
+ /* each position start at the next value of the previous one */
+ c[i] = c[i-1] + 1;
+ ++i;
+ }
+
+ return 1;
+}
+#endif
+
diff --git a/raid/gf.h b/raid/gf.h
index 7d165ad1..818b9d13 100644
--- a/raid/gf.h
+++ b/raid/gf.h
@@ -24,12 +24,6 @@
* Basic range checks are implemented using BUG_ON().
*/
-/*
- * Generic assert() with inverted meaning.
- */
-#define BUG_ON(a) assert(!(a))
-
-
/*
* GF a*b.
*/
diff --git a/raid/int.c b/raid/int.c
index d15622a5..ab0aa904 100644
--- a/raid/int.c
+++ b/raid/int.c
@@ -402,7 +402,7 @@ void raid_rec1_int8(int nr, const int *id, const int *ip, int nd, size_t size, v
(void)nr; /* unused, it's always 1 */
- /* if it's RAID5 uses the dedicated and faster function */
+ /* if it's RAID5 uses the faster function */
if (ip[0] == 0) {
raid_rec1_par1(id, nd, size, vv);
return;
@@ -459,7 +459,7 @@ void raid_rec2_int8(int nr, const int *id, const int *ip, int nd, size_t size, v
(void)nr; /* unused, it's always 2 */
- /* if it's RAID6 recovering with P and Q uses the dedicated and faster function */
+ /* if it's RAID6 recovering with P and Q uses the faster function */
if (ip[0] == 0 && ip[1] == 1) {
raid_rec2_par2(id, ip, nd, size, vv);
return;
diff --git a/raid/internal.h b/raid/internal.h
index b86e5064..864f6e95 100644
--- a/raid/internal.h
+++ b/raid/internal.h
@@ -18,8 +18,15 @@
#ifndef __RAID_INTERNAL_H
#define __RAID_INTERNAL_H
+/*
+ * Includes anything required for compatibility.
+ */
#include "../portable.h"
+#define BUG_ON(a) assert(!(a))
+/*
+ * Include the main header.
+ */
#include "raid.h"
/*
diff --git a/raid/memory.c b/raid/memory.c
new file mode 100644
index 00000000..e65add7b
--- /dev/null
+++ b/raid/memory.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 Andrea Mazzoleni
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "internal.h"
+#include "memory.h"
+
+void *raid_malloc_align(size_t size, void **freeptr)
+{
+ unsigned char *ptr;
+ uintptr_t offset;
+
+ ptr = malloc(size + RAID_MALLOC_ALIGN);
+ if (!ptr)
+ return 0;
+
+ *freeptr = ptr;
+
+ offset = ((uintptr_t)ptr) % RAID_MALLOC_ALIGN;
+
+ if (offset != 0)
+ ptr += RAID_MALLOC_ALIGN - offset;
+
+ return ptr;
+}
+
+void **raid_malloc_vector(size_t reverse, size_t count, size_t size, void **freeptr)
+{
+ void **v;
+ unsigned char *va;
+ size_t i;
+
+ assert(reverse <= count);
+
+ v = malloc(count * sizeof(void *));
+ if (!v)
+ return 0;
+
+ va = raid_malloc_align(count * (size + RAID_MALLOC_DISPLACEMENT), freeptr);
+ if (!va) {
+ free(v);
+ return 0;
+ }
+
+ for (i = 0; i < count; ++i)
+ v[i] = va + i * (size + RAID_MALLOC_DISPLACEMENT);
+
+ /* reverse order for the initial ones */
+ for (i = 0; i < reverse/2; ++i) {
+ void *ptr = v[i];
+ v[i] = v[reverse - 1 - i];
+ v[reverse - 1 - i] = ptr;
+ }
+
+ return v;
+}
+
+int raid_mtest_vector(void **vv, size_t count, size_t size)
+{
+ unsigned char **v = (unsigned char **)vv;
+ size_t i;
+ size_t j;
+ unsigned k;
+ unsigned char d;
+ unsigned char p;
+
+ /* fill with 0 */
+ d = 0;
+ for (i = 0; i < count; ++i)
+ for (j = 0; j < size; ++j)
+ v[i][j] = d;
+
+ /* test with all the byte patterns */
+ for (k = 1; k < 256; ++k) {
+ p = d;
+ d = k;
+
+ /* forward fill */
+ for (i = 0; i < count; ++i) {
+ for (j = 0; j < size; ++j) {
+ if (v[i][j] != p)
+ return -1;
+ v[i][j] = d;
+ }
+ }
+
+ p = d;
+ d = ~p;
+ /* backward fill with complement */
+ for (i = 0; i < count; ++i) {
+ for (j = size; j > 0; --j) {
+ if (v[i][j-1] != p)
+ return -1;
+ v[i][j-1] = d;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void raid_mrand_vector(void **vv, size_t count, size_t size)
+{
+ unsigned char **v = (unsigned char **)vv;
+ size_t i;
+ size_t j;
+
+ for (i = 0; i < count; ++i)
+ for (j = 0; j < size; ++j)
+ v[i][j] = rand();
+}
+
diff --git a/raid/memory.h b/raid/memory.h
new file mode 100644
index 00000000..8f44548e
--- /dev/null
+++ b/raid/memory.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 Andrea Mazzoleni
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __RAID_MEMORY_H
+#define __RAID_MEMORY_H
+
+/**
+ * Memory alignment provided by raid_malloc_align().
+ *
+ * It should guarantee good cache performance everywhere.
+ */
+#define RAID_MALLOC_ALIGN 256
+
+/**
+ * Memory displacement to avoid cache collisions on contiguous blocks,
+ * ued by raid_malloc_vector().
+ *
+ * When allocating a sequence of blocks with a size of power of 2,
+ * there is the risk that the start of each block is mapped into the same
+ * cache line, resulting in cache collisions if you access all the blocks
+ * in parallel, from the start to the end.
+ *
+ * The selected value was choosen empirically with some speed tests
+ * with 8/12/16/20/24 data buffers and 3 parity buffers
+ * for RAID-5/6/TP computation.
+ *
+ * With displacement (8 buffers, icore5, 32 bit):
+ *
+ * PAR1 sse2x4 21936 [MB/s]
+ * PAR2 sse2x2 11902 [MB/s]
+ * PARz sse2x1 5838 [MB/s]
+ *
+ * Without displacement:
+ *
+ * PAR1 sse2x4 15368 [MB/s]
+ * PAR2 sse2x2 6814 [MB/s]
+ * PARz sse2x1 3033 [MB/s]
+ */
+#define RAID_MALLOC_DISPLACEMENT (7*256)
+
+/**
+ * Aligned malloc.
+ */
+void *raid_malloc_align(size_t size, void **freeptr);
+
+/**
+ * Aligned vector allocation.
+ * Returns a vector of "count" pointers, each one pointing to a block of the
+ * specified "size".
+ * The first "reverse" pointers are put in reverse memory offset order.
+ */
+void **raid_malloc_vector(size_t reverse, size_t count, size_t size, void **freeptr);
+
+/**
+ * Tests the memory vector for RAM problems.
+ * If a problem is found, it crashes.
+ */
+int raid_mtest_vector(void **vv, size_t count, size_t size);
+
+/**
+ * Fills the memory vector with random data.
+ */
+void raid_mrand_vector(void **vv, size_t count, size_t size);
+
+#endif
+
diff --git a/raid/raid.h b/raid/raid.h
index 406f20be..1600fb26 100644
--- a/raid/raid.h
+++ b/raid/raid.h
@@ -44,7 +44,6 @@
/**
* Maximum number of data disks.
- * Limit of the parity generator matrix used.
*/
#define RAID_DATA_MAX 251
diff --git a/raid/test.c b/raid/test.c
new file mode 100644
index 00000000..4eb65207
--- /dev/null
+++ b/raid/test.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2013 Andrea Mazzoleni
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "internal.h"
+#include "cpu.h"
+#include "combo.h"
+#include "memory.h"
+
+/**
+ * Binomial coefficient of n over r.
+ */
+static int ibc(int n, int r)
+{
+ if (r == 0 || n == r)
+ return 1;
+ else
+ return ibc(n - 1, r - 1) + ibc(n - 1, r);
+}
+
+/**
+ * Power n ^ r;
+ */
+static int ipow(int n, int r)
+{
+ int v = 1;
+ while (r) {
+ v *= n;
+ --r;
+ }
+ return v;
+}
+
+int raid_test_combo(void)
+{
+ int r;
+ int count;
+ int p[RAID_PARITY_MAX];
+
+ for (r = 1; r <= RAID_PARITY_MAX; ++r) {
+ /* count combination (r of RAID_PARITY_MAX) elements */
+ count = 0;
+ combination_first(r, RAID_PARITY_MAX, p);
+
+ do {
+ ++count;
+ } while (combination_next(r, RAID_PARITY_MAX, p));
+
+ if (count != ibc(RAID_PARITY_MAX, r))
+ return -1;
+ }
+
+ for (r = 1; r <= RAID_PARITY_MAX; ++r) {
+ /* count permutation (r of RAID_PARITY_MAX) elements */
+ count = 0;
+ permutation_first(r, RAID_PARITY_MAX, p);
+
+ do {
+ ++count;
+ } while (permutation_next(r, RAID_PARITY_MAX, p));
+
+ if (count != ipow(RAID_PARITY_MAX, r))
+ return -1;
+ }
+
+ return 0;
+}
+
+int raid_test_sort(void)
+{
+ int p[RAID_PARITY_MAX];
+ int r;
+
+ for (r = 1; r <= RAID_PARITY_MAX; ++r) {
+ permutation_first(r, RAID_PARITY_MAX, p);
+ do {
+ int i[RAID_PARITY_MAX];
+ int j;
+
+ /* make a copy */
+ for (j = 0; j < r; ++j)
+ i[j] = p[j];
+
+ raid_sort(r, i);
+
+ /* check order */
+ for (j = 1; j < r; ++j)
+ if (i[j-1] > i[j])
+ return -1;
+ } while (permutation_next(r, RAID_PARITY_MAX, p));
+ }
+
+ return 0;
+}
+
+int raid_test_rec(int mode, int nd, size_t size)
+{
+ void *buffer_alloc;
+ void **buffer;
+ void **data;
+ void **parity;
+ void **test;
+ void *data_save[RAID_PARITY_MAX];
+ void *parity_save[RAID_PARITY_MAX];
+ void *zero;
+ void *waste;
+ int buffermax;
+ int id[RAID_PARITY_MAX];
+ int ip[RAID_PARITY_MAX];
+ int i;
+ int j;
+ int nr;
+ void (*map[RAID_PARITY_MAX][4])(int nr, const int *id, const int *ip, int nd, size_t size, void **vbuf);
+ int mac[RAID_PARITY_MAX];
+ int np;
+
+ raid_mode(mode);
+ if (mode == RAID_MODE_CAUCHY)
+ np = RAID_PARITY_MAX;
+ else
+ np = 3;
+
+ buffermax = nd + np * 2 + 2;
+
+ buffer = raid_malloc_vector(nd, buffermax, size, &buffer_alloc);
+ if (!buffer)
+ return -1;
+
+ data = buffer;
+ parity = buffer + nd;
+ test = buffer + nd + np;
+
+ for (i = 0; i < np; ++i)
+ parity_save[i] = parity[i];
+
+ zero = buffer[buffermax-2];
+ memset(zero, 0, size);
+ raid_zero(zero);
+
+ waste = buffer[buffermax-1];
+
+ /* fill data disk with random */
+ raid_mrand_vector(buffer, nd, size);
+
+ /* setup recov functions */
+ for (i = 0; i < np; ++i) {
+ mac[i] = 0;
+ if (i == 0) {
+ map[i][mac[i]++] = raid_rec1_int8;
+#if defined(__i386__) || defined(__x86_64__)
+ if (raid_cpu_has_ssse3())
+ map[i][mac[i]++] = raid_rec1_ssse3;
+#endif
+ } else if (i == 1) {
+ map[i][mac[i]++] = raid_rec2_int8;
+#if defined(__i386__) || defined(__x86_64__)
+ if (raid_cpu_has_ssse3())
+ map[i][mac[i]++] = raid_rec2_ssse3;
+#endif
+ } else {
+ map[i][mac[i]++] = raid_recX_int8;
+#if defined(__i386__) || defined(__x86_64__)
+ if (raid_cpu_has_ssse3())
+ map[i][mac[i]++] = raid_recX_ssse3;
+#endif
+ }
+ }
+
+ /* compute the parity */
+ raid_par(nd, np, size, buffer);
+
+ /* set all the parity to the waste buffer */
+ for (i = 0; i < np; ++i)
+ parity[i] = waste;
+
+ /* all parity levels */
+ for (nr = 1; nr <= np; ++nr) {
+ /* all combinations (nr of nd) disks */
+ combination_first(nr, nd, id);
+ do {
+ /* all combinations (nr of np) parities */
+ combination_first(nr, np, ip);
+ do {
+ /* for each recover function */
+ for (j = 0; j < mac[nr-1]; ++j) {
+ /* set */
+ for (i = 0; i < nr; ++i) {
+ /* remove the missing data */
+ data_save[i] = data[id[i]];
+ data[id[i]] = test[i];
+ /* set the parity to use */
+ parity[ip[i]] = parity_save[ip[i]];
+ }
+
+ /* recover */
+ map[nr-1][j](nr, id, ip, nd, size, buffer);
+
+ /* check */
+ for (i = 0; i < nr; ++i)
+ if (memcmp(test[i], data_save[i], size) != 0)
+ return -1;
+
+ /* restore */
+ for (i = 0; i < nr; ++i) {
+ /* restore the data */
+ data[id[i]] = data_save[i];
+ /* restore the parity */
+ parity[ip[i]] = waste;
+ }
+ }
+ } while (combination_next(nr, np, ip));
+ } while (combination_next(nr, nd, id));
+ }
+
+ free(buffer_alloc);
+ free(buffer);
+
+ return 0;
+}
+
+int raid_test_par(int mode, int nd, size_t size)
+{
+ void *buffer_alloc;
+ void **buffer;
+ int buffermax;
+ int i, j;
+ void (*map[64])(int nd, size_t size, void **vbuf);
+ int mac;
+ int np;
+
+ raid_mode(mode);
+ if (mode == RAID_MODE_CAUCHY)
+ np = RAID_PARITY_MAX;
+ else
+ np = 3;
+
+ buffermax = nd + np * 2;
+
+ buffer = raid_malloc_vector(nd, buffermax, size, &buffer_alloc);
+ if (!buffer)
+ return -1;
+
+ /* fill with random */
+ raid_mrand_vector(buffer, buffermax, size);
+
+ /* compute the parity */
+ raid_par(nd, np, size, buffer);
+
+ /* copy in back buffers */
+ for (i = 0; i < np; ++i)
+ memcpy(buffer[nd + np + i], buffer[nd + i], size);
+
+ /* load all the available functions */
+ mac = 0;
+
+ map[mac++] = raid_par1_int32;
+ map[mac++] = raid_par1_int64;
+ map[mac++] = raid_par2_int32;
+ map[mac++] = raid_par2_int64;
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (raid_cpu_has_sse2()) {
+ map[mac++] = raid_par1_sse2;
+ map[mac++] = raid_par2_sse2;
+#if defined(__x86_64__)
+ map[mac++] = raid_par2_sse2ext;
+#endif
+ }
+
+ if (mode == RAID_MODE_CAUCHY) {
+ map[mac++] = raid_par3_int8;
+ map[mac++] = raid_par4_int8;
+ map[mac++] = raid_par5_int8;
+ map[mac++] = raid_par6_int8;
+
+ if (raid_cpu_has_ssse3()) {
+ map[mac++] = raid_par3_ssse3;
+ map[mac++] = raid_par4_ssse3;
+ map[mac++] = raid_par5_ssse3;
+ map[mac++] = raid_par6_ssse3;
+#if defined(__x86_64__)
+ map[mac++] = raid_par3_ssse3ext;
+ map[mac++] = raid_par4_ssse3ext;
+ map[mac++] = raid_par5_ssse3ext;
+ map[mac++] = raid_par6_ssse3ext;
+#endif
+ }
+#endif
+ } else {
+#if defined(__i386__) || defined(__x86_64__)
+ map[mac++] = raid_parz_int32;
+ map[mac++] = raid_parz_int64;
+ if (raid_cpu_has_sse2()) {
+ map[mac++] = raid_parz_sse2;
+#if defined(__x86_64__)
+ map[mac++] = raid_parz_sse2ext;
+#endif
+ }
+#endif
+ }
+
+ /* check all the functions */
+ for (j = 0; j < mac; ++j) {
+ /* compute parity */
+ map[j](nd, size, buffer);
+
+ /* check it */
+ for (i = 0; i < np; ++i)
+ if (memcmp(buffer[nd + np + i], buffer[nd + i], size) != 0)
+ return -1;
+ }
+
+ free(buffer_alloc);
+ free(buffer);
+
+ return 0;
+}
+
diff --git a/raid/test.h b/raid/test.h
new file mode 100644
index 00000000..721c7e5a
--- /dev/null
+++ b/raid/test.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013 Andrea Mazzoleni
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __RAID_TEST_H
+#define __RAID_TEST_H
+
+/**
+ * Tests sorting functions.
+ *
+ * Test raid_sort() with all the possible combinations of elements to sort.
+ *
+ * Returns 0 on success.
+ */
+int raid_test_sort(void);
+
+/**
+ * Tests combinations functions.
+ *
+ * Tests combination_first() and combination_next() for all the parity levels.
+ *
+ * Returns 0 on success.
+ */
+int raid_test_combo(void);
+
+/**
+ * Tests recovering functions.
+ *
+ * All the recovering functions are tested with all the combinations
+ * of failing disks and recovering parities.
+ *
+ * Take care that the test time grows exponentially with the number of disks.
+ *
+ * Returns 0 on success.
+ */
+int raid_test_rec(unsigned mode, int nd, size_t size);
+
+/**
+ * Tests parity generation functions.
+ *
+ * All the parity generation functions are tested with the specified
+ * number of disks.
+ *
+ * Returns 0 on success.
+ */
+int raid_test_par(unsigned mode, int nd, size_t size);
+
+#endif
+
diff --git a/raid/x86.c b/raid/x86.c
index c0f6ad4e..471ece6d 100644
--- a/raid/x86.c
+++ b/raid/x86.c
@@ -1338,7 +1338,7 @@ void raid_rec1_ssse3(int nr, const int *id, const int *ip, int nd, size_t size,
(void)nr; /* unused, it's always 1 */
- /* if it's RAID5 uses the dedicated and faster function */
+ /* if it's RAID5 uses the faster function */
if (ip[0] == 0) {
raid_rec1_par1(id, nd, size, vv);
return;
diff --git a/selftest.c b/selftest.c
index 34f6d81f..3cf86986 100644
--- a/selftest.c
+++ b/selftest.c
@@ -21,10 +21,11 @@
#include "util.h"
#include "raid/raid.h"
#include "raid/cpu.h"
+#include "raid/combo.h"
#include "raid/internal.h"
+#include "raid/test.h"
#include "elem.h"
#include "state.h"
-#include "combo.h"
struct hash_test_vector {
const char* data;
@@ -48,268 +49,9 @@ static struct hash_test_vector TEST_SPOOKY2[] = {
{ 0, 0, { 0 } }
};
-/**
- * Binomial coefficient of n over r.
- */
-static unsigned bc(unsigned n, unsigned r)
-{
- if (r == 0 || n == r)
- return 1;
- else
- return bc(n - 1, r - 1) + bc(n - 1, r);
-}
-
-static void combotest(void)
-{
- unsigned r;
- unsigned count;
- int p[LEV_MAX];
-
- /* all parities */
- for(r=1;r<=LEV_MAX;++r) {
- /* count combination (r of LEV_MAX) parities */
- count = 0;
- combination_first(r, LEV_MAX, p);
- do {
- ++count;
- } while (combination_next(r, LEV_MAX, p));
-
- if (count != bc(LEV_MAX, r)) {
- fprintf(stderr, "Failed COMBO test\n");
- exit(EXIT_FAILURE);
- }
- }
-}
-
-static void recovtest(unsigned mode, unsigned nd, unsigned block_size)
-{
- void* buffer_alloc;
- void** buffer;
- void** data;
- void** parity;
- void** test;
- void* data_save[LEV_MAX];
- void* parity_save[LEV_MAX];
- void* zero;
- void* waste;
- unsigned buffermax;
- int id[LEV_MAX];
- int ip[LEV_MAX];
- unsigned i;
- unsigned j;
- unsigned nr;
- void (*map[LEV_MAX][4])(int nr, const int* id, const int* ip, int nd, size_t size, void** vbuf);
- unsigned mac[LEV_MAX];
- unsigned np;
-
- raid_mode(mode);
- if (mode == RAID_MODE_CAUCHY)
- np = RAID_PARITY_MAX;
- else
- np = 3;
-
- buffermax = nd + np * 2 + 2;
-
- buffer = malloc_nofail_vector_align(nd, buffermax, block_size, &buffer_alloc);
- mtest_vector(buffer, buffermax, block_size);
-
- data = buffer;
- parity = buffer + nd;
- test = buffer + nd + np;
-
- for(i=0;itv_sec - start->tv_sec) + stop->tv_usec - start->tv_usec;
+ int64_t d;
+
+ d = 1000000LL * (stop->tv_sec - start->tv_sec);
+ d += stop->tv_usec - start->tv_usec;
+
+ return d;
}
/**
@@ -48,7 +53,7 @@ static int64_t diffgettimeofday(struct timeval* start, struct timeval* stop)
count += delta; \
gettimeofday(&stop, 0); \
} while (diffgettimeofday(&start, &stop) < 1000000LL); \
- ds = block_size * (int64_t)count * nd; \
+ ds = size * (int64_t)count * nd; \
dt = diffgettimeofday(&start, &stop);
void speed(void)
@@ -57,40 +62,37 @@ void speed(void)
struct timeval stop;
int64_t ds;
int64_t dt;
- unsigned i, j;
+ int i, j;
unsigned char digest[HASH_SIZE];
unsigned char seed[HASH_SIZE];
int id[LEV_MAX];
int ip[LEV_MAX];
- unsigned count;
- unsigned delta = 10;
- unsigned block_size = 256 * 1024;
- unsigned nd = 8;
- unsigned buffermax;
- void* buffer_alloc;
- void** buffer;
+ int count;
+ int delta = 10;
+ int size = 256 * 1024;
+ int nd = 8;
+ int buffermax;
+ void* v_alloc;
+ void** v;
void* zero;
- /* we need disk + 1 for each parity buffers + 1 zero buffer */
+ /* we need disk + 1 for each parity buffers + 1 zero v */
buffermax = nd + LEV_MAX + 1;
- buffer = malloc_nofail_vector_align(nd, buffermax, block_size, &buffer_alloc);
- mtest_vector(buffer, buffermax, block_size);
+ v = malloc_nofail_vector_align(nd, buffermax, size, &v_alloc);
/* initialize disks with fixed data */
- for(i=0;i0;--j) {
- if (v[i][j-1] != p)
- goto fail;
- v[i][j-1] = d;
- }
- }
- }
-
- return;
-
-fail:
- fprintf(stderr, "DANGER! Your RAM memory is broken! DO NOT PROCEED UNTIL FIXED!\n");
- fprintf(stderr, "Try running some memory test like http://www.memtest86.com/\n");
- exit(EXIT_FAILURE);
-}
-
-void mrand_vector(void** vv, size_t count, size_t size)
-{
- unsigned char** v = (unsigned char**)vv;
- size_t i;
- size_t j;
-
- for(i=0;i