Skip to content

Commit

Permalink
compute fletcher 4 with avx instructions
Browse files Browse the repository at this point in the history
Detect if the running CPU supports AVX instruction, and evaluate
Fletcher-4 computation througput and choose the fastest one.

Signed-off-by: Jinshan Xiong <[email protected]>
  • Loading branch information
Jinshan Xiong committed Mar 21, 2016
1 parent 505d965 commit 284dc85
Show file tree
Hide file tree
Showing 8 changed files with 457 additions and 71 deletions.
1 change: 1 addition & 0 deletions include/sys/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ COMMON_H = \
$(top_srcdir)/include/sys/space_reftree.h \
$(top_srcdir)/include/sys/spa.h \
$(top_srcdir)/include/sys/spa_impl.h \
$(top_srcdir)/include/sys/spa_checksum.h \
$(top_srcdir)/include/sys/trace.h \
$(top_srcdir)/include/sys/trace_acl.h \
$(top_srcdir)/include/sys/trace_arc.h \
Expand Down
33 changes: 1 addition & 32 deletions include/sys/spa.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/fs/zfs.h>
#include <sys/spa_checksum.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -142,12 +143,6 @@ typedef struct dva {
uint64_t dva_word[2];
} dva_t;

/*
* Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
*/
typedef struct zio_cksum {
uint64_t zc_word[4];
} zio_cksum_t;

/*
* Each block is described by its DVAs, time of birth, checksum, etc.
Expand Down Expand Up @@ -440,35 +435,9 @@ _NOTE(CONSTCOND) } while (0)
DVA_EQUAL(&(bp1)->blk_dva[1], &(bp2)->blk_dva[1]) && \
DVA_EQUAL(&(bp1)->blk_dva[2], &(bp2)->blk_dva[2]))

#define ZIO_CHECKSUM_EQUAL(zc1, zc2) \
(0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \
((zc1).zc_word[1] - (zc2).zc_word[1]) | \
((zc1).zc_word[2] - (zc2).zc_word[2]) | \
((zc1).zc_word[3] - (zc2).zc_word[3])))

#define ZIO_CHECKSUM_IS_ZERO(zc) \
(0 == ((zc)->zc_word[0] | (zc)->zc_word[1] | \
(zc)->zc_word[2] | (zc)->zc_word[3]))

#define ZIO_CHECKSUM_BSWAP(zcp) \
{ \
(zcp)->zc_word[0] = BSWAP_64((zcp)->zc_word[0]); \
(zcp)->zc_word[1] = BSWAP_64((zcp)->zc_word[1]); \
(zcp)->zc_word[2] = BSWAP_64((zcp)->zc_word[2]); \
(zcp)->zc_word[3] = BSWAP_64((zcp)->zc_word[3]); \
}


#define DVA_IS_VALID(dva) (DVA_GET_ASIZE(dva) != 0)

#define ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3) \
{ \
(zcp)->zc_word[0] = w0; \
(zcp)->zc_word[1] = w1; \
(zcp)->zc_word[2] = w2; \
(zcp)->zc_word[3] = w3; \
}

#define BP_IDENTITY(bp) (ASSERT(!BP_IS_EMBEDDED(bp)), &(bp)->blk_dva[0])
#define BP_IS_GANG(bp) \
(BP_IS_EMBEDDED(bp) ? B_FALSE : DVA_GET_GANG(BP_IDENTITY(bp)))
Expand Down
72 changes: 72 additions & 0 deletions include/sys/spa_checksum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/

#ifndef _SPA_CHECKSUM_H
#define _SPA_CHECKSUM_H

#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
* Each block has a 256-bit checksum -- strong enough for cryptographic hashes.
*/
typedef struct zio_cksum {
uint64_t zc_word[4];
} zio_cksum_t;

#define ZIO_SET_CHECKSUM(zcp, w0, w1, w2, w3) \
{ \
(zcp)->zc_word[0] = w0; \
(zcp)->zc_word[1] = w1; \
(zcp)->zc_word[2] = w2; \
(zcp)->zc_word[3] = w3; \
}

#define ZIO_CHECKSUM_EQUAL(zc1, zc2) \
(0 == (((zc1).zc_word[0] - (zc2).zc_word[0]) | \
((zc1).zc_word[1] - (zc2).zc_word[1]) | \
((zc1).zc_word[2] - (zc2).zc_word[2]) | \
((zc1).zc_word[3] - (zc2).zc_word[3])))

#define ZIO_CHECKSUM_IS_ZERO(zc) \
(0 == ((zc)->zc_word[0] | (zc)->zc_word[1] | \
(zc)->zc_word[2] | (zc)->zc_word[3]))

#define ZIO_CHECKSUM_BSWAP(zcp) \
{ \
(zcp)->zc_word[0] = BSWAP_64((zcp)->zc_word[0]); \
(zcp)->zc_word[1] = BSWAP_64((zcp)->zc_word[1]); \
(zcp)->zc_word[2] = BSWAP_64((zcp)->zc_word[2]); \
(zcp)->zc_word[3] = BSWAP_64((zcp)->zc_word[3]); \
}

#ifdef __cplusplus
}
#endif

#endif
15 changes: 14 additions & 1 deletion include/zfs_fletcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#define _ZFS_FLETCHER_H

#include <sys/types.h>
#include <sys/spa.h>
#include <sys/spa_checksum.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -45,6 +45,19 @@ void fletcher_4_incremental_native(const void *, uint64_t,
zio_cksum_t *);
void fletcher_4_incremental_byteswap(const void *, uint64_t,
zio_cksum_t *);
void fletcher_4_init(void);

/*
* fletcher checksum struct
*/
struct fletcher_4_calls {
void (*init)(zio_cksum_t *);
void (*fini)(zio_cksum_t *);
void (*compute)(const void *, uint64_t, zio_cksum_t *);
void (*compute_byteswap)(const void *, uint64_t, zio_cksum_t *);
boolean_t (*valid)(void);
const char *name;
};

#ifdef __cplusplus
}
Expand Down
2 changes: 2 additions & 0 deletions module/zcommon/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ $(MODULE)-objs += zfs_comutil.o
$(MODULE)-objs += zfs_fletcher.o
$(MODULE)-objs += zfs_uio.o
$(MODULE)-objs += zpool_prop.o

$(MODULE)-$(CONFIG_X86) += zfs_fletcher_intel.o
145 changes: 107 additions & 38 deletions module/zcommon/zfs_fletcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/byteorder.h>
#include <sys/zio.h>
#include <sys/spa.h>
#include <zfs_fletcher.h>

void
fletcher_2_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
Expand Down Expand Up @@ -165,43 +165,13 @@ fletcher_2_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
ZIO_SET_CHECKSUM(zcp, a0, a1, b0, b1);
}

void
fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
static void fletcher_4_generic_init(zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
uint64_t a, b, c, d;

for (a = b = c = d = 0; ip < ipend; ip++) {
a += ip[0];
b += a;
c += b;
d += c;
}

ZIO_SET_CHECKSUM(zcp, a, b, c, d);
}

void
fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
uint64_t a, b, c, d;

for (a = b = c = d = 0; ip < ipend; ip++) {
a += BSWAP_32(ip[0]);
b += a;
c += b;
d += c;
}

ZIO_SET_CHECKSUM(zcp, a, b, c, d);
ZIO_SET_CHECKSUM(zcp, 0, 0, 0, 0);
}

void
fletcher_4_incremental_native(const void *buf, uint64_t size,
zio_cksum_t *zcp)
static void
fletcher_4_generic(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
Expand All @@ -222,9 +192,8 @@ fletcher_4_incremental_native(const void *buf, uint64_t size,
ZIO_SET_CHECKSUM(zcp, a, b, c, d);
}

void
fletcher_4_incremental_byteswap(const void *buf, uint64_t size,
zio_cksum_t *zcp)
static void
fletcher_4_generic_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
const uint32_t *ip = buf;
const uint32_t *ipend = ip + (size / sizeof (uint32_t));
Expand All @@ -245,7 +214,107 @@ fletcher_4_incremental_byteswap(const void *buf, uint64_t size,
ZIO_SET_CHECKSUM(zcp, a, b, c, d);
}

static const struct fletcher_4_calls fletcher_4_generic_calls = {
.init = fletcher_4_generic_init,
.compute = fletcher_4_generic,
.compute_byteswap = fletcher_4_generic_byteswap,
.name = "generic"
};

static const struct fletcher_4_calls *chosen = &fletcher_4_generic_calls;

void
fletcher_4_native(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
chosen->init(zcp);
chosen->compute(buf, size, zcp);
if (chosen->fini != NULL)
chosen->fini(zcp);
}

void
fletcher_4_byteswap(const void *buf, uint64_t size, zio_cksum_t *zcp)
{
chosen->init(zcp);
chosen->compute_byteswap(buf, size, zcp);
if (chosen->fini != NULL)
chosen->fini(zcp);
}

void
fletcher_4_incremental_native(const void *buf, uint64_t size,
zio_cksum_t *zcp)
{
fletcher_4_generic(buf, size, zcp);
}

void
fletcher_4_incremental_byteswap(const void *buf, uint64_t size,
zio_cksum_t *zcp)
{
fletcher_4_generic_byteswap(buf, size, zcp);
}


#if defined(_KERNEL) && defined(HAVE_SPL)

extern struct fletcher_4_calls fletcher_4_avx2_calls;

static const struct fletcher_4_calls *fletcher_4_algos[] = {
&fletcher_4_generic_calls,
#if defined(HAVE_AVX) && defined(HAVE_AVX2)
&fletcher_4_avx2_calls,
#endif
};

#define BENCH_SIZE 4096
#define ZFS_ARRAY_SIZE(a) (sizeof (a) / sizeof (*a))
#define kernel_cpu_relax() do {} while (0)

/* cant use allocation methods from zfs module! */
static char databuf[BENCH_SIZE];

void
fletcher_4_init(void)
{
unsigned long bestperf = 0;
const unsigned int bits = 4;
int i;

for (i = 0; i < ZFS_ARRAY_SIZE(fletcher_4_algos); i++) {
const struct fletcher_4_calls *algo = fletcher_4_algos[i];
unsigned long perf = 0;
clock_t j0, j1;
zio_cksum_t zc;

if (algo->valid != NULL && !algo->valid())
continue;

kpreempt_disable();
j0 = ddi_get_lbolt();
while ((j1 = ddi_get_lbolt()) == j0) {
kernel_cpu_relax();
}

algo->init(&zc);
while (ddi_time_before(ddi_get_lbolt(), j1 + (1 << bits))) {
algo->compute(databuf, PAGE_SIZE, &zc);
perf++;
}
if (algo->fini != NULL)
algo->fini(&zc);
kpreempt_enable();

if (perf > bestperf) {
bestperf = perf;
chosen = algo;
}
cmn_err(CE_NOTE, "fletcher-4: %-8s %5ld MB/s",
algo->name, SEC_TO_TICK(perf) >> (20 - 16 + bits));
}
}

EXPORT_SYMBOL(fletcher_4_init);
EXPORT_SYMBOL(fletcher_2_native);
EXPORT_SYMBOL(fletcher_2_byteswap);
EXPORT_SYMBOL(fletcher_4_native);
Expand Down
Loading

0 comments on commit 284dc85

Please sign in to comment.