Finalizes alternate triple parity support.

This commit is contained in:
Andrea Mazzoleni 2013-11-05 19:40:32 +01:00
parent a762c30a46
commit bb0cd0e7ac
8 changed files with 177 additions and 63 deletions

View file

@ -3,10 +3,11 @@ SnapRAID HISTORY
5.0 2013/11 (BETA)
==================
* Added support for up to six level of parity. Take care that to get
good performance for triple parity and beyond you need a CPU with
SSSE3 support.
* Faster RAID5 and RAID6 computation for ARM 64 bit CPUs.
* Added support for up to six level of parity.
* Added a specific and faster triple parity format for CPUs that
don't support SSSE3 instructions like ARM and AMD Phenom, Athlon
and Opteron.
* Faster RAID5 and RAID6 implementation for ARM 64 bit CPUs.
* In sync, if a silent error is found, directly mark the block as bad
like in scrub, and continue with the sync process.
* Sort files by inode when listing the directory. This improves

2
raid.c
View file

@ -739,7 +739,7 @@ void raidZ3_sse2ext(unsigned char** vbuf, unsigned data, unsigned size)
q = vbuf[data+1];
r = vbuf[data+2];
asm volatile("movdqa %0,%%xmm7" : : "m" (raid_16_const.poly[0]));
asm volatile("movdqa %0,%%xmm7" : : "m" (gfconst16.poly[0]));
for(i=0;i<size;i+=32) {
asm volatile("movdqa %0,%%xmm0" : : "m" (vbuf[l][i]));

View file

@ -103,9 +103,9 @@ static void recovtest(unsigned mode, unsigned diskmax, unsigned block_size)
raid_set(mode);
if (mode == RAID_MODE_S)
level = LEV_MAX;
level = RAID_PARITY_S_MAX;
else
level = 3;
level = RAID_PARITY_Z_MAX;
buffermax = diskmax + level * 2 + 2;
@ -222,9 +222,9 @@ static void gentest(unsigned mode, unsigned diskmax, unsigned block_size)
raid_set(mode);
if (mode == RAID_MODE_S)
level = LEV_MAX;
level = RAID_PARITY_S_MAX;
else
level = 3;
level = RAID_PARITY_Z_MAX;
buffermax = diskmax + level * 2;

View file

@ -809,6 +809,26 @@ Leaving the parity disks reserved for only these files ensures that
they doesn\(cqt get fragmented, improving the performance.
.PP
These options are optional and they can be used only one time.
.SS z\(hyparity FILE
Defines an alternate file and format to store the triple parity,
instead of the other \(cqr\(hyparity\(cq one.
.PP
It\(cqs mainly intended for low end CPUs like ARM or AMD Phenom, Athlon
and Opteron that don\(cqt support the SSSE3 instructions set, and in
such case it may provide better performance.
.PP
This is also the parity format used by ZFS, but it doesn\(cqt work
for beyond triple parity.
.PP
If you are using the \(cqr\(hyparity\(cq you will be warned if it\(cqs
recommended to use the \(cqz\(hyparity\(cq format for a performance
increase.
.PP
It\(cqs possible to convert from one format to another, adjusting
the configuraton file with the wanted z\(hyparity or r\(hyparity file,
and using \(cqfix\(cq to recreate it.
.PP
This option is alternative to \(cqr\(hyparity\(cq.
.SS content FILE
Defines the file to use to store the list and checksums of all the
files present in your disk array.

View file

@ -602,6 +602,27 @@ Configuration
These options are optional and they can be used only one time.
z-parity FILE
Defines an alternate file and format to store the triple parity,
instead of the other 'r-parity' one.
It's mainly intended for low end CPUs like ARM or AMD Phenom, Athlon
and Opteron that don't support the SSSE3 instructions set, and in
such case it may provide better performance.
This is also the parity format used by ZFS, but it doesn't work
for beyond triple parity.
If you are using the 'r-parity' you will be warned if it's
recommended to use the 'z-parity' format for a performance
increase.
It's possible to convert from one format to another, adjusting
the configuraton file with the wanted z-parity or r-parity file,
and using 'fix' to recreate it.
This option is alternative to 'r-parity'.
content FILE
Defines the file to use to store the list and checksums of all the
files present in your disk array.

View file

@ -656,7 +656,30 @@ they doesn't get fragmented, improving the performance.
These options are optional and they can be used only one time.
7.3 content FILE
7.3 z-parity FILE
-----------------
Defines an alternate file and format to store the triple parity,
instead of the other 'r-parity' one.
It's mainly intended for low end CPUs like ARM or AMD Phenom, Athlon
and Opteron that don't support the SSSE3 instructions set, and in
such case it may provide better performance.
This is also the parity format used by ZFS, but it doesn't work
for beyond triple parity.
If you are using the 'r-parity' you will be warned if it's
recommended to use the 'z-parity' format for a performance
increase.
It's possible to convert from one format to another, adjusting
the configuraton file with the wanted z-parity or r-parity file,
and using 'fix' to recreate it.
This option is alternative to 'r-parity'.
7.4 content FILE
----------------
Defines the file to use to store the list and checksums of all the
@ -673,7 +696,7 @@ more copies of the same files.
You have to store at least one copy for each parity disk used
plus one. Using some more don't hurt.
7.4 disk NAME DIR
7.5 disk NAME DIR
-----------------
Defines the name and the mount point of the disks of the array.
@ -685,14 +708,14 @@ keep the NAME fixed.
You should use one option for each disk of the array.
7.5 nohidden
7.6 nohidden
------------
Excludes all the hidden files and directory.
In Unix hidden files are the ones starting with ".".
In Windows they are the ones with the hidden attribute.
7.6 exclude/include PATTERN
7.7 exclude/include PATTERN
---------------------------
Defines the file or directory patterns to exclude and include
@ -710,7 +733,7 @@ specifications.
This option can be used many times.
7.7 block_size SIZE_IN_KIBIBYTES
7.8 block_size SIZE_IN_KIBIBYTES
--------------------------------
Defines the basic block size in kibi bytes of the redundancy
@ -741,7 +764,7 @@ wasted for each file.
For example, with 10000 files and a 256 KiB block size, you are
going to waste 1.2 GiB.
---- 7.7.1 autosave SIZE_IN_GIBIBYTES ----
---- 7.8.1 autosave SIZE_IN_GIBIBYTES ----
Automatically save the state when synching after the specied amount
of GiB processed.
This option is useful to avoid to restart from scratch long "sync"
@ -750,12 +773,12 @@ may interrupt SnapRAID.
The SIZE argument is specified in gibibytes. Where one gibi bytes
is 1073741824 bytes.
---- 7.7.2 pool DIR ----
---- 7.8.2 pool DIR ----
Defines the pooling directory where the virtual view of the disk
array is created using the "pool" command.
The directory must already exist.
7.8 Examples
7.9 Examples
------------
An example of a typical configuration for Unix is:

107
speed.c
View file

@ -110,15 +110,16 @@ void speed(void)
cpu_info(vendor, &family, &model);
printf("CPU %s, family %u, model %u, flags%s%s%s%s%s%s%s\n", vendor, family, model,
printf("CPU %s, family %u, model %u, flags%s%s%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_avx2() ? "avx2" : "",
cpu_has_slowmult() ? " slowmult" : "",
cpu_has_slowpshufb() ? " slowpshufb" : ""
);
);
}
#else
printf("CPU is not a x86/x64\n");
@ -568,14 +569,18 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<diskmax;++j) {
/* +1 to avoid RAID5 optimized case */
raid_recov1_ssse3(1, d, e + 1, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
/* +1 to avoid RAID5 optimized case */
raid_recov1_ssse3(1, d, e + 1, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("%8s", "recov2");
@ -592,14 +597,18 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<diskmax;++j) {
/* +1 to avoid RAID6 optimized case */
raid_recov2_ssse3(2, d, e + 1, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
/* +1 to avoid RAID6 optimized case */
raid_recov2_ssse3(2, d, e + 1, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("%8s", "recov3");
@ -615,13 +624,17 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(3, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(3, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("%8s", "recov4");
@ -637,13 +650,17 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(4, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(4, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("%8s", "recov5");
@ -658,14 +675,18 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(5, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(5, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("%8s", "recov6");
@ -681,13 +702,17 @@ void speed(void)
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(6, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
#if defined(__i386__) || defined(__x86_64__)
if (cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<diskmax;++j) {
raid_recovX_ssse3(6, d, e, buffer, diskmax, zero, block_size);
}
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
printf("%8"PRIu64, ds / dt);
}
#endif
printf("\n");
printf("\n");

34
state.c
View file

@ -53,12 +53,15 @@ const char* lev_config_name(unsigned l)
return 0;
}
const char* lev_raid_name(unsigned n)
const char* lev_raid_name(unsigned mode, unsigned n)
{
switch (n) {
case 1 : return "raid5";
case 2 : return "raid6";
case 3 : return "raidS3";
case 3 : if (mode == RAID_MODE_S)
return "raidS3";
else
return "raidZ3";
case 4 : return "raidS4";
case 5 : return "raidS5";
case 6 : return "raidS6";
@ -118,6 +121,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
tommy_node* i;
unsigned l;
/* check for parity level */
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);
@ -275,11 +279,18 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
}
}
/* check for speed */
#if defined(__i386__) || defined(__x86_64__)
if (!cpu_has_ssse3())
#endif
if (state->level > 2) {
fprintf(stderr, "WARNING! Your CPU doesn't have a fast implementation beyond RAID6.\n");
if (state->raid_mode == RAID_MODE_S) {
if (state->level == 3) {
fprintf(stderr, "WARNING! Your CPU doesn't have a fast implementation for triple parity.\n");
fprintf(stderr, "WARNING! It's recommended to switch to 'z-parity' instead than 'r-parity'.\n");
} else if (state->level > 3) {
fprintf(stderr, "WARNING! Your CPU doesn't have a fast implementation beyond triple parity.\n");
fprintf(stderr, "WARNING! It's recommended to reduce the parity levels to triple parity.\n");
}
}
/* ensure that specified filter disks are valid ones */
@ -696,7 +707,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
fprintf(stdlog, "disk:%s:%s\n", disk->name, disk->dir);
}
fprintf(stdlog, "mode:%s\n", lev_raid_name(state->level));
fprintf(stdlog, "mode:%s\n", lev_raid_name(state->raid_mode, state->level));
for(l=0;l<state->level;++l)
fprintf(stdlog, "%s:%s\n", lev_config_name(l), state->parity_path[l]);
if (state->pool[0] != 0)
@ -861,6 +872,19 @@ static void state_map(struct snapraid_state* state)
fprintf(stderr, "Too few data disks. You must define at least %u.\n", RAID_DATA_MIN);
exit(EXIT_FAILURE);
}
/* recommend number of parities */
if (diskcount >= 34 && state->level < 6) {
fprintf(stderr, "WARNING! With %u disks it's recommended to use six parity levels.\n", diskcount);
} else if (diskcount >= 27 && state->level < 5) {
fprintf(stderr, "WARNING! With %u disks it's recommended to use five parity levels.\n", diskcount);
} else if (diskcount >= 20 && state->level < 4) {
fprintf(stderr, "WARNING! With %u disks it's recommended to use four parity leveles.\n", diskcount);
} else if (diskcount >= 13 && state->level < 3) {
fprintf(stderr, "WARNING! With %u disks it's recommended to use three parity levels.\n", diskcount);
} else if (diskcount >= 6 && state->level < 2) {
fprintf(stderr, "WARNING! With %u disks it's recommended to use two parity levels.\n", diskcount);
}
}
/**