Moves RAID tests in the raid/ dir.

This commit is contained in:
Andrea Mazzoleni 2013-12-29 22:13:08 +01:00
parent eb08995834
commit 03482b84a6
16 changed files with 943 additions and 612 deletions

View file

@ -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

View file

@ -24,7 +24,7 @@
#include "parity.h"
#include "handle.h"
#include "raid/raid.h"
#include "combo.h"
#include "raid/combo.h"
/****************************************************************************/
/* check */

90
combo.h
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef __COMBO_H
#define __COMBO_H
#include <assert.h>
/**
* 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]<N-(R-1);++i[0])
* for(i[1]=i[0]+1;i[1]<N-(R-2);++i[1])
* ...
* for(i[R-2]=i[R-3]+1;i[R-2]<N-1;++i[R-2])
* for(i[R-1]=i[R-2]+1;i[R-1]<N;++i[R-1])
* code using i[0], i[1], ..., i[R-1]
*/
static inline void combination_first(unsigned r, unsigned n, int* c)
{
unsigned i;
(void)n; /* unused, but kept for clarity */
assert(0 < r && r <= n);
for(i=0;i<r;++i)
c[i] = i;
}
/**
* Get the next combination of r of n elements.
* Return ==0 when finished.
*/
static inline int combination_next(unsigned r, unsigned n, int* c)
{
unsigned i = r - 1; /* present position */
int h = n; /* high limit for this position */
recurse:
/* next element at position i */
++c[i];
/* if the position has reached the max */
if (c[i] >= 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

158
raid/combo.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef __COMBO_H
#define __COMBO_H
#include <assert.h>
/**
* 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;++i[0])
* for(i[1]=0;i[1]<N;++i[1])
* ...
* for(i[R-2]=0;i[R-2]<N;++i[R-2])
* for(i[R-1]=0;i[R-1]<N;++i[R-1])
* code using i[0], i[1], ..., i[R-1]
*/
static inline void permutation_first(int r, int n, int *c)
{
int i;
(void)n; /* unused, but kept for clarity */
assert(0 < r && r <= n);
for (i = 0; i < r; ++i)
c[i] = 0;
}
/**
* Get the next permutation with repetition of r of n elements.
* Return ==0 when finished.
*/
static inline int permutation_next(int r, int n, int *c)
{
int i = r - 1; /* present position */
recurse:
/* next element at position i */
++c[i];
/* if the position has reached the max */
if (c[i] >= 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]<N-(R-1);++i[0])
* for(i[1]=i[0]+1;i[1]<N-(R-2);++i[1])
* ...
* for(i[R-2]=i[R-3]+1;i[R-2]<N-1;++i[R-2])
* for(i[R-1]=i[R-2]+1;i[R-1]<N;++i[R-1])
* code using i[0], i[1], ..., i[R-1]
*/
static inline void combination_first(int r, int n, int *c)
{
int i;
(void)n; /* unused, but kept for clarity */
assert(0 < r && r <= n);
for (i = 0; i < r; ++i)
c[i] = i;
}
/**
* Get the next combination without repetition of r of n elements.
* Return ==0 when finished.
*/
static inline int combination_next(int r, int n, int *c)
{
int i = r - 1; /* present position */
int h = n; /* high limit for this position */
recurse:
/* next element at position i */
++c[i];
/* if the position has reached the max */
if (c[i] >= 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

View file

@ -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.
*/

View file

@ -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;

View file

@ -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"
/*

125
raid/memory.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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();
}

80
raid/memory.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -44,7 +44,6 @@
/**
* Maximum number of data disks.
* Limit of the parity generator matrix used.
*/
#define RAID_DATA_MAX 251

331
raid/test.c Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
}

62
raid/test.h Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View file

@ -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;

View file

@ -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;i<np;++i)
parity_save[i] = parity[i];
zero = buffer[buffermax-2];
memset(zero, 0, block_size);
raid_zero(zero);
waste = buffer[buffermax-1];
/* fill data disk with random */
mrand_vector(buffer, nd, block_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, block_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, block_size, buffer);
/* check */
for(i=0;i<nr;++i) {
if (memcmp(test[i], data_save[i], block_size) != 0) {
fprintf(stderr, "Failed RECOV test\n");
exit(EXIT_FAILURE);
}
}
/* 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);
}
static void gentest(unsigned mode, unsigned nd, unsigned block_size)
{
void* buffer_alloc;
void** buffer;
unsigned buffermax;
unsigned i, j;
void (*map[64])(int nd, size_t size, void** vbuf);
unsigned mac;
unsigned np;
raid_mode(mode);
if (mode == RAID_MODE_CAUCHY)
np = RAID_PARITY_MAX;
else
np = 3;
buffermax = nd + np * 2;
buffer = malloc_nofail_vector_align(nd, buffermax, block_size, &buffer_alloc);
mtest_vector(buffer, buffermax, block_size);
/* fill with random */
mrand_vector(buffer, buffermax, block_size);
/* compute the parity */
raid_par(nd, np, block_size, buffer);
/* copy in back buffers */
for(i=0;i<np;++i)
memcpy(buffer[nd + np + i], buffer[nd + i], block_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, block_size, buffer);
/* check it */
for(i=0;i<np;++i) {
if (memcmp(buffer[nd + np + i], buffer[nd + i], block_size) != 0) {
fprintf(stderr, "Failed GEN test\n");
exit(EXIT_FAILURE);
}
}
}
free(buffer_alloc);
free(buffer);
}
#define HASH_TEST_MAX 512 /* tests are never longer than 512 bytes */
static void hashtest(void)
static void test_hash(void)
{
unsigned i;
unsigned char* seed_aligned;
@ -391,7 +133,7 @@ static struct crc_test_vector TEST_CRC32C[] = {
{ 0, 0, 0 }
};
static void crc32ctest(void)
static void test_crc32c(void)
{
unsigned i;
@ -405,7 +147,7 @@ static void crc32ctest(void)
}
}
void selftest()
void selftest(void)
{
fprintf(stdlog, "selftest:\n");
fflush(stdlog);
@ -418,13 +160,35 @@ void selftest()
exit(EXIT_FAILURE);
}
hashtest();
crc32ctest();
combotest();
gentest(RAID_MODE_VANDERMONDE, 32, 256);
recovtest(RAID_MODE_VANDERMONDE, 12, 256);
gentest(RAID_MODE_CAUCHY, 32, 256);
recovtest(RAID_MODE_CAUCHY, 12, 256);
gentest(RAID_MODE_CAUCHY, 1, 256);
test_hash();
test_crc32c();
if (raid_test_sort() != 0) {
fprintf(stderr, "Failed SORT test\n");
exit(EXIT_FAILURE);
}
if (raid_test_combo() != 0) {
fprintf(stderr, "Failed COMBO test\n");
exit(EXIT_FAILURE);
}
if (raid_test_par(RAID_MODE_VANDERMONDE, 32, 256) != 0) {
fprintf(stderr, "Failed PAR Vandermonde test\n");
exit(EXIT_FAILURE);
}
if (raid_test_rec(RAID_MODE_VANDERMONDE, 12, 256) != 0) {
fprintf(stderr, "Failed REC Vandermonde test\n");
exit(EXIT_FAILURE);
}
if (raid_test_par(RAID_MODE_CAUCHY, 32, 256) != 0) {
fprintf(stderr, "Failed PAR Cauchy test\n");
exit(EXIT_FAILURE);
}
if (raid_test_rec(RAID_MODE_CAUCHY, 12, 256) != 0) {
fprintf(stderr, "Failed REC Cauchy test\n");
exit(EXIT_FAILURE);
}
if (raid_test_par(RAID_MODE_CAUCHY, 1, 256) != 0) {
fprintf(stderr, "Failed PAR Cauchy test sigle data disk\n");
exit(EXIT_FAILURE);
}
}

