Adds SSSE3 and AVX parity computation.

This commit is contained in:
Andrea Mazzoleni 2013-10-06 16:06:17 +02:00
parent 1b46d03d70
commit 823bc8a8c0
8 changed files with 871 additions and 325 deletions

View file

@ -10,6 +10,8 @@ SnapRAID HISTORY
up to 89 disks with Hexa (6) parity is possible, but not yet implemented.
Note that more general approaches without these limitations are also
possible, but they would affect badly the performance.
Parity computation uses SSSE3 and AVX instructions if available for the
best performance.
* In sync, if a silent error is found, directly mark the block as bad
just like in scrub, and continue with the sync process.
* Sort files by inode when listing the directory. This improves
@ -20,6 +22,8 @@ SnapRAID HISTORY
of more info.
* For files with changes only in some blocks, updates the parity
only for blocks that really are changed.
This improves the performance in sync for edited files.
* Faster parity computation for ARM 64 bit CPU.
* Reduced memory usage avoiding to allocate unnecessary memory.
4.2 2013/10 (BETA)

18
cpu.h
View file

@ -91,6 +91,15 @@ static inline int cpu_has_sse2(void)
return (reg[3] >> 26) & 1;
}
static inline int cpu_has_ssse3(void)
{
uint32_t reg[4];
cpuid(1, reg);
return (reg[2] >> 9) & 1;
}
static inline int cpu_has_sse42(void)
{
uint32_t reg[4];
@ -100,6 +109,15 @@ static inline int cpu_has_sse42(void)
return (reg[2] >> 20) & 1;
}
static inline int cpu_has_avx(void)
{
uint32_t reg[4];
cpuid(1, reg);
return (reg[2] >> 28) & 1;
}
/**
* Check if the processor has a slow MULT implementation.
* If yes, it's better to use a hash not based on multiplication.

View file

@ -133,6 +133,53 @@ int main(void)
}
printf("};\n\n");
/* x4l */
printf("#define GFX4L { ");
for(i=0;i<16;++i) {
v = gfmul(0x4, i);
printf("0x%02x", (unsigned)v);
if (i != 15)
printf(", ");
}
printf(" }\n");
/* x4h */
printf("#define GFX4H { ");
for(i=0;i<16;++i) {
v = gfmul(0x40, i);
printf("0x%02x", (unsigned)v);
if (i != 15)
printf(", ");
}
printf(" }\n");
/* x8l */
printf("#define GFX8L { ");
for(i=0;i<16;++i) {
v = gfmul(0x8, i);
printf("0x%02x", (unsigned)v);
if (i != 15)
printf(", ");
}
printf(" }\n");
/* x8h */
printf("#define GFX8H { ");
for(i=0;i<16;++i) {
v = gfmul(0x80, i);
printf("0x%02x", (unsigned)v);
if (i != 15)
printf(", ");
}
printf(" }\n");
/* poly */
printf("#define GFPOLY8 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d } \n");
printf("#define GFPOLY16 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d } \n");
printf("#define GFMASK16 { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f } \n");
printf("\n");
return 0;
}

791
raid.c

File diff suppressed because it is too large Load diff

53
raid.h
View file

