Skip to content

Commit

Permalink
crc32c: Add crc32c function optimized for ppc architecture
Browse files Browse the repository at this point in the history
Add a performance optimized crc32c function for
ppc64le that uses Altivec assembly instructions.
Add an architecture probe for ppc (PowerPC
'ppc64le' architecture).  When the architecture
probe detects that the ppc specific crc32c function
(ceph_crc32c_ppc) can be used, it will do so instead
of using the default crc32c function (ceph_crc32c_sctp).

Signed-off-by: Andrew Solomon <[email protected]>
  • Loading branch information
kestrels committed Mar 20, 2017
1 parent 0007adb commit 59bed55
Show file tree
Hide file tree
Showing 11 changed files with 1,940 additions and 2 deletions.
24 changes: 22 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,22 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
endif()
endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU)

set(CMAKE_ASM_COMPILER ${PROJECT_SOURCE_DIR}/src/yasm-wrapper)
set(CMAKE_ASM_FLAGS "-f elf64")
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
message(STATUS " we are ppc64le")
CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC)
if(HAS_ALTIVEC)
message(STATUS " HAS_ALTIVEC yes")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maltivec")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -maltivec")
endif(HAS_ALTIVEC)
CHECK_C_COMPILER_FLAG("-mcpu=power8" HAVE_POWER8)
if(HAVE_POWER8)
message(STATUS " HAVE_POWER8 yes")
endif(HAVE_POWER8)
else(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")
set(CMAKE_ASM_COMPILER ${PROJECT_SOURCE_DIR}/src/yasm-wrapper)
set(CMAKE_ASM_FLAGS "-f elf64")
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64le")

execute_process(
COMMAND yasm -f elf64 ${CMAKE_SOURCE_DIR}/src/common/crc32c_intel_fast_asm.S -o /dev/null
Expand Down Expand Up @@ -290,6 +304,7 @@ configure_file(
set(arch_files
arch/arm.c
arch/intel.c
arch/ppc.c
arch/probe.cc)

set(auth_files
Expand Down Expand Up @@ -415,6 +430,7 @@ set(libcommon_files
common/crc32c.cc
common/crc32c_intel_baseline.c
common/crc32c_intel_fast.c
common/crc32c_ppc.c
${yasm_srcs}
xxHash/xxhash.c
common/assert.cc
Expand Down Expand Up @@ -520,6 +536,10 @@ elseif(FREEBSD OR APPLE)
message(STATUS " Using EventKqueue for events.")
endif(LINUX)

if(HAVE_POWER8)
list(APPEND libcommon_files common/crc32c_ppc_asm.S)
endif(HAVE_POWER8)

if(WITH_LTTNG AND WITH_EVENTTRACE)
message(STATUS " Using EventTrace class.")
add_definitions("-DWITH_EVENTTRACE")
Expand Down
40 changes: 40 additions & 0 deletions src/arch/ppc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Copyright (C) 2017 International Business Machines Corp.
* All rights reserved.
*
* 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.
*/
#include "arch/ppc.h"
#include "arch/probe.h"

/* flags we export */
int ceph_arch_ppc_crc32 = 0;

#include <stdio.h>
#include <sys/auxv.h>

#if __linux__ && __powerpc64__
#include <asm/cputable.h>
#endif /* __linux__ && __powerpc64__ */

#ifndef PPC_FEATURE2_VEC_CRYPTO
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
#endif

#ifndef AT_HWCAP2
#define AT_HWCAP2 26
#endif

int ceph_arch_ppc_probe(void)
{
ceph_arch_ppc_crc32 = 0;

#if __linux__ && __powerpc64__
if (getauxval(AT_HWCAP2) & PPC_FEATURE2_VEC_CRYPTO) ceph_arch_ppc_crc32 = 1;
#endif /* __linux__ && __powerpc64__ */

return 0;
}

24 changes: 24 additions & 0 deletions src/arch/ppc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/* Copyright (C) 2017 International Business Machines Corp.
* All rights reserved.
*
* 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.
*/
#ifndef CEPH_ARCH_PPC_H
#define CEPH_ARCH_PPC_H

#ifdef __cplusplus
extern "C" {
#endif

extern int ceph_arch_ppc_crc32;

extern int ceph_arch_ppc_probe(void);

#ifdef __cplusplus
}
#endif

#endif
2 changes: 2 additions & 0 deletions src/arch/probe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "arch/intel.h"
#include "arch/arm.h"
#include "arch/ppc.h"

int ceph_arch_probe(void)
{
Expand All @@ -13,6 +14,7 @@ int ceph_arch_probe(void)

ceph_arch_intel_probe();
ceph_arch_arm_probe();
ceph_arch_ppc_probe();

ceph_arch_probed = 1;
return 1;
Expand Down
6 changes: 6 additions & 0 deletions src/common/crc32c.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include "arch/probe.h"
#include "arch/intel.h"
#include "arch/arm.h"
#include "arch/ppc.h"
#include "common/sctp_crc32.h"
#include "common/crc32c_intel_baseline.h"
#include "common/crc32c_intel_fast.h"
#include "common/crc32c_aarch64.h"
#include "common/crc32c_ppc.h"

/*
* choose best implementation based on the CPU architecture.
Expand All @@ -30,6 +32,10 @@ ceph_crc32c_func_t ceph_choose_crc32(void)
return ceph_crc32c_aarch64;
}

if (ceph_arch_ppc_crc32) {
return ceph_crc32c_ppc;
}

// default
return ceph_crc32c_sctp;
}
Expand Down
111 changes: 111 additions & 0 deletions src/common/crc32c_ppc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* Copyright (C) 2017 International Business Machines Corp.
* All rights reserved.
*
* 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.
*/
#define CRC_TABLE
#include "acconfig.h"
#include "include/int_types.h"
#include "crc32c_ppc_constants.h"

#include <stdlib.h>
#include <strings.h>

#define VMX_ALIGN 16
#define VMX_ALIGN_MASK (VMX_ALIGN-1)

#ifdef REFLECT
static unsigned int crc32_align(unsigned int crc, unsigned char const *p,
unsigned long len)
{
while (len--)
crc = crc_table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return crc;
}
#else
static unsigned int crc32_align(unsigned int crc, unsigned char const *p,
unsigned long len)
{
while (len--)
crc = crc_table[((crc >> 24) ^ *p++) & 0xff] ^ (crc << 8);
return crc;
}
#endif


#ifdef HAVE_POWER8
unsigned int __crc32_vpmsum(unsigned int crc, unsigned char const *p,
unsigned long len);

static uint32_t crc32_vpmsum(uint32_t crc, unsigned char const *data,
unsigned len)
{
unsigned int prealign;
unsigned int tail;

#ifdef CRC_XOR
crc ^= 0xffffffff;
#endif

if (len < VMX_ALIGN + VMX_ALIGN_MASK) {
crc = crc32_align(crc, data, (unsigned long)len);
goto out;
}

if ((unsigned long)data & VMX_ALIGN_MASK) {
prealign = VMX_ALIGN - ((unsigned long)data & VMX_ALIGN_MASK);
crc = crc32_align(crc, data, prealign);
len -= prealign;
data += prealign;
}

crc = __crc32_vpmsum(crc, data, (unsigned long)len & ~VMX_ALIGN_MASK);

tail = len & VMX_ALIGN_MASK;
if (tail) {
data += len & ~VMX_ALIGN_MASK;
crc = crc32_align(crc, data, tail);
}

out:
#ifdef CRC_XOR
crc ^= 0xffffffff;
#endif

return crc;
}

/* This wrapper function works around the fact that crc32_vpmsum
* does not gracefully handle the case where the data pointer is NULL. There
* may be room for performance improvement here.
*/
uint32_t ceph_crc32c_ppc(uint32_t crc, unsigned char const *data, unsigned len)
{
unsigned char *buf2;

if (!data) {
buf2 = malloc(len);
bzero(buf2, len);
crc = crc32_vpmsum(crc, buf2, len);
free(buf2);
} else {
crc = crc32_vpmsum(crc, data, (unsigned long)len);
}
return crc;
}

#else /* HAVE_POWER8 */

/* This symbol has to exist on non-ppc architectures (and on legacy
* ppc systems using power7 or below) in order to compile properly
* there, even though it won't be called.
*/
uint32_t ceph_crc32c_ppc(uint32_t crc, unsigned char const *data, unsigned len)
{
return 0;
}

#endif /* HAVE_POWER8 */
22 changes: 22 additions & 0 deletions src/common/crc32c_ppc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* Copyright (C) 2017 International Business Machines Corp.
* All rights reserved.
*
* 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.
*/
#ifndef CEPH_COMMON_CRC32C_PPC_H
#define CEPH_COMMON_CRC32C_PPC_H

#ifdef __cplusplus
extern "C" {
#endif

extern uint32_t ceph_crc32c_ppc(uint32_t crc, unsigned char const *buffer, unsigned len);

#ifdef __cplusplus
}
#endif

#endif
Loading

0 comments on commit 59bed55

Please sign in to comment.