189
speed.c
View file

@ -27,9 +27,14 @@
/**
* Differential us of two timeval.
*/
static int64_t diffgettimeofday(struct timeval* start, struct timeval* stop)
static int64_t diffgettimeofday(struct timeval *start, struct timeval *stop)
{
return 1000000LL * (stop->tv_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;i<nd;++i) {
memset(buffer[i], i, block_size);
}
for(i=0;i<nd;++i)
memset(v[i], i, size);
/* zero buffer */
zero = buffer[nd+LEV_MAX];
memset(zero, 0, block_size);
/* zero v */
zero = v[nd+LEV_MAX];
memset(zero, 0, size);
raid_zero(zero);
/* hash seed */
for(i=0;i<HASH_SIZE;++i) {
for(i=0;i<HASH_SIZE;++i)
seed[i] = i;
}
/* basic disks and parity mapping */
for(i=0;i<LEV_MAX;++i) {
@ -127,9 +129,9 @@ void speed(void)
printf("CPU is not a x86/x64\n");
#endif
#if WORDS_BIGENDIAN
printf("Memory is big-endian %u-bit\n", (unsigned)sizeof(void*) * 8);
printf("Memory is big-endian %d-bit\n", (int)sizeof(void*) * 8);
#else
printf("Memory is little-endian %u-bit\n", (unsigned)sizeof(void*) * 8);
printf("Memory is little-endian %d-bit\n", (int)sizeof(void*) * 8);
#endif
#if HAVE_FUTIMENS
@ -144,8 +146,8 @@ void speed(void)
printf("\n");
printf("Speed test using %u buffers of %u bytes, for a total of %u KiB.\n", nd, block_size, nd * block_size / 1024);
printf("The reported value is the sustainable aggregate bandwidth of all data disks in MiB/s (not counting parity disks).\n");
printf("Speed test using %u data buffers of %u bytes, for a total of %u KiB.\n", nd, size, nd * size / 1024);
printf("The reported value is the aggregate bandwidth of all data disks in MiB/s (not counting parity disks).\n");
printf("\n");
printf("Memory write speed using the C memset() function:\n");
@ -153,9 +155,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
memset(buffer[j], j, block_size);
}
for(j=0;j<nd;++j)
memset(v[j], j, size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -169,9 +170,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
crc32c_gen(0, buffer[j], block_size);
}
for(j=0;j<nd;++j)
crc32c_gen(0, v[j], size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -183,9 +183,8 @@ void speed(void)
#if HAVE_CRC32B
if (raid_cpu_has_sse42()) {
SPEED_START {
for(j=0;j<nd;++j) {
crc32c_x86(0, buffer[j], block_size);
}
for(j=0;j<nd;++j)
crc32c_x86(0, v[j], size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -218,18 +217,16 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
memhash(HASH_MURMUR3, seed, digest, buffer[j], block_size);
}
for(j=0;j<nd;++j)
memhash(HASH_MURMUR3, seed, digest, v[j], size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
memhash(HASH_SPOOKY2, seed, digest, buffer[j], block_size);
}
for(j=0;j<nd;++j)
memhash(HASH_SPOOKY2, seed, digest, v[j], size);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -263,14 +260,14 @@ void speed(void)
printf("%8s", "");
SPEED_START {
raid_par1_int32(nd, block_size, buffer);
raid_par1_int32(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
raid_par1_int64(nd, block_size, buffer);
raid_par1_int64(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -279,7 +276,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_sse2()) {
SPEED_START {
raid_par1_sse2(nd, block_size, buffer);
raid_par1_sse2(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -296,14 +293,14 @@ void speed(void)
printf("%8s", "");
SPEED_START {
raid_par2_int32(nd, block_size, buffer);
raid_par2_int32(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
raid_par2_int64(nd, block_size, buffer);
raid_par2_int64(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -312,7 +309,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_sse2()) {
SPEED_START {
raid_par2_sse2(nd, block_size, buffer);
raid_par2_sse2(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -320,7 +317,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_par2_sse2ext(nd, block_size, buffer);
raid_par2_sse2ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -338,14 +335,14 @@ void speed(void)
printf("%8s", "");
SPEED_START {
raid_parz_int32(nd, block_size, buffer);
raid_parz_int32(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
fflush(stdout);
SPEED_START {
raid_parz_int64(nd, block_size, buffer);
raid_parz_int64(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -354,7 +351,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_sse2()) {
SPEED_START {
raid_parz_sse2(nd, block_size, buffer);
raid_parz_sse2(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -362,7 +359,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_parz_sse2ext(nd, block_size, buffer);
raid_parz_sse2ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -378,7 +375,7 @@ void speed(void)
fflush(stdout);
SPEED_START {
raid_par3_int8(nd, block_size, buffer);
raid_par3_int8(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -398,7 +395,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
raid_par3_ssse3(nd, block_size, buffer);
raid_par3_ssse3(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -406,7 +403,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_par3_ssse3ext(nd, block_size, buffer);
raid_par3_ssse3ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -422,7 +419,7 @@ void speed(void)
fflush(stdout);
SPEED_START {
raid_par4_int8(nd, block_size, buffer);
raid_par4_int8(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -442,7 +439,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
raid_par4_ssse3(nd, block_size, buffer);
raid_par4_ssse3(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -450,7 +447,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_par4_ssse3ext(nd, block_size, buffer);
raid_par4_ssse3ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -466,7 +463,7 @@ void speed(void)
fflush(stdout);
SPEED_START {
raid_par5_int8(nd, block_size, buffer);
raid_par5_int8(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -486,7 +483,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
raid_par5_ssse3(nd, block_size, buffer);
raid_par5_ssse3(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -494,7 +491,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_par5_ssse3ext(nd, block_size, buffer);
raid_par5_ssse3ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -510,7 +507,7 @@ void speed(void)
fflush(stdout);
SPEED_START {
raid_par6_int8(nd, block_size, buffer);
raid_par6_int8(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -530,7 +527,7 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
raid_par6_ssse3(nd, block_size, buffer);
raid_par6_ssse3(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -538,7 +535,7 @@ void speed(void)
#if defined(__x86_64__)
SPEED_START {
raid_par6_ssse3ext(nd, block_size, buffer);
raid_par6_ssse3ext(nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -562,10 +559,9 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
for(j=0;j<nd;++j)
/* +1 to avoid PAR1 optimized case */
raid_rec1_int8(1, id, ip + 1, nd, block_size, buffer);
}
raid_rec1_int8(1, id, ip + 1, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -574,10 +570,9 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
for(j=0;j<nd;++j)
/* +1 to avoid PAR1 optimized case */
raid_rec1_ssse3(1, id, ip + 1, nd, block_size, buffer);
}
raid_rec1_ssse3(1, id, ip + 1, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -590,10 +585,9 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
for(j=0;j<nd;++j)
/* +1 to avoid PAR2 optimized case */
raid_rec2_int8(2, id, ip + 1, nd, block_size, buffer);
}
raid_rec2_int8(2, id, ip + 1, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -602,10 +596,9 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
for(j=0;j<nd;++j)
/* +1 to avoid PAR2 optimized case */
raid_rec2_ssse3(2, id, ip + 1, nd, block_size, buffer);
}
raid_rec2_ssse3(2, id, ip + 1, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -618,9 +611,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_int8(3, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_int8(3, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -629,9 +621,8 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_ssse3(3, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_ssse3(3, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -644,9 +635,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_int8(4, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_int8(4, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -655,9 +645,8 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_ssse3(4, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_ssse3(4, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -670,9 +659,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_int8(5, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_int8(5, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -681,9 +669,8 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_ssse3(5, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_ssse3(5, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -696,9 +683,8 @@ void speed(void)
fflush(stdout);
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_int8(6, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_int8(6, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -707,9 +693,8 @@ void speed(void)
#if defined(__i386__) || defined(__x86_64__)
if (raid_cpu_has_ssse3()) {
SPEED_START {
for(j=0;j<nd;++j) {
raid_recX_ssse3(6, id, ip, nd, block_size, buffer);
}
for(j=0;j<nd;++j)
raid_recX_ssse3(6, id, ip, nd, size, v);
} SPEED_STOP
printf("%8"PRIu64, ds / dt);
@ -720,7 +705,7 @@ void speed(void)
printf("If the 'best' expectations are wrong, please report it in the SnapRAID forum\n\n");
free(buffer_alloc);
free(buffer);
free(v_alloc);
free(v);
}

186
util.c
View file

@ -19,6 +19,7 @@
#include "util.h"
#include "raid/cpu.h"
#include "raid/memory.h"
/****************************************************************************/
/* hex conversion table */
@ -1342,143 +1343,6 @@ void* malloc_nofail(size_t size)
return ptr;
}
/**
* Memory alignment provided by malloc_nofail_align().
*
* It should guarantee good cache performance everywhere.
*/
#define MALLOC_ALIGN 256
void* malloc_nofail_align(size_t size, void** freeptr)
{
unsigned char* ptr = malloc_nofail(size + MALLOC_ALIGN);
uintptr_t offset;
*freeptr = ptr;
offset = ((uintptr_t)ptr) % MALLOC_ALIGN;
if (offset != 0) {
ptr += MALLOC_ALIGN - offset;
}
return ptr;
}
/**
* Memory displacement to avoid cache collisions on contiguous blocks.
*
* 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 MALLOC_DISPLACEMENT (7*256)
void** malloc_nofail_vector_align(size_t reverse, size_t count, size_t size, void** freeptr)
{
void** buffer;
unsigned char* buffer_aligned;
size_t i;
assert(reverse <= count);
buffer = malloc_nofail(count * sizeof(void*));
buffer_aligned = malloc_nofail_align(count * (size + MALLOC_DISPLACEMENT), freeptr);
for(i=0;i<count;++i)
buffer[i] = buffer_aligned + i * (size + MALLOC_DISPLACEMENT);
/* reverse order for the initial ones */
for(i=0;i<reverse/2;++i) {
void* ptr = buffer[i];
buffer[i] = buffer[reverse - 1 - i];
buffer[reverse - 1 - i] = ptr;
}
return buffer;
}
void 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)
goto fail;
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)
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<count;++i) {
for(j=0;j<size;++j)
v[i][j] = rand();
}
}
char* strdup_nofail(const char* str)
{
size_t size;
@ -1503,6 +1367,54 @@ char* strdup_nofail(const char* str)
return ptr;
}
void* malloc_nofail_align(size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc_align(size, freeptr);
if (!ptr) {
/* don't use printf to avoid any possible extra allocation */
if (write(2, "Low Memory\n", 11) != 11) {
/* ignore error */
}
exit(EXIT_FAILURE);
}
return ptr;
}
void** malloc_nofail_vector_align(size_t reverse, size_t count, size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc_vector(reverse, count, size, freeptr);
if (!ptr) {
/* don't use printf to avoid any possible extra allocation */
if (write(2, "Low Memory\n", 11) != 11) {
/* ignore error */
}
exit(EXIT_FAILURE);
}
return ptr;
}
void mtest_vector(void** vv, size_t count, size_t size)
{
if (raid_mtest_vector(vv, count, size) != 0) {
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)
{
raid_mrand_vector(vv, count, size);
}
/****************************************************************************/
/* byte operations */