@ -78,30 +78,43 @@ void raid_recov_3data(int x, int y, int z, int i, int j, int k, unsigned char**
*/
void raid_recov_4data(int x, int y, int z, int v, int i, int j, int k, int l, unsigned char** vbuf, unsigned data, unsigned char* zero, unsigned size);
/**
* Gets the name of the selected function to compute parity.
*/
const char* raid5_tag(void);
const char* raid6_tag(void);
const char* raidTP_tag(void);
const char* raidQP_tag(void);
/**
* Internal specialized parity computation.
* Only for testing.
*/
void raid5_int32r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_int64r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_mmxr4(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_sse2r4(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_sse2r8(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_int32r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_int64r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_mmxr2(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_sse2r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_sse2r4(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_int32r2(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_int64r2(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_mmxr1(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_sse2r1(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_sse2r2(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_int32r2(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_int64r2(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_mmxr1(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_sse2r1(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_sse2r2(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_mmx(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_sse2(unsigned char** vbuf, unsigned data, unsigned size);
void raid5_sse2ext(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raid6_mmx(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_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_mmx(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_sse2(unsigned char** vbuf, unsigned data, unsigned size);
void raidTP_sse2ext(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_int32(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_int64(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_mmx(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_sse2(unsigned char** vbuf, unsigned data, unsigned size);
void raidQP_sse2ext(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 raidQP_avxext(unsigned char** vbuf, unsigned data, unsigned size);
#endif

View file

@ -335,33 +335,48 @@ static void gentest(unsigned diskmax, unsigned block_size)
/* load all the available functions */
mac = 0;
map[mac++] = raid5_int32r2;
map[mac++] = raid5_int64r2;
map[mac++] = raid6_int32r2;
map[mac++] = raid6_int64r2;
map[mac++] = raidTP_int32r2;
map[mac++] = raidTP_int64r2;
map[mac++] = raidQP_int32r2;
map[mac++] = raidQP_int64r2;
map[mac++] = raid5_int32;
map[mac++] = raid5_int64;
map[mac++] = raid6_int32;
map[mac++] = raid6_int64;
map[mac++] = raidTP_int32;
map[mac++] = raidTP_int64;
map[mac++] = raidQP_int32;
map[mac++] = raidQP_int64;
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
map[mac++] = raid5_mmxr4;
map[mac++] = raid6_mmxr2;
map[mac++] = raidQP_mmxr1;
map[mac++] = raidTP_mmxr1;
map[mac++] = raid5_mmx;
map[mac++] = raid6_mmx;
map[mac++] = raidQP_mmx;
map[mac++] = raidTP_mmx;
}
if (cpu_has_sse2()) {
map[mac++] = raid5_sse2r4;
map[mac++] = raid6_sse2r2;
map[mac++] = raidTP_sse2r1;
map[mac++] = raidQP_sse2r1;
map[mac++] = raid5_sse2;
map[mac++] = raid6_sse2;
map[mac++] = raidTP_sse2;
map[mac++] = raidQP_sse2;
#if defined(__x86_64__)
map[mac++] = raid5_sse2r8;
map[mac++] = raid6_sse2r4;
map[mac++] = raidTP_sse2r2;
map[mac++] = raidQP_sse2r2;
map[mac++] = raid5_sse2ext;
map[mac++] = raid6_sse2ext;
map[mac++] = raidTP_sse2ext;
map[mac++] = raidQP_sse2ext;
#endif
}
if (cpu_has_ssse3()) {
map[mac++] = raidTP_ssse3;
map[mac++] = raidQP_ssse3;
#if defined(__x86_64__)
map[mac++] = raidTP_ssse3ext;
map[mac++] = raidQP_ssse3ext;
#endif
}
if (cpu_has_avx()) {
#if defined(__x86_64__)
map[mac++] = raidQP_avxext;
#endif
}
#endif

220
speed.c
View file

@ -89,9 +89,12 @@ void speed(void)
cpu_info(vendor, &family, &model);
printf("CPU %s, family %u, model %u, flags%s%s%s\n", vendor, family, model,
printf("CPU %s, family %u, model %u, flags%s%s%s%s%s%s\n", vendor, family, model,
cpu_has_mmx() ? " mmx" : "",
cpu_has_sse2() ? " sse2" : "",
cpu_has_ssse3() ? " ssse3" : "",
cpu_has_sse42() ? " sse42" : "",
cpu_has_avx() ? " avx" : "",
cpu_has_slowmult() ? " slowmult" : ""
);
}
@ -130,93 +133,10 @@ void speed(void)
#endif
printf("\n");
printf("Expected fastest RAID5 is ");
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_sse2()) {
#if defined(__x86_64__)
if (cpu_has_slowextendedreg())
printf("sse2x4");
else
printf("sse2x8");
#else
printf("sse2x4");
#endif
} else if (cpu_has_mmx())
printf("mmxx4");
else
printf("int32x2");
#else
if (sizeof(void*) == 4)
printf("int32x2");
else
printf("int64x2");
#endif
printf("\n");
printf("Expected fastest RAID6 is ");
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_sse2()) {
#if defined(__x86_64__)
if (cpu_has_slowextendedreg())
printf("sse2x2");
else
printf("sse2x4");
#else
printf("sse2x2");
#endif
} else if (cpu_has_mmx())
printf("mmxx2");
else
printf("int32x2");
#else
if (sizeof(void*) == 4)
printf("int32x2");
else
printf("int64x2");
#endif
printf("\n");
printf("Expected fastest RAIDTP is ");
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_sse2())
#if defined(__x86_64__)
printf("sse2x2");
#else
printf("sse2x1");
#endif
else if (cpu_has_mmx())
printf("mmxx1");
else
printf("int32x2");
#else
if (sizeof(void*) == 4)
printf("int32x2");
else
printf("int64x2");
#endif
printf("\n");
printf("Expected fastest RAIDQP is ");
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_sse2())
#if defined(__x86_64__)
printf("sse2x2");
#else
printf("sse2x1");
#endif
else if (cpu_has_mmx())
printf("mmxx1");
else
printf("int32x2");
#else
if (sizeof(void*) == 4)
printf("int32x2");
else
printf("int64x2");
#endif
printf("\n");
printf("Expected fastest RAID5 is %s\n", raid5_tag());
printf("Expected fastest RAID6 is %s\n", raid6_tag());
printf("Expected fastest RAIDTP is %s\n", raidTP_tag());
printf("Expected fastest RAIDQP is %s\n", raidQP_tag());
printf("If these expectations are false, please report it in the SnapRAID forum\n");
@ -268,135 +188,151 @@ void speed(void)
printf("HASH Spooky2 %"PRIu64" [MB/s]\n", ds / dt);
SPEED_START {
raid5_int32r2(buffer, diskmax, block_size);
raid5_int32(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID5 int32x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID5 int32 %"PRIu64" [MB/s]\n", ds / dt);
SPEED_START {
raid5_int64r2(buffer, diskmax, block_size);
raid5_int64(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID5 int64x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID5 int64 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
SPEED_START {
raid5_mmxr4(buffer, diskmax, block_size);
raid5_mmx(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID5 mmxx4 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID5 mmx %"PRIu64" [MB/s]\n", ds / dt);
}
if (cpu_has_sse2()) {
SPEED_START {
raid5_sse2r4(buffer, diskmax, block_size);
raid5_sse2(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID5 sse2x4 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID5 sse2 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raid5_sse2r8(buffer, diskmax, block_size);
raid5_sse2ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID5 sse2x8 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID5 sse2ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
#endif
SPEED_START {
raid6_int32r2(buffer, diskmax, block_size);
raid6_int32(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID6 int32x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID6 int32 %"PRIu64" [MB/s]\n", ds / dt);
SPEED_START {
raid6_int64r2(buffer, diskmax, block_size);
raid6_int64(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID6 int64x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID6 int64 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
SPEED_START {
raid6_mmxr2(buffer, diskmax, block_size);
raid6_mmx(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID6 mmxx2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID6 mmx %"PRIu64" [MB/s]\n", ds / dt);
}
if (cpu_has_sse2()) {
SPEED_START {
raid6_sse2r2(buffer, diskmax, block_size);
raid6_sse2(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID6 sse2x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID6 sse2 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raid6_sse2r4(buffer, diskmax, block_size);
raid6_sse2ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAID6 sse2x4 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAID6 sse2ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
#endif
SPEED_START {
raidTP_int32r2(buffer, diskmax, block_size);
raidTP_int32(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP int32x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP int32 %"PRIu64" [MB/s]\n", ds / dt);
SPEED_START {
raidTP_int64r2(buffer, diskmax, block_size);
raidTP_int64(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP int64x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP int64 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
SPEED_START {
raidTP_mmxr1(buffer, diskmax, block_size);
raidTP_mmx(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP mmxr1 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP mmx %"PRIu64" [MB/s]\n", ds / dt);
}
if (cpu_has_sse2()) {
SPEED_START {
raidTP_sse2r1(buffer, diskmax, block_size);
raidTP_sse2(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP sse2x1 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP sse2 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raidTP_sse2r2(buffer, diskmax, block_size);
raidTP_sse2ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP sse2x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP sse2ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
#endif
SPEED_START {
raidQP_int32r2(buffer, diskmax, block_size);
} SPEED_STOP
if (cpu_has_ssse3()) {
SPEED_START {
raidTP_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP int32x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDTP ssse3 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raidTP_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDTP ssse3ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
SPEED_START {
raidQP_int64r2(buffer, diskmax, block_size);
raidQP_int32(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP int64x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDQP int32 %"PRIu64" [MB/s]\n", ds / dt);
SPEED_START {
raidQP_int64(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP int64 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_mmx()) {
SPEED_START {
raidQP_mmxr1(buffer, diskmax, block_size);
raidQP_mmx(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP mmxr1 %"PRIu64" [MB/s]\n", ds / dt);
@ -404,21 +340,47 @@ void speed(void)
if (cpu_has_sse2()) {
SPEED_START {
raidQP_sse2r1(buffer, diskmax, block_size);
raidQP_sse2(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP sse2x1 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDQP sse2 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raidQP_sse2r2(buffer, diskmax, block_size);
raidQP_sse2ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP sse2x2 %"PRIu64" [MB/s]\n", ds / dt);
printf("RAIDQP sse2ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
#endif
if (cpu_has_ssse3()) {
SPEED_START {
raidQP_ssse3(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP ssse3 %"PRIu64" [MB/s]\n", ds / dt);
#if defined(__x86_64__)
SPEED_START {
raidQP_ssse3ext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP ssse3ext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
if (cpu_has_avx()) {
#if defined(__x86_64__)
SPEED_START {
raidQP_avxext(buffer, diskmax, block_size);
} SPEED_STOP
printf("RAIDQP avxext %"PRIu64" [MB/s]\n", ds / dt);
#endif
}
free(buffer_alloc);
free(buffer);
}

View file

@ -8868,3 +8868,11 @@ const unsigned char __attribute__((aligned(256))) gfinv[256] =
0x42, 0xd4, 0xe8, 0x75, 0x7f, 0xff, 0x7e, 0xfd,
};
#define GFX4L { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c }
#define GFX4H { 0x00, 0x40, 0x80, 0xc0, 0x1d, 0x5d, 0x9d, 0xdd, 0x3a, 0x7a, 0xba, 0xfa, 0x27, 0x67, 0xa7, 0xe7 }
#define GFX8L { 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78 }
#define GFX8H { 0x00, 0x80, 0x1d, 0x9d, 0x3a, 0xba, 0x27, 0xa7, 0x74, 0xf4, 0x69, 0xe9, 0x4e, 0xce, 0x53, 0xd3 }
#define GFPOLY8 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d }
#define GFPOLY16 { 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d }
#define GFMASK16 { 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f }