Adds support for fast triple parity without SSSE3.

This commit is contained in:
Andrea Mazzoleni 2013-11-04 23:47:49 +01:00
parent 6a3438f883
commit a5a3c33854
17 changed files with 784 additions and 214 deletions

View file

@ -75,7 +75,7 @@ EXTRA_DIST = \
noautomake.sh \
README AUTHORS HISTORY INSTALL COPYING TODO TEST INSTALL.windows \
snapraid.d snapraid.1 snapraid.txt \
test-raid5.conf test-raid6.conf test-raidTP.conf test-raidQP.conf test-raidPP.conf test-raidHP.conf test-raidHP-hole.conf \
test-raid5.conf test-raid6.conf test-raidS3.conf test-raidS4.conf test-raidS5.conf test-raidS6.conf test-raidS6-hole.conf \
snapraid.conf.example \
configure.windows-x86 configure.windows-x64 snapraid.conf.example.windows \
acinclude.m4
@ -99,14 +99,14 @@ maintainer-clean-local:
CHECKFLAGS = --test-skip-device --test-skip-self -q
CHECKCOUNT = 2000
CHECKSIZE = 4000
CONF = $(srcdir)/test-raidHP.conf
HOLE = $(srcdir)/test-raidHP-hole.conf
CONF = $(srcdir)/test-raidS6.conf
HOLE = $(srcdir)/test-raidS6-hole.conf
RAID5 = $(srcdir)/test-raid5.conf
RAID6 = $(srcdir)/test-raid6.conf
RAIDTP = $(srcdir)/test-raidTP.conf
RAIDQP = $(srcdir)/test-raidQP.conf
RAIDPP = $(srcdir)/test-raidPP.conf
RAIDHP = $(srcdir)/test-raidHP.conf
RAIDTP = $(srcdir)/test-raidS3.conf
RAIDQP = $(srcdir)/test-raidS4.conf
RAIDPP = $(srcdir)/test-raidS5.conf
RAIDHP = $(srcdir)/test-raidS6.conf
check-local:
rm -rf test

30
cpu.h
View file

@ -3,7 +3,7 @@
*
* 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
* 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,
@ -192,20 +192,20 @@ static inline int cpu_has_slowpshufb(void)
* RAID6 mmx 1160 [MB/s]
* RAID6 sse2 2082 [MB/s]
* RAID6 sse2ext 2481 [MB/s]
* RAIDTP int32 236 [MB/s]
* RAIDTP int64 456 [MB/s]
* RAIDTP mmx 576 [MB/s]
* RAIDTP sse2 1109 [MB/s]
* RAIDTP sse2ext 1527 [MB/s]
* RAIDTP ssse3 931 [MB/s] (slower than sse2ext)
* RAIDTP ssse3ext 932 [MB/s] (slower than sse2ext)
* RAIDQP int32 144 [MB/s]
* RAIDQP int64 271 [MB/s]
* RAIDQP mmx 431 [MB/s]
* RAIDQP sse2 843 [MB/s]
* RAIDQP sse2ext 1086 [MB/s]
* RAIDQP ssse3 732 [MB/s] (slower than sse2ext)
* RAIDQP ssse3ext 571 [MB/s] (slower than sse2ext)
* RAIDZ3 int32 236 [MB/s]
* RAIDZ3 int64 456 [MB/s]
* RAIDZ3 mmx 576 [MB/s]
* RAIDZ3 sse2 1109 [MB/s]
* RAIDZ3 sse2ext 1527 [MB/s]
* RAIDZ3 ssse3 931 [MB/s] (slower than sse2ext)
* RAIDZ3 ssse3ext 932 [MB/s] (slower than sse2ext)
* RAIDZ4 int32 144 [MB/s]
* RAIDZ4 int64 271 [MB/s]
* RAIDZ4 mmx 431 [MB/s]
* RAIDZ4 sse2 843 [MB/s]
* RAIDZ4 sse2ext 1086 [MB/s]
* RAIDZ4 ssse3 732 [MB/s] (slower than sse2ext)
* RAIDZ4 ssse3ext 571 [MB/s] (slower than sse2ext)
*/
if (family == 6 && model == 28)
return 1;

View file

@ -134,6 +134,32 @@ void set_cauchy(unsigned char* matrix)
}
}
/**
* Setup the Power matrix used to generate the parity.
*/
void set_power(unsigned char* matrix)
{
unsigned i;
unsigned char v;
v = 1;
for(i=0;i<DISK;++i) {
matrix[0*DISK+i] = v;
}
v = 1;
for(i=0;i<DISK;++i) {
matrix[1*DISK+i] = v;
v = gfmul(2, v);
}
v = 1;
for(i=0;i<DISK;++i) {
matrix[2*DISK+i] = v;
v = gfmul(4, v);
}
}
/**
* Next power of 2.
*/
@ -230,6 +256,38 @@ int main(void)
}
printf("};\n\n");
/* power matrix */
set_power(matrix);
printf("/**\n");
printf(" * Power matrix used to generate parity.\n");
printf(" * This matrix is valid for up to %u parity with %u data disks.\n", 3, DISK);
printf(" *\n");
for(p=0;p<3;++p) {
printf(" * ");
for(i=0;i<DISK;++i) {
printf("%02x ", matrix[p*DISK+i]);
}
printf("\n");
}
printf(" */\n");
printf("const unsigned char __attribute__((aligned(256))) gfpower[%u][256] =\n", 3);
printf("{\n");
for(p=0;p<3;++p) {
printf("\t{\n");
for(i=0;i<DISK;++i) {
if (i % 8 == 0)
printf("\t\t");
printf("0x%02x,", matrix[p*DISK+i]);
if (i % 8 == 7)
printf("\n");
else
printf(" ");
}
printf("\n\t},\n");
}
printf("};\n\n");
/* cauchy matrix */
set_cauchy(matrix);

465
raid.c
View file

@ -26,8 +26,7 @@
* This support was later completely rewritten (many times), but
* the H. Peter Anvin's Copyright may still apply.
*
* The RAIDTP (Triple Parity), RAIDQP (Quad parity), RAIDPP (Penta Parity)
* and RAIDHP (Hexa parity) support, and the recovering based on matrix
* The others RAID levels and the recovering based on matrix
* inversion is original work implemented from scratch.
*/
@ -42,7 +41,7 @@
* P = sum(Di)
* Q = sum(2^i * Di) with 0<=i<N
*
* To support RAIDTP (Triple Parity), it was first evaluated, and then
* To support triple parity it was first evaluated, and then
* dropped, the use of an extension of the same approach, with additional
* parity coefficients set as powers of 4, with equations:
*
@ -53,7 +52,7 @@
* This method is also the same used by ZFS to implement its RAIDZ3
* support, it works well, and it's very efficient.
*
* Unfortunately, the same approach doesn't work for RAIDQP (Quad Parity).
* Unfortunately, the same approach doesn't work for quad parity.
* Using additional parity coefficients set as power of 8 with equations:
*
* P = sum(Di)
@ -69,8 +68,8 @@
* requirement to have a MDS (Maximum Distance Separable) code [2, Chap 11,
* Theorem 8].
*
* Using the primitive polynomial 285, RAIDQP works for up to 21 data disks
* with parity coefficients "1,2,4,8". Changing polynomial to one of
* Using the primitive polynomial 285, quad parity works for up to 21 data
* disks with parity coefficients "1,2,4,8". Changing polynomial to one of
* 391/451/463/487, it works for up to 27 disks with the same parity
* coefficients.
* Using different parity coefficients, like "5,13,27,35", it's possible
@ -79,7 +78,7 @@
* polynomial 100087 or 122563 that supports up to Hexa (6) Parity
* with parity coefficients 1,2,4,8,16,32, but only for up to 89 disks.
*
* To overcome these limitations we instead use a Cauchy Matrix [3][4]
* To overcome these limitations we instead use a Cauchy matrix [3][4]
* to compute the parity.
* Such matrix has the mathematical property to have all the square
* submatrices not singular, resulting in always solvable equations, for
@ -91,12 +90,12 @@
*
* Hopefully there is a method to implement parallel multiplications
* using SSSE3 instructions [1][5]. Method already competitive with the
* computation of RAIDTP parity using power coefficients.
* computation of triple parity using power coefficients.
*
* Another important property of the Cauchy matrix is that we can setup
* the first two rows with coeffients equal at the RAID5 and RAID6 approach
* described in Anvin's paper [1], resulting in a compatible extension,
* and requiring SSSE3 instructions only if RAIDTP is used.
* and requiring SSSE3 instructions only if triple parity is used.
*
* We also adjust the matrix, multipling each row for a constant factor
* to make the first column with all 1, to optimize the computation
@ -167,24 +166,24 @@
* int8 int32 int64 sse2 sse2e ssse3 ssse3e
* raid5 11927 22075 36004
* raid6 3378 5874 18235 19164
* raidTP 844 8814 9419
* raidQP 665 6836 7415
* raidPP 537 5388 5686
* raidHP 449 4307 4789
* raidS3 844 8814 9419
* raidS4 665 6836 7415
* raidS5 537 5388 5686
* raidS6 449 4307 4789
*
* Values are in MiB/s of data processed, not counting generated parity.
* You can replicate these results in your machine using the "snapraid -T"
* command.
*
* For comparison, a similar implementation using the power coeffients
* approach, is only a little faster (5%) for RAIDTP with power
* coefficient "4", and with equal speed for RAIDQP with power coefficient
* approach, is only a little faster (5%) for RAIDS3 with power
* coefficient "4", and with equal speed for RAIDS4 with power coefficient
* "8", even using AVX instructions to get a better registers allocation
* with the three operands PSHUFB.
*
* int32 int64 sse2 sse2e ssse3 ssse3e avxe
* raidTP (power) 1511 2775 8625 9336 9645 9966
* raidQP (power) 842 1518 5195 5507 6278 6737 7410
* raidZ3 1511 2775 8625 9336 9645 9966
* raidZ4 842 1518 5195 5507 6278 6737 7410
*
* References:
* [1] Anvin, "The mathematics of RAID-6", 2004
@ -564,14 +563,253 @@ void raid6_sse2ext(unsigned char** vbuf, unsigned data, unsigned size)
#endif
/*
* RAIDTP 8bit C implementation
* RAIDZ3 with power coefficients 32bit C implementation
*/
void raidZ3_int32(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
unsigned char* r;
int d, l;
unsigned i;
uint32_t d0, r0, q0, p0;
uint32_t d1, r1, q1, p1;
l = data - 1;
p = vbuf[data];
q = vbuf[data+1];
r = vbuf[data+2];
for(i=0;i<size;i+=8) {
r0 = q0 = p0 = v_32(vbuf[l][i]);
r1 = q1 = p1 = v_32(vbuf[l][i+4]);
for(d=l-1;d>=0;--d) {
d0 = v_32(vbuf[d][i]);
d1 = v_32(vbuf[d][i+4]);
p0 ^= d0;
p1 ^= d1;
q0 = x2_32(q0);
q1 = x2_32(q1);
q0 ^= d0;
q1 ^= d1;
r0 = x2_32(r0);
r1 = x2_32(r1);
r0 = x2_32(r0);
r1 = x2_32(r1);
r0 ^= d0;
r1 ^= d1;
}
v_32(p[i]) = p0;
v_32(p[i+4]) = p1;
v_32(q[i]) = q0;
v_32(q[i+4]) = q1;
v_32(r[i]) = r0;
v_32(r[i+4]) = r1;
}
}
/*
* RAIDZ3 with power coefficients 64bit C implementation
*/
void raidZ3_int64(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
unsigned char* r;
int d, l;
unsigned i;
uint64_t d0, r0, q0, p0;
uint64_t d1, r1, q1, p1;
l = data - 1;
p = vbuf[data];
q = vbuf[data+1];
r = vbuf[data+2];
for(i=0;i<size;i+=16) {
r0 = q0 = p0 = v_64(vbuf[l][i]);
r1 = q1 = p1 = v_64(vbuf[l][i+8]);
for(d=l-1;d>=0;--d) {
d0 = v_64(vbuf[d][i]);
d1 = v_64(vbuf[d][i+8]);
p0 ^= d0;
p1 ^= d1;
q0 = x2_64(q0);
q1 = x2_64(q1);
q0 ^= d0;
q1 ^= d1;
r0 = x2_64(r0);
r1 = x2_64(r1);
r0 = x2_64(r0);
r1 = x2_64(r1);
r0 ^= d0;
r1 ^= d1;
}
v_64(p[i]) = p0;
v_64(p[i+8]) = p1;
v_64(q[i]) = q0;
v_64(q[i+8]) = q1;
v_64(r[i]) = r0;
v_64(r[i+8]) = r1;
}
}
#if defined(__i386__) || defined(__x86_64__)
/*
* RAIDZ3 with power coefficients SSE2 implementation
*/
void raidZ3_sse2(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
unsigned char* r;
int d, l;
unsigned i;
l = data - 1;
p = vbuf[data];
q = vbuf[data+1];
r = vbuf[data+2];
asm volatile("movdqa %0,%%xmm7" : : "m" (gfconst16.poly[0]));
for(i=0;i<size;i+=16) {
asm volatile("movdqa %0,%%xmm0" : : "m" (vbuf[l][i]));
asm volatile("movdqa %xmm0,%xmm1");
asm volatile("movdqa %xmm0,%xmm2");
for(d=l-1;d>=0;--d) {
asm volatile("pxor %xmm4,%xmm4");
asm volatile("pxor %xmm5,%xmm5");
asm volatile("pxor %xmm6,%xmm6");
asm volatile("pcmpgtb %xmm1,%xmm4");
asm volatile("pcmpgtb %xmm2,%xmm5");
asm volatile("paddb %xmm1,%xmm1");
asm volatile("paddb %xmm2,%xmm2");
asm volatile("pand %xmm7,%xmm4");
asm volatile("pand %xmm7,%xmm5");
asm volatile("pxor %xmm4,%xmm1");
asm volatile("pxor %xmm5,%xmm2");
asm volatile("pcmpgtb %xmm2,%xmm6");
asm volatile("paddb %xmm2,%xmm2");
asm volatile("pand %xmm7,%xmm6");
asm volatile("pxor %xmm6,%xmm2");
asm volatile("movdqa %0,%%xmm3" : : "m" (vbuf[d][i]));
asm volatile("pxor %xmm3,%xmm0");
asm volatile("pxor %xmm3,%xmm1");
asm volatile("pxor %xmm3,%xmm2");
}
asm volatile("movntdq %%xmm0,%0" : "=m" (p[i]));
asm volatile("movntdq %%xmm1,%0" : "=m" (q[i]));
asm volatile("movntdq %%xmm2,%0" : "=m" (r[i]));
}
asm volatile("sfence" : : : "memory");
}
#endif
#if defined(__x86_64__)
/*
* RAIDZ3 with power coefficients SSE2 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raidZ3_sse2ext(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
unsigned char* r;
int d, l;
unsigned i;
l = data - 1;
p = vbuf[data];
q = vbuf[data+1];
r = vbuf[data+2];
asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0]));
for(i=0;i<size;i+=32) {
asm volatile("movdqa %0,%%xmm0" : : "m" (vbuf[l][i]));
asm volatile("movdqa %0,%%xmm8" : : "m" (vbuf[l][i+16]));
asm volatile("movdqa %xmm0,%xmm1");
asm volatile("movdqa %xmm8,%xmm9");
asm volatile("movdqa %xmm0,%xmm2");
asm volatile("movdqa %xmm8,%xmm10");
for(d=l-1;d>=0;--d) {
asm volatile("pxor %xmm4,%xmm4");
asm volatile("pxor %xmm5,%xmm5");
asm volatile("pxor %xmm6,%xmm6");
asm volatile("pxor %xmm12,%xmm12");
asm volatile("pxor %xmm13,%xmm13");
asm volatile("pxor %xmm14,%xmm14");
asm volatile("pcmpgtb %xmm1,%xmm4");
asm volatile("pcmpgtb %xmm2,%xmm5");
asm volatile("pcmpgtb %xmm9,%xmm12");
asm volatile("pcmpgtb %xmm10,%xmm13");
asm volatile("paddb %xmm1,%xmm1");
asm volatile("paddb %xmm2,%xmm2");
asm volatile("paddb %xmm9,%xmm9");
asm volatile("paddb %xmm10,%xmm10");
asm volatile("pand %xmm7,%xmm4");
asm volatile("pand %xmm7,%xmm5");
asm volatile("pand %xmm7,%xmm12");
asm volatile("pand %xmm7,%xmm13");
asm volatile("pxor %xmm4,%xmm1");
asm volatile("pxor %xmm5,%xmm2");
asm volatile("pxor %xmm12,%xmm9");
asm volatile("pxor %xmm13,%xmm10");
asm volatile("pcmpgtb %xmm2,%xmm6");
asm volatile("pcmpgtb %xmm10,%xmm14");
asm volatile("paddb %xmm2,%xmm2");
asm volatile("paddb %xmm10,%xmm10");
asm volatile("pand %xmm7,%xmm6");
asm volatile("pand %xmm7,%xmm14");
asm volatile("pxor %xmm6,%xmm2");
asm volatile("pxor %xmm14,%xmm10");
asm volatile("movdqa %0,%%xmm3" : : "m" (vbuf[d][i]));
asm volatile("movdqa %0,%%xmm11" : : "m" (vbuf[d][i+16]));
asm volatile("pxor %xmm3,%xmm0");
asm volatile("pxor %xmm3,%xmm1");
asm volatile("pxor %xmm3,%xmm2");
asm volatile("pxor %xmm11,%xmm8");
asm volatile("pxor %xmm11,%xmm9");
asm volatile("pxor %xmm11,%xmm10");
}
asm volatile("movntdq %%xmm0,%0" : "=m" (p[i]));
asm volatile("movntdq %%xmm8,%0" : "=m" (p[i+16]));
asm volatile("movntdq %%xmm1,%0" : "=m" (q[i]));
asm volatile("movntdq %%xmm9,%0" : "=m" (q[i+16]));
asm volatile("movntdq %%xmm2,%0" : "=m" (r[i]));
asm volatile("movntdq %%xmm10,%0" : "=m" (r[i+16]));
}
asm volatile("sfence" : : : "memory");
}
#endif
/*
* RAIDS3 8bit C implementation
*
* Note that instead of a generic multiplicationt table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raidTP_int8(unsigned char** vbuf, unsigned data, unsigned size)
void raidS3_int8(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -611,9 +849,9 @@ void raidTP_int8(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__i386__) || defined(__x86_64__)
/*
* RAIDTP SSSE3 implementation
* RAIDS3 SSSE3 implementation
*/
void raidTP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
void raidS3_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -697,11 +935,11 @@ void raidTP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__x86_64__)
/*
* RAIDTP SSSE3 implementation
* RAIDS3 SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raidTP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
void raidS3_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -826,14 +1064,14 @@ void raidTP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
#endif
/*
* RAIDQP 8bit C implementation
* RAIDS4 8bit C implementation
*
* Note that instead of a generic multiplicationt table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raidQP_int8(unsigned char** vbuf, unsigned data, unsigned size)
void raidS4_int8(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -878,9 +1116,9 @@ void raidQP_int8(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__i386__) || defined(__x86_64__)
/*
* RAIDQP SSSE3 implementation
* RAIDS4 SSSE3 implementation
*/
void raidQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
void raidS4_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -983,11 +1221,11 @@ void raidQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__x86_64__)
/*
* RAIDQP SSSE3 implementation
* RAIDS4 SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raidQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
void raidS4_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1144,14 +1382,14 @@ void raidQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
#endif
/*
* RAIDPP 8bit C implementation
* RAIDS5 8bit C implementation
*
* Note that instead of a generic multiplicationt table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raidPP_int8(unsigned char** vbuf, unsigned data, unsigned size)
void raidS5_int8(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1201,13 +1439,13 @@ void raidPP_int8(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__i386__) || defined(__x86_64__)
/*
* RAIDPP SSSE3 implementation
* RAIDS5 SSSE3 implementation
*/
#ifdef _WIN32
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
__attribute__((force_align_arg_pointer))
#endif
void raidPP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
void raidS5_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
{
unsigned char* p;
@ -1331,11 +1569,11 @@ void raidPP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__x86_64__)
/*
* RAIDPP SSSE3 implementation
* RAIDS5 SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raidPP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
void raidS5_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1452,14 +1690,14 @@ void raidPP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
#endif
/*
* RAIDHP 8bit C implementation
* RAIDS6 8bit C implementation
*
* Note that instead of a generic multiplicationt table, likely resulting
* in multiple cache misses, a precomputed table could be used.
* But this is only a kind of reference function, and we are not really
* interested in speed.
*/
void raidHP_int8(unsigned char** vbuf, unsigned data, unsigned size)
void raidS6_int8(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1514,13 +1752,13 @@ void raidHP_int8(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__i386__) || defined(__x86_64__)
/*
* RAIDHP SSSE3 implementation
* RAIDS6 SSSE3 implementation
*/
#ifdef _WIN32
/* ensures that stack is aligned at 16 bytes because we allocate SSE registers in it */
__attribute__((force_align_arg_pointer))
#endif
void raidHP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
void raidS6_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1665,11 +1903,11 @@ void raidHP_ssse3(unsigned char** vbuf, unsigned data, unsigned size)
#if defined(__x86_64__)
/*
* RAIDHP SSSE3 implementation
* RAIDS6 SSSE3 implementation
*
* Note that it uses 16 registers, meaning that x64 is required.
*/
void raidHP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
void raidS6_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
{
unsigned char* p;
unsigned char* q;
@ -1802,28 +2040,42 @@ void raidHP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size)
}
#endif
/****************************************************************************/
/* mode */
static unsigned raid_mode = RAID_MODE_S; /**< RAID mode. */
void raid_set(unsigned mode)
{
raid_mode = mode;
}
/****************************************************************************/
/* parity generation */
/* internal forwarder */
static void (*raid5_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raid6_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidTP_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidQP_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidPP_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidHP_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidZ3_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidS3_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidS4_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidS5_gen)(unsigned char** vbuf, unsigned data, unsigned size);
static void (*raidS6_gen)(unsigned char** vbuf, unsigned data, unsigned size);
void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size)
{
assert(data >= RAID_DATA_MIN && data <= RAID_DATA_MAX);
switch (level) {
case 1 : raid5_gen(vbuf, data, size); break;
case 2 : raid6_gen(vbuf, data, size); break;
case 3 : raidTP_gen(vbuf, data, size); break;
case 4 : raidQP_gen(vbuf, data, size); break;
case 5 : raidPP_gen(vbuf, data, size); break;
case 6 : raidHP_gen(vbuf, data, size); break;
case 3 :
if (raid_mode == RAID_MODE_S)
raidS3_gen(vbuf, data, size);
else
raidZ3_gen(vbuf, data, size);
break;
case 4 : raidS4_gen(vbuf, data, size); break;
case 5 : raidS5_gen(vbuf, data, size); break;
case 6 : raidS6_gen(vbuf, data, size); break;
default:
fprintf(stderr, "Invalid raid gen level\n");
exit(EXIT_FAILURE);
@ -1892,11 +2144,11 @@ static inline const unsigned char* table(unsigned char v)
*/
static inline void raid_delta_gen(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size)
{
unsigned char* p[RAID_PARITY_MAX];
unsigned char* pa[RAID_PARITY_MAX];
unsigned char* p[RAID_PARITY_S_MAX];
unsigned char* pa[RAID_PARITY_S_MAX];
unsigned i;
assert(level > 0 && level <= RAID_PARITY_MAX);
assert(level > 0 && level <= RAID_PARITY_S_MAX);
for(i=0;i<level;++i) {
/* keep a copy of the parity buffer */
@ -2029,7 +2281,10 @@ static void raid6_recov2(const int* d, const int* c, unsigned char** vbuf, unsig
*/
static unsigned char A(unsigned p, unsigned d)
{
return gfgen[p][d];
if (raid_mode == RAID_MODE_S)
return gfgen[p][d];
else
return gfpower[p][d];
}
/**
@ -2225,11 +2480,11 @@ void raid_recov2_int8(unsigned level, const int* d, const int* c, unsigned char*
*/
void raid_recovX_int8(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size)
{
unsigned char* p[RAID_PARITY_MAX];
unsigned char* pa[RAID_PARITY_MAX];
const unsigned char* T[RAID_PARITY_MAX][RAID_PARITY_MAX];
unsigned char G[RAID_PARITY_MAX*RAID_PARITY_MAX];
unsigned char V[RAID_PARITY_MAX*RAID_PARITY_MAX];
unsigned char* p[RAID_PARITY_S_MAX];
unsigned char* pa[RAID_PARITY_S_MAX];
const unsigned char* T[RAID_PARITY_S_MAX][RAID_PARITY_S_MAX];
unsigned char G[RAID_PARITY_S_MAX*RAID_PARITY_S_MAX];
unsigned char V[RAID_PARITY_S_MAX*RAID_PARITY_S_MAX];
unsigned i, j, k;
/* setup the coefficients matrix */
@ -2258,7 +2513,7 @@ void raid_recovX_int8(unsigned level, const int* d, const int* c, unsigned char*
}
for(i=0;i<size;++i) {
unsigned char PD[RAID_PARITY_MAX];
unsigned char PD[RAID_PARITY_S_MAX];
/* delta */
for(j=0;j<level;++j)
@ -2441,10 +2696,10 @@ void raid_recov2_ssse3(unsigned level, const int* d, const int* c, unsigned char
void raid_recovX_ssse3(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size)
{
unsigned N = level;
unsigned char* p[RAID_PARITY_MAX];
unsigned char* pa[RAID_PARITY_MAX];
unsigned char G[RAID_PARITY_MAX*RAID_PARITY_MAX];
unsigned char V[RAID_PARITY_MAX*RAID_PARITY_MAX];
unsigned char* p[RAID_PARITY_S_MAX];
unsigned char* pa[RAID_PARITY_S_MAX];
unsigned char G[RAID_PARITY_S_MAX*RAID_PARITY_S_MAX];
unsigned char V[RAID_PARITY_S_MAX*RAID_PARITY_S_MAX];
unsigned i, j, k;
/* setup the coefficients matrix */
@ -2468,7 +2723,7 @@ void raid_recovX_ssse3(unsigned level, const int* d, const int* c, unsigned char
asm volatile("movdqa %0,%%xmm7" : : "m" (gfconst16.mask[0]));
for(i=0;i<size;i+=16) {
unsigned char PD[RAID_PARITY_MAX][16] __attribute__((aligned(16)));
unsigned char PD[RAID_PARITY_S_MAX][16] __attribute__((aligned(16)));
/* delta */
for(j=0;j<N;++j) {
@ -2540,17 +2795,19 @@ void raid_recov(unsigned level, const int* d, const int* c, unsigned char** vbuf
void raid_init(void)
{
raidTP_gen = raidTP_int8;
raidQP_gen = raidQP_int8;
raidPP_gen = raidPP_int8;
raidHP_gen = raidHP_int8;
raidS3_gen = raidS3_int8;
raidS4_gen = raidS4_int8;
raidS5_gen = raidS5_int8;
raidS6_gen = raidS6_int8;
if (sizeof(void*) == 4) {
raid5_gen = raid5_int32;
raid6_gen = raid6_int32;
raidZ3_gen = raidZ3_int32;
} else {
raid5_gen = raid5_int64;
raid6_gen = raid6_int64;
raidZ3_gen = raidZ3_int64;
}
raid_recov1 = raid_recov1_int8;
@ -2563,25 +2820,28 @@ void raid_init(void)
#if defined(__x86_64__)
if (cpu_has_slowextendedreg()) {
raid6_gen = raid6_sse2;
raidZ3_gen = raidZ3_sse2;
} else {
raid6_gen = raid6_sse2ext;
raidZ3_gen = raidZ3_sse2ext;
}
#else
raid6_gen = raid6_sse2;
raidZ3_gen = raidZ3_sse2;
#endif
}
if (cpu_has_ssse3()) {
#if defined(__x86_64__)
raidTP_gen = raidTP_ssse3ext;
raidQP_gen = raidQP_ssse3ext;
raidPP_gen = raidPP_ssse3ext;
raidHP_gen = raidHP_ssse3ext;
raidS3_gen = raidS3_ssse3ext;
raidS4_gen = raidS4_ssse3ext;
raidS5_gen = raidS5_ssse3ext;
raidS6_gen = raidS6_ssse3ext;
#else
raidTP_gen = raidTP_ssse3;
raidQP_gen = raidQP_ssse3;
raidPP_gen = raidPP_ssse3;
raidHP_gen = raidHP_ssse3;
raidS3_gen = raidS3_ssse3;
raidS4_gen = raidS4_ssse3;
raidS5_gen = raidS5_ssse3;
raidS6_gen = raidS6_ssse3;
#endif
raid_recov1 = raid_recov1_ssse3;
raid_recov2 = raid_recov2_ssse3;
@ -2594,14 +2854,16 @@ static struct raid_func {
const char* name;
void* p;
} RAID_FUNC[] = {
{ "int8", raidTP_int8 },
{ "int8", raidQP_int8 },
{ "int8", raidPP_int8 },
{ "int8", raidHP_int8 },
{ "int8", raidS3_int8 },
{ "int8", raidS4_int8 },
{ "int8", raidS5_int8 },
{ "int8", raidS6_int8 },
{ "int32", raid5_int32 },
{ "int64", raid5_int64 },
{ "int32", raid6_int32 },
{ "int64", raid6_int64 },
{ "int32", raidZ3_int32 },
{ "int64", raidZ3_int64 },
{ "int8", raid_recov1_int8 },
{ "int8", raid_recov2_int8 },
{ "int8", raid_recovX_int8 },
@ -2609,10 +2871,11 @@ static struct raid_func {
#if defined(__i386__) || defined(__x86_64__)
{ "sse2", raid5_sse2 },
{ "sse2", raid6_sse2 },
{ "ssse3", raidTP_ssse3 },
{ "ssse3", raidQP_ssse3 },
{ "ssse3", raidPP_ssse3 },
{ "ssse3", raidHP_ssse3 },
{ "sse2", raidZ3_sse2 },
{ "ssse3", raidS3_ssse3 },
{ "ssse3", raidS4_ssse3 },
{ "ssse3", raidS5_ssse3 },
{ "ssse3", raidS6_ssse3 },
{ "ssse3", raid_recov1_ssse3 },
{ "ssse3", raid_recov2_ssse3 },
{ "ssse3", raid_recovX_ssse3 },
@ -2620,10 +2883,11 @@ static struct raid_func {
#if defined(__x86_64__)
{ "sse2e", raid6_sse2ext },
{ "ssse3e", raidTP_ssse3ext },
{ "ssse3e", raidQP_ssse3ext },
{ "ssse3e", raidPP_ssse3ext },
{ "ssse3e", raidHP_ssse3ext },
{ "sse2e", raidZ3_sse2ext },
{ "ssse3e", raidS3_ssse3ext },
{ "ssse3e", raidS4_ssse3ext },
{ "ssse3e", raidS5_ssse3ext },
{ "ssse3e", raidS6_ssse3ext },
#endif
{ 0, 0 }
};
@ -2649,24 +2913,29 @@ const char* raid6_tag(void)
return raid_tag(raid6_gen);
}
const char* raidTP_tag(void)
const char* raidZ3_tag(void)
{
return raid_tag(raidTP_gen);
return raid_tag(raidZ3_gen);
}
const char* raidQP_tag(void)
const char* raidS3_tag(void)
{
return raid_tag(raidQP_gen);
return raid_tag(raidS3_gen);
}
const char* raidPP_tag(void)
const char* raidS4_tag(void)
{
return raid_tag(raidPP_gen);
return raid_tag(raidS4_gen);
}
const char* raidHP_tag(void)
const char* raidS5_tag(void)
{
return raid_tag(raidHP_gen);
return raid_tag(raidS5_gen);
}
const char* raidS6_tag(void)
{
return raid_tag(raidS6_gen);
}
const char* raid_recov1_tag(void)

78
raid.h
View file

@ -22,9 +22,33 @@
/* raid */
/**
* Max level of parity supported.
* RAID mode supporting up to 6 parities.
*
* It requires SSSE3 to get good performance with triple or more parities.
*
* This is the default mode used by SnapRAID.
*/
#define RAID_PARITY_MAX 6
#define RAID_MODE_S 0
/**
* RAID mode supporting up to 3 parities,
*
* It has a fast implementation not requiring SSSE3 for triple parity.
* This is mostly intended for low end CPUs like ARM and AMD Athlon II.
*
* This is the mode used by ZFS.
*/
#define RAID_MODE_Z 1
/**
* Max level of parity supported for mode S.
*/
#define RAID_PARITY_S_MAX 6
/**
* Max level of parity supported for mode Z.
*/
#define RAID_PARITY_Z_MAX 3
/**
* Maximum number of data disks.
@ -34,7 +58,6 @@
/**
* Minimum number of data disks.
* Limit of some optimized parity generator functions.
*/
#define RAID_DATA_MIN 2
@ -43,8 +66,18 @@
*/
void raid_init(void);
/**
* Set the RAID mode to use. One of RAID_MODE_*.
*
* You can change mode at any time, and it will affect next calls to raid_gen() and raid_recov().
*
* The two modes are compatible for the first two levels of parity. The third one is different.
*/
void raid_set(unsigned mode);
/**
* Computes the parity.
*
* \param level Number of parities to compute.
* \param vbuf Vector of pointers to the blocks for disks and parities.
* It has (::data + ::level) elements. Each element points to a buffer of ::size bytes.
@ -55,6 +88,7 @@ void raid_gen(unsigned level, unsigned char** vbuf, unsigned data, unsigned size
/**
* Recovers failures of data disks using the specified parities.
*
* Note that only the data blocks are recovered. The parity is destroyed.
* \param level Number of failed disks.
* \param d[] Vector of indexes of the data disks to recover. Starting from 0.
@ -73,16 +107,18 @@ void raid_recov(unsigned level, const int* d, const int* c, unsigned char** vbuf
*/
const char* raid5_tag(void);
const char* raid6_tag(void);
const char* raidTP_tag(void);
const char* raidQP_tag(void);
const char* raidPP_tag(void);
const char* raidHP_tag(void);
const char* raidZ3_tag(void);
const char* raidS3_tag(void);
const char* raidS4_tag(void);
const char* raidS5_tag(void);
const char* raidS6_tag(void);
const char* raid_recov1_tag(void);
const char* raid_recov2_tag(void);
const char* raid_recovX_tag(void);
/**
* Specialized parity computation.
*
* Only for testing.
*/
void raid5_int32(unsigned char** vbuf, unsigned data, unsigned size);
@ -92,18 +128,22 @@ void raid6_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_sse2(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidPP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidPP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidPP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidHP_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidHP_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidHP_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidZ3_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raidZ3_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raidZ3_sse2(unsigned char** vbuf, unsigned data, unsigned size);
void raidZ3_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidS3_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidS3_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidS3_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidS4_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidS4_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidS4_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidS5_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidS5_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidS5_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raidS6_int8(unsigned char** vbuf, unsigned data, unsigned size);
void raidS6_ssse3(unsigned char** vbuf, unsigned data, unsigned size);
void raidS6_ssse3ext(unsigned char** vbuf, unsigned data, unsigned size);
void raid_recov1_int8(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recov2_int8(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
void raid_recovX_int8(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);

View file

@ -80,7 +80,7 @@ static void combotest(void)
}
}
static void recovtest(unsigned diskmax, unsigned block_size)
static void recovtest(unsigned mode, unsigned diskmax, unsigned block_size)
{
void* buffer_alloc;
unsigned char** buffer;
@ -99,17 +99,24 @@ static void recovtest(unsigned diskmax, unsigned block_size)
unsigned r;
void (*map[LEV_MAX][4])(unsigned level, const int* d, const int* c, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
unsigned mac[LEV_MAX];
unsigned level;
buffermax = diskmax + LEV_MAX * 2 + 2;
raid_set(mode);
if (mode == RAID_MODE_S)
level = LEV_MAX;
else
level = 3;
buffermax = diskmax + level * 2 + 2;
buffer = malloc_nofail_vector_align(diskmax, buffermax, block_size, &buffer_alloc);
mtest_vector(buffer, buffermax, block_size);
data = buffer;
parity = buffer + diskmax;
test = buffer + diskmax + LEV_MAX;
test = buffer + diskmax + level;
for(i=0;i<LEV_MAX;++i)
for(i=0;i<level;++i)
parity_save[i] = parity[i];
zero = buffer[buffermax-2];
@ -124,7 +131,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
}
/* setup recov functions */
for(i=0;i<LEV_MAX;++i) {
for(i=0;i<level;++i) {
mac[i] = 0;
if (i == 0) {
map[i][mac[i]++] = raid_recov1_int8;
@ -151,19 +158,19 @@ static void recovtest(unsigned diskmax, unsigned block_size)
}
/* compute the parity */
raid_gen(LEV_MAX, buffer, diskmax, block_size);
raid_gen(level, buffer, diskmax, block_size);
/* set all the parity to the waste buffer */
for(i=0;i<LEV_MAX;++i)
for(i=0;i<level;++i)
parity[i] = waste;
/* all parity levels */
for(r=1;r<=LEV_MAX;++r) {
for(r=1;r<=level;++r) {
/* all combinations (r of diskmax) disks */
combination_first(r, diskmax, d);
do {
/* all combinations (r of LEV_MAX) parities */
combination_first(r, LEV_MAX, p);
/* all combinations (r of level) parities */
combination_first(r, level, p);
do {
/* for each recover function */
for(j=0;j<mac[r-1];++j) {
@ -195,7 +202,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
parity[p[i]] = waste;
}
}
} while (combination_next(r, LEV_MAX, p));
} while (combination_next(r, level, p));
} while (combination_next(r, diskmax, d));
}
@ -203,7 +210,7 @@ static void recovtest(unsigned diskmax, unsigned block_size)
free(buffer);
}
static void gentest(unsigned diskmax, unsigned block_size)
static void gentest(unsigned mode, unsigned diskmax, unsigned block_size)
{
void* buffer_alloc;
unsigned char** buffer;
@ -211,8 +218,15 @@ static void gentest(unsigned diskmax, unsigned block_size)
unsigned i, j;
void (*map[64])(unsigned char** buffer, unsigned diskmax, unsigned size);
unsigned mac;
unsigned level;
buffermax = diskmax + LEV_MAX * 2;
raid_set(mode);
if (mode == RAID_MODE_S)
level = LEV_MAX;
else
level = 3;
buffermax = diskmax + level * 2;
buffer = malloc_nofail_vector_align(diskmax, buffermax, block_size, &buffer_alloc);
mtest_vector(buffer, buffermax, block_size);
@ -224,20 +238,15 @@ static void gentest(unsigned diskmax, unsigned block_size)
}
/* compute the parity */
raid_gen(LEV_MAX, buffer, diskmax, block_size);
raid_gen(level, buffer, diskmax, block_size);
/* copy in back buffers */
for(i=0;i<LEV_MAX;++i)
memcpy(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size);
for(i=0;i<level;++i)
memcpy(buffer[diskmax + level + i], buffer[diskmax + i], block_size);
/* load all the available functions */
mac = 0;
map[mac++] = raidTP_int8;
map[mac++] = raidQP_int8;
map[mac++] = raidPP_int8;
map[mac++] = raidHP_int8;
map[mac++] = raid5_int32;
map[mac++] = raid5_int64;
map[mac++] = raid6_int32;
@ -252,19 +261,37 @@ static void gentest(unsigned diskmax, unsigned block_size)
#endif
}
if (cpu_has_ssse3()) {
map[mac++] = raidTP_ssse3;
map[mac++] = raidQP_ssse3;
map[mac++] = raidPP_ssse3;
map[mac++] = raidHP_ssse3;
if (mode == RAID_MODE_S) {
map[mac++] = raidS3_int8;
map[mac++] = raidS4_int8;
map[mac++] = raidS5_int8;
map[mac++] = raidS6_int8;
if (cpu_has_ssse3()) {
map[mac++] = raidS3_ssse3;
map[mac++] = raidS4_ssse3;
map[mac++] = raidS5_ssse3;
map[mac++] = raidS6_ssse3;
#if defined(__x86_64__)
map[mac++] = raidTP_ssse3ext;
map[mac++] = raidQP_ssse3ext;
map[mac++] = raidPP_ssse3ext;
map[mac++] = raidHP_ssse3ext;
map[mac++] = raidS3_ssse3ext;
map[mac++] = raidS4_ssse3ext;
map[mac++] = raidS5_ssse3ext;
map[mac++] = raidS6_ssse3ext;
#endif
}
#endif
} else {
#if defined(__i386__) || defined(__x86_64__)
map[mac++] = raidZ3_int32;
map[mac++] = raidZ3_int64;
if (cpu_has_sse2()) {
map[mac++] = raidZ3_sse2;
#if defined(__x86_64__)
map[mac++] = raidZ3_sse2ext;
#endif
}
#endif
}
#endif
/* check all the functions */
for(j=0;j<mac;++j) {
@ -272,8 +299,8 @@ static void gentest(unsigned diskmax, unsigned block_size)
map[j](buffer, diskmax, block_size);
/* check it */
for(i=0;i<LEV_MAX;++i) {
if (memcmp(buffer[diskmax + LEV_MAX + i], buffer[diskmax + i], block_size) != 0) {
for(i=0;i<level;++i) {
if (memcmp(buffer[diskmax + level + i], buffer[diskmax + i], block_size) != 0) {
fprintf(stderr, "Failed GEN test\n");
exit(EXIT_FAILURE);
}
@ -398,6 +425,9 @@ void selftest()
hashtest();
crc32ctest();
combotest();
gentest(32, 256);
recovtest(12, 256);
gentest(RAID_MODE_Z, 32, 256);
recovtest(RAID_MODE_Z, 12, 256);
gentest(RAID_MODE_S, 32, 256);
recovtest(RAID_MODE_S, 12, 256);
}

View file

@ -560,6 +560,9 @@ int main(int argc, char* argv[])
/* read the configuration file */
state_config(&state, conf, command, &opt, &filterlist_disk);
/* set the raid mode */
raid_set(state.raid_mode);
#if HAVE_LOCKFILE
/* create the lock file */
if (!opt.skip_lock) {

110
speed.c
View file

@ -327,33 +327,31 @@ void speed(void)
#endif
printf("\n");
/* RAIDTP */
printf("%8s", "raidTP");
printf("%8s", raidTP_tag());
/* RAIDZ3 */
printf("%8s", "raidZ3");
printf("%8s", raidZ3_tag());
fflush(stdout);
printf("%8s", "");
SPEED_START {
raidTP_int8(buffer, diskmax, block_size);
raidZ3_int32(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
printf("%8s", "");
printf("%8s", "");
SPEED_START {
raidZ3_int64(buffer, diskmax, block_size);
} SPEED_STOP
if (cpu_has_sse2()) {
printf("%8s", "");
#if defined(__x86_64__)
printf("%8s", "");
#endif
}
printf("%8"PRIu64, ds / dt);
fflush(stdout);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
if (cpu_has_sse2()) {
SPEED_START {
raidTP_ssse3(buffer, diskmax, block_size);
raidZ3_sse2(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -361,7 +359,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raidTP_ssse3ext(buffer, diskmax, block_size);
raidZ3_sse2ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -371,13 +369,13 @@ void speed(void)
#endif
printf("\n");
/* RAIDQP */
printf("%8s", "raidQP");
printf("%8s", raidQP_tag());
/* RAIDS3 */
printf("%8s", "raidS3");
printf("%8s", raidS3_tag());
fflush(stdout);
SPEED_START {
raidQP_int8(buffer, diskmax, block_size);
raidS3_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -397,7 +395,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
raidQP_ssse3(buffer, diskmax, block_size);
raidS3_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -405,7 +403,51 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raidQP_ssse3ext(buffer, diskmax, block_size);
raidS3_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
#endif
}
#endif
printf("\n");
/* RAIDS4 */
printf("%8s", "raidS4");
printf("%8s", raidS4_tag());
fflush(stdout);
SPEED_START {
raidS4_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
printf("%8s", "");
printf("%8s", "");
if (cpu_has_sse2()) {
printf("%8s", "");
#if defined(__x86_64__)
printf("%8s", "");
#endif
}
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
raidS4_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
#if defined(__x86_64__)
SPEED_START {
raidS4_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -415,13 +457,13 @@ void speed(void)
#endif
printf("\n");
/* RAIDPP */
printf("%8s", "raidPP");
printf("%8s", raidPP_tag());
/* RAIDS5 */
printf("%8s", "raidS5");
printf("%8s", raidS5_tag());
fflush(stdout);
SPEED_START {
raidPP_int8(buffer, diskmax, block_size);
raidS5_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -441,7 +483,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
raidPP_ssse3(buffer, diskmax, block_size);
raidS5_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -449,7 +491,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raidPP_ssse3ext(buffer, diskmax, block_size);
raidS5_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -459,13 +501,13 @@ void speed(void)
#endif
printf("\n");
/* RAIDHP */
printf("%8s", "raidHP");
printf("%8s", raidHP_tag());
/* RAIDS6 */
printf("%8s", "raidS6");
printf("%8s", raidS6_tag());
fflush(stdout);
SPEED_START {
raidHP_int8(buffer, diskmax, block_size);
raidS6_int8(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -485,7 +527,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
raidHP_ssse3(buffer, diskmax, block_size);
raidS6_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -493,7 +535,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raidHP_ssse3ext(buffer, diskmax, block_size);
raidS6_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);

21
state.c
View file

@ -58,10 +58,10 @@ const char* lev_raid_name(unsigned n)
switch (n) {
case 1 : return "raid5";
case 2 : return "raid6";
case 3 : return "raidTP";
case 4 : return "raidQP";
case 5 : return "raidPP";
case 6 : return "raidHP";
case 3 : return "raidS3";
case 4 : return "raidS4";
case 5 : return "raidS5";
case 6 : return "raidS6";
}
return 0;
@ -75,6 +75,7 @@ void state_init(struct snapraid_state* state)
state->autosave = 0;
state->need_write = 0;
state->block_size = 256 * 1024; /* default 256 KiB */
state->raid_mode = RAID_MODE_S;
for(l=0;l<LEV_MAX;++l) {
state->parity_path[l][0] = 0;
state->parity_device[l] = 0;
@ -117,6 +118,13 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
tommy_node* i;
unsigned l;
if (state->raid_mode == RAID_MODE_Z) {
if (state->level > RAID_PARITY_Z_MAX) {
fprintf(stderr, "If you use the z-parity you cannot have more than %u parities.\n", RAID_PARITY_Z_MAX);
exit(EXIT_FAILURE);
}
}
for(l=0;l<state->level;++l) {
if (state->parity_path[l][0] == 0) {
fprintf(stderr, "No '%s' specification in '%s'\n", lev_config_name(l), path);
@ -370,6 +378,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|| strcmp(tag, "s-parity") == 0
|| strcmp(tag, "t-parity") == 0
|| strcmp(tag, "u-parity") == 0
|| strcmp(tag, "z-parity") == 0
) {
char device[PATH_MAX];
char* slash;
@ -383,6 +392,10 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
case 's' : l = 3; break;
case 't' : l = 4; break;
case 'u' : l = 5; break;
case 'z' :
l = 2;
state->raid_mode = RAID_MODE_Z;
break;
default:
fprintf(stderr, "Invalid '%s' specification in '%s' at line %u\n", tag, path, line);
exit(EXIT_FAILURE);

View file

@ -87,6 +87,7 @@ struct snapraid_state {
uint64_t autosave; /**< Autosave after the specified amount of data. 0 to disable. */
int need_write; /**< If the state is changed. */
uint32_t block_size; /**< Block size in bytes. */
unsigned raid_mode; /**< Raid mode to use. RAID_MODE_DEFAULT or RAID_MODE_ALTERNATE. */
char parity_path[LEV_MAX][PATH_MAX]; /**< Path of the parity file. One for each parity. */
uint64_t parity_device[LEV_MAX]; /**< Device identifier of the parity. One for each parity. */
char pool[PATH_MAX]; /**< Path of the pool tree. */

114
tables.h
View file

@ -8796,6 +8796,120 @@ const unsigned char __attribute__((aligned(256))) gfinv[256] =
0x42, 0xd4, 0xe8, 0x75, 0x7f, 0xff, 0x7e, 0xfd,
};
/**
* Power matrix used to generate parity.
* This matrix is valid for up to 3 parity with 251 data disks.
*
* 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
* 01 02 04 08 10 20 40 80 1d 3a 74 e8 cd 87 13 26 4c 98 2d 5a b4 75 ea c9 8f 03 06 0c 18 30 60 c0 9d 27 4e 9c 25 4a 94 35 6a d4 b5 77 ee c1 9f 23 46 8c 05 0a 14 28 50 a0 5d ba 69 d2 b9 6f de a1 5f be 61 c2 99 2f 5e bc 65 ca 89 0f 1e 3c 78 f0 fd e7 d3 bb 6b d6 b1 7f fe e1 df a3 5b b6 71 e2 d9 af 43 86 11 22 44 88 0d 1a 34 68 d0 bd 67 ce 81 1f 3e 7c f8 ed c7 93 3b 76 ec c5 97 33 66 cc 85 17 2e 5c b8 6d da a9 4f 9e 21 42 84 15 2a 54 a8 4d 9a 29 52 a4 55 aa 49 92 39 72 e4 d5 b7 73 e6 d1 bf 63 c6 91 3f 7e fc e5 d7 b3 7b f6 f1 ff e3 db ab 4b 96 31 62 c4 95 37 6e dc a5 57 ae 41 82 19 32 64 c8 8d 07 0e 1c 38 70 e0 dd a7 53 a6 51 a2 59 b2 79 f2 f9 ef c3 9b 2b 56 ac 45 8a 09 12 24 48 90 3d 7a f4 f5 f7 f3 fb eb cb 8b 0b 16 2c 58 b0 7d fa e9 cf 83 1b 36 6c
* 01 04 10 40 1d 74 cd 13 4c 2d b4 ea 8f 06 18 60 9d 4e 25 94 6a b5 ee 9f 46 05 14 50 5d 69 b9 de 5f 61 99 5e 65 89 1e 78 fd d3 6b b1 fe df 5b 71 d9 43 11 44 0d 34 d0 67 81 3e f8 c7 3b ec 97 66 85 2e b8 da 4f 21 84 2a a8 9a 52 55 49 39 e4 b7 e6 bf c6 3f fc d7 7b f1 e3 ab 96 62 95 6e a5 ae 82 32 c8 07 1c 70 dd 53 51 59 79 f9 c3 2b ac 8a 12 48 3d f4 f7 fb cb 0b 2c b0 fa cf 1b 6c ad 8e 02 08 20 80 3a e8 87 26 98 5a 75 c9 03 0c 30 c0 27 9c 4a 35 d4 77 c1 23 8c 0a 28 a0 ba d2 6f a1 be c2 2f bc ca 0f 3c f0 e7 bb d6 7f e1 a3 b6 e2 af 86 22 88 1a 68 bd ce 1f 7c ed 93 76 c5 33 cc 17 5c 6d a9 9e 42 15 54 4d 29 a4 aa 92 72 d5 73 d1 63 91 7e e5 b3 f6 ff db 4b 31 c4 37 dc 57 41 19 64 8d 0e 38 e0 a7 a6 a2 b2 f2 ef 9b 56 45 09 24 90 7a f5 f3 eb 8b 16 58 7d e9
*/
const unsigned char __attribute__((aligned(256))) gfpower[3][256] =
{
{
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01,
},
{
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26,
0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9,
0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0,
0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35,
0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23,
0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0,
0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1,
0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc,
0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0,
0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f,
0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2,
0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88,
0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce,
0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93,
0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc,
0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9,
0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54,
0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa,
0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73,
0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e,
0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff,
0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4,
0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41,
0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e,
0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6,
0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef,
0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09,
0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5,
0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16,
0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83,
0x1b, 0x36, 0x6c,
},
{
0x01, 0x04, 0x10, 0x40, 0x1d, 0x74, 0xcd, 0x13,
0x4c, 0x2d, 0xb4, 0xea, 0x8f, 0x06, 0x18, 0x60,
0x9d, 0x4e, 0x25, 0x94, 0x6a, 0xb5, 0xee, 0x9f,
0x46, 0x05, 0x14, 0x50, 0x5d, 0x69, 0xb9, 0xde,
0x5f, 0x61, 0x99, 0x5e, 0x65, 0x89, 0x1e, 0x78,
0xfd, 0xd3, 0x6b, 0xb1, 0xfe, 0xdf, 0x5b, 0x71,
0xd9, 0x43, 0x11, 0x44, 0x0d, 0x34, 0xd0, 0x67,
0x81, 0x3e, 0xf8, 0xc7, 0x3b, 0xec, 0x97, 0x66,
0x85, 0x2e, 0xb8, 0xda, 0x4f, 0x21, 0x84, 0x2a,
0xa8, 0x9a, 0x52, 0x55, 0x49, 0x39, 0xe4, 0xb7,
0xe6, 0xbf, 0xc6, 0x3f, 0xfc, 0xd7, 0x7b, 0xf1,
0xe3, 0xab, 0x96, 0x62, 0x95, 0x6e, 0xa5, 0xae,
0x82, 0x32, 0xc8, 0x07, 0x1c, 0x70, 0xdd, 0x53,
0x51, 0x59, 0x79, 0xf9, 0xc3, 0x2b, 0xac, 0x8a,
0x12, 0x48, 0x3d, 0xf4, 0xf7, 0xfb, 0xcb, 0x0b,
0x2c, 0xb0, 0xfa, 0xcf, 0x1b, 0x6c, 0xad, 0x8e,
0x02, 0x08, 0x20, 0x80, 0x3a, 0xe8, 0x87, 0x26,
0x98, 0x5a, 0x75, 0xc9, 0x03, 0x0c, 0x30, 0xc0,
0x27, 0x9c, 0x4a, 0x35, 0xd4, 0x77, 0xc1, 0x23,
0x8c, 0x0a, 0x28, 0xa0, 0xba, 0xd2, 0x6f, 0xa1,
0xbe, 0xc2, 0x2f, 0xbc, 0xca, 0x0f, 0x3c, 0xf0,
0xe7, 0xbb, 0xd6, 0x7f, 0xe1, 0xa3, 0xb6, 0xe2,
0xaf, 0x86, 0x22, 0x88, 0x1a, 0x68, 0xbd, 0xce,
0x1f, 0x7c, 0xed, 0x93, 0x76, 0xc5, 0x33, 0xcc,
0x17, 0x5c, 0x6d, 0xa9, 0x9e, 0x42, 0x15, 0x54,
0x4d, 0x29, 0xa4, 0xaa, 0x92, 0x72, 0xd5, 0x73,
0xd1, 0x63, 0x91, 0x7e, 0xe5, 0xb3, 0xf6, 0xff,
0xdb, 0x4b, 0x31, 0xc4, 0x37, 0xdc, 0x57, 0x41,
0x19, 0x64, 0x8d, 0x0e, 0x38, 0xe0, 0xa7, 0xa6,
0xa2, 0xb2, 0xf2, 0xef, 0x9b, 0x56, 0x45, 0x09,
0x24, 0x90, 0x7a, 0xf5, 0xf3, 0xeb, 0x8b, 0x16,
0x58, 0x7d, 0xe9,
},
};
/**
* Cauchy matrix used to generate parity.
* This matrix is valid for up to 6 parity with 251 data disks.

4
util.c
View file

@ -1362,13 +1362,13 @@ void* malloc_nofail_align(size_t size, void** freeptr)
*
* RAID5 sse2x4 21936 [MB/s]
* RAID6 sse2x2 11902 [MB/s]
* RAIDTP sse2x1 5838 [MB/s]
* RAIDZ3 sse2x1 5838 [MB/s]
*
* Without displacement:
*
* RAID5 sse2x4 15368 [MB/s]
* RAID6 sse2x2 6814 [MB/s]
* RAIDTP sse2x1 3033 [MB/s]
* RAIDZ3 sse2x1 3033 [MB/s]
*/
#define MALLOC_DISPLACEMENT (7*256)