lib/util: add ISA-L accelerated xor generation
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Change-Id: I3ef9dadb4c68e92760c8426f0fffb7b249829e2b Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/12080 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Community-CI: Mellanox Build Bot Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
parent
7131bec415
commit
69c448a30e
@ -108,6 +108,9 @@ For now we are using hard-coded PSK and only support TLS 1.3.
|
|||||||
|
|
||||||
Added new functions: `spdk_hexlify` and `spdk_unhexlify`.
|
Added new functions: `spdk_hexlify` and `spdk_unhexlify`.
|
||||||
|
|
||||||
|
A new API `spdk_xor_gen` was added to generate XOR from multiple source buffers. It is going to be
|
||||||
|
used by `raid5f` for calculating parity.
|
||||||
|
|
||||||
### virtio
|
### virtio
|
||||||
|
|
||||||
virtio-vhost-user no longer tries to support dynamic memory allocation. The vhost target does
|
virtio-vhost-user no longer tries to support dynamic memory allocation. The vhost target does
|
||||||
|
42
include/spdk/xor.h
Normal file
42
include/spdk/xor.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file
|
||||||
|
* XOR utility functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SPDK_XOR_H
|
||||||
|
#define SPDK_XOR_H
|
||||||
|
|
||||||
|
#include "spdk/stdinc.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate XOR from multiple source buffers.
|
||||||
|
*
|
||||||
|
* \param dest Destination buffer.
|
||||||
|
* \param sources Array of source buffers.
|
||||||
|
* \param n Number of source buffers in the array.
|
||||||
|
* \param len Length of each buffer in bytes.
|
||||||
|
* \return 0 on success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int spdk_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the optimal buffer alignment for XOR functions.
|
||||||
|
*
|
||||||
|
* \return The alignment in bytes.
|
||||||
|
*/
|
||||||
|
size_t spdk_xor_get_optimal_alignment(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* SPDK_XOR_H */
|
@ -11,7 +11,7 @@ SO_MINOR := 1
|
|||||||
|
|
||||||
C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c \
|
C_SRCS = base64.c bit_array.c cpuset.c crc16.c crc32.c crc32c.c crc32_ieee.c \
|
||||||
dif.c fd.c file.c hexlify.c iov.c math.c pipe.c strerror_tls.c string.c uuid.c \
|
dif.c fd.c file.c hexlify.c iov.c math.c pipe.c strerror_tls.c string.c uuid.c \
|
||||||
fd_group.c zipf.c
|
fd_group.c xor.c zipf.c
|
||||||
LIBNAME = util
|
LIBNAME = util
|
||||||
LOCAL_SYS_LIBS = -luuid
|
LOCAL_SYS_LIBS = -luuid
|
||||||
|
|
||||||
|
@ -153,6 +153,10 @@
|
|||||||
spdk_fd_group_event_modify;
|
spdk_fd_group_event_modify;
|
||||||
spdk_fd_group_get_fd;
|
spdk_fd_group_get_fd;
|
||||||
|
|
||||||
|
# public functions in xor.h
|
||||||
|
spdk_xor_gen;
|
||||||
|
spdk_xor_get_optimal_alignment;
|
||||||
|
|
||||||
# public functions in zipf.h
|
# public functions in zipf.h
|
||||||
spdk_zipf_create;
|
spdk_zipf_create;
|
||||||
spdk_zipf_free;
|
spdk_zipf_free;
|
||||||
|
145
lib/util/xor.c
Normal file
145
lib/util/xor.c
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "spdk/xor.h"
|
||||||
|
#include "spdk/config.h"
|
||||||
|
#include "spdk/assert.h"
|
||||||
|
#include "spdk/util.h"
|
||||||
|
|
||||||
|
/* maximum number of source buffers */
|
||||||
|
#define SPDK_XOR_MAX_SRC 256
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
is_aligned(void *ptr, size_t alignment)
|
||||||
|
{
|
||||||
|
uintptr_t p = (uintptr_t)ptr;
|
||||||
|
|
||||||
|
return p == SPDK_ALIGN_FLOOR(p, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
buffers_aligned(void *dest, void **sources, uint32_t n, size_t alignment)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (!is_aligned(sources[i], alignment)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_aligned(dest, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xor_gen_unaligned(void *dest, void **sources, uint32_t n, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
uint8_t b = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
b ^= ((uint8_t *)sources[j])[i];
|
||||||
|
}
|
||||||
|
((uint8_t *)dest)[i] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xor_gen_basic(void *dest, void **sources, uint32_t n, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t shift;
|
||||||
|
uint32_t len_div, len_rem;
|
||||||
|
uint32_t i, j;
|
||||||
|
|
||||||
|
if (!buffers_aligned(dest, sources, n, sizeof(uint64_t))) {
|
||||||
|
xor_gen_unaligned(dest, sources, n, len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shift = spdk_u32log2(sizeof(uint64_t));
|
||||||
|
len_div = len >> shift;
|
||||||
|
len_rem = len_div << shift;
|
||||||
|
|
||||||
|
for (i = 0; i < len_div; i++) {
|
||||||
|
uint64_t w = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
w ^= ((uint64_t *)sources[j])[i];
|
||||||
|
}
|
||||||
|
((uint64_t *)dest)[i] = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len_rem < len) {
|
||||||
|
void *sources2[SPDK_XOR_MAX_SRC];
|
||||||
|
|
||||||
|
for (j = 0; j < n; j++) {
|
||||||
|
sources2[j] = sources[j] + len_rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
xor_gen_unaligned(dest + len_rem, sources2, n, len - len_rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SPDK_CONFIG_ISAL
|
||||||
|
#include "isa-l/include/raid.h"
|
||||||
|
|
||||||
|
#define SPDK_XOR_BUF_ALIGN 32
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
|
||||||
|
{
|
||||||
|
if (buffers_aligned(dest, sources, n, SPDK_XOR_BUF_ALIGN)) {
|
||||||
|
void *buffers[SPDK_XOR_MAX_SRC + 1];
|
||||||
|
|
||||||
|
if (n >= INT_MAX) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffers, sources, n * sizeof(buffers[0]));
|
||||||
|
buffers[n] = dest;
|
||||||
|
|
||||||
|
if (xor_gen(n + 1, len, buffers)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xor_gen_basic(dest, sources, n, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define SPDK_XOR_BUF_ALIGN sizeof(uint64_t)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
do_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
|
||||||
|
{
|
||||||
|
xor_gen_basic(dest, sources, n, len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
spdk_xor_gen(void *dest, void **sources, uint32_t n, uint32_t len)
|
||||||
|
{
|
||||||
|
if (n < 2 || n > SPDK_XOR_MAX_SRC) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return do_xor_gen(dest, sources, n, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
spdk_xor_get_optimal_alignment(void)
|
||||||
|
{
|
||||||
|
return SPDK_XOR_BUF_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDK_STATIC_ASSERT(SPDK_XOR_BUF_ALIGN > 0 && !(SPDK_XOR_BUF_ALIGN & (SPDK_XOR_BUF_ALIGN - 1)),
|
||||||
|
"Must be power of 2");
|
@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
|
|||||||
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
|
||||||
|
|
||||||
DIRS-y = base64.c bit_array.c cpuset.c crc16.c crc32_ieee.c crc32c.c dif.c \
|
DIRS-y = base64.c bit_array.c cpuset.c crc16.c crc32_ieee.c crc32c.c dif.c \
|
||||||
iov.c math.c pipe.c string.c
|
iov.c math.c pipe.c string.c xor.c
|
||||||
|
|
||||||
.PHONY: all clean $(DIRS-y)
|
.PHONY: all clean $(DIRS-y)
|
||||||
|
|
||||||
|
10
test/unit/lib/util/xor.c/Makefile
Normal file
10
test/unit/lib/util/xor.c/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
# Copyright (c) Intel Corporation.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..)
|
||||||
|
|
||||||
|
TEST_FILE = xor_ut.c
|
||||||
|
|
||||||
|
include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk
|
121
test/unit/lib/util/xor.c/xor_ut.c
Normal file
121
test/unit/lib/util/xor.c/xor_ut.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
* Copyright (c) Intel Corporation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "spdk/stdinc.h"
|
||||||
|
|
||||||
|
#include "spdk_cunit.h"
|
||||||
|
|
||||||
|
#include "util/xor.c"
|
||||||
|
#include "common/lib/test_env.c"
|
||||||
|
|
||||||
|
#define BUF_COUNT 8
|
||||||
|
#define SRC_BUF_COUNT (BUF_COUNT - 1)
|
||||||
|
#define BUF_SIZE 4096
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_xor_gen(void)
|
||||||
|
{
|
||||||
|
void *bufs[BUF_COUNT];
|
||||||
|
void *bufs2[SRC_BUF_COUNT];
|
||||||
|
uint8_t *ref, *dest;
|
||||||
|
int ret;
|
||||||
|
size_t i, j;
|
||||||
|
uint32_t *tmp;
|
||||||
|
|
||||||
|
/* alloc and fill the buffers with a pattern */
|
||||||
|
for (i = 0; i < BUF_COUNT; i++) {
|
||||||
|
ret = posix_memalign(&bufs[i], spdk_xor_get_optimal_alignment(), BUF_SIZE);
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret == 0);
|
||||||
|
|
||||||
|
tmp = bufs[i];
|
||||||
|
for (j = 0; j < BUF_SIZE / sizeof(*tmp); j++) {
|
||||||
|
tmp[j] = (i << 16) + j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dest = bufs[SRC_BUF_COUNT];
|
||||||
|
|
||||||
|
/* prepare the reference buffer */
|
||||||
|
ref = malloc(BUF_SIZE);
|
||||||
|
SPDK_CU_ASSERT_FATAL(ref != NULL);
|
||||||
|
|
||||||
|
memset(ref, 0, BUF_SIZE);
|
||||||
|
for (i = 0; i < SRC_BUF_COUNT; i++) {
|
||||||
|
for (j = 0; j < BUF_SIZE; j++) {
|
||||||
|
ref[j] ^= ((uint8_t *)bufs[i])[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* generate xor, compare the dest and reference buffers */
|
||||||
|
ret = spdk_xor_gen(dest, bufs, SRC_BUF_COUNT, BUF_SIZE);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
ret = memcmp(ref, dest, BUF_SIZE);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
|
||||||
|
/* len not multiple of alignment */
|
||||||
|
memset(dest, 0xba, BUF_SIZE);
|
||||||
|
ret = spdk_xor_gen(dest, bufs, SRC_BUF_COUNT, BUF_SIZE - 1);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
ret = memcmp(ref, dest, BUF_SIZE - 1);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
|
||||||
|
/* unaligned buffer */
|
||||||
|
memcpy(bufs2, bufs, sizeof(bufs2));
|
||||||
|
bufs2[1] += 1;
|
||||||
|
bufs2[2] += 2;
|
||||||
|
bufs2[3] += 3;
|
||||||
|
|
||||||
|
memset(ref, 0, BUF_SIZE);
|
||||||
|
for (i = 0; i < SRC_BUF_COUNT; i++) {
|
||||||
|
for (j = 0; j < BUF_SIZE - SRC_BUF_COUNT; j++) {
|
||||||
|
ref[j] ^= ((uint8_t *)bufs2[i])[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dest, 0xba, BUF_SIZE);
|
||||||
|
ret = spdk_xor_gen(dest, bufs2, SRC_BUF_COUNT, BUF_SIZE - SRC_BUF_COUNT);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
ret = memcmp(ref, dest, BUF_SIZE - SRC_BUF_COUNT);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
|
||||||
|
/* xoring a buffer with itself should result in all zeros */
|
||||||
|
memset(ref, 0, BUF_SIZE);
|
||||||
|
bufs2[0] = bufs[0];
|
||||||
|
bufs2[1] = bufs[0];
|
||||||
|
dest = bufs[0];
|
||||||
|
|
||||||
|
ret = spdk_xor_gen(dest, bufs2, 2, BUF_SIZE);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
ret = memcmp(ref, dest, BUF_SIZE);
|
||||||
|
CU_ASSERT(ret == 0);
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
for (i = 0; i < BUF_COUNT; i++) {
|
||||||
|
free(bufs[i]);
|
||||||
|
}
|
||||||
|
free(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
CU_pSuite suite = NULL;
|
||||||
|
unsigned int num_failures;
|
||||||
|
|
||||||
|
CU_set_error_action(CUEA_ABORT);
|
||||||
|
CU_initialize_registry();
|
||||||
|
|
||||||
|
suite = CU_add_suite("xor", NULL, NULL);
|
||||||
|
|
||||||
|
CU_ADD_TEST(suite, test_xor_gen);
|
||||||
|
|
||||||
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||||
|
|
||||||
|
CU_basic_run_tests();
|
||||||
|
|
||||||
|
num_failures = CU_get_number_of_failures();
|
||||||
|
CU_cleanup_registry();
|
||||||
|
|
||||||
|
return num_failures;
|
||||||
|
}
|
@ -133,6 +133,7 @@ function unittest_util() {
|
|||||||
$valgrind $testdir/lib/util/iov.c/iov_ut
|
$valgrind $testdir/lib/util/iov.c/iov_ut
|
||||||
$valgrind $testdir/lib/util/math.c/math_ut
|
$valgrind $testdir/lib/util/math.c/math_ut
|
||||||
$valgrind $testdir/lib/util/pipe.c/pipe_ut
|
$valgrind $testdir/lib/util/pipe.c/pipe_ut
|
||||||
|
$valgrind $testdir/lib/util/xor.c/xor_ut
|
||||||
}
|
}
|
||||||
|
|
||||||
function unittest_init() {
|
function unittest_init() {
|
||||||
|
Loading…
Reference in New Issue
Block a user