mirror of
https://github.com/postgres/postgres.git
synced 2025-11-24 00:23:06 +03:00
Use ARMv8 CRC instructions where available.
ARMv8 introduced special CPU instructions for calculating CRC-32C. Use them, when available, for speed. Like with the similar Intel CRC instructions, several factors affect whether the instructions can be used. The compiler intrinsics for them must be supported by the compiler, and the instructions must be supported by the target architecture. If the compilation target architecture does not support the instructions, but adding "-march=armv8-a+crc" makes them available, then we compile the code with a runtime check to determine if the host we're running on supports them or not. For the runtime check, use glibc getauxval() function. Unfortunately, that's not very portable, but I couldn't find any more portable way to do it. If getauxval() is not available, the CRC instructions will still be used if the target architecture supports them without any additional compiler flags, but the runtime check will not be available. Original patch by Yuqi Gu, heavily modified by me. Reviewed by Andres Freund, Thomas Munro. Discussion: https://www.postgresql.org/message-id/HE1PR0801MB1323D171938EABC04FFE7FA9E3110%40HE1PR0801MB1323.eurprd08.prod.outlook.com
This commit is contained in:
55
src/port/pg_crc32c_armv8_choose.c
Normal file
55
src/port/pg_crc32c_armv8_choose.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_crc32c_armv8_choose.c
|
||||
* Choose between ARMv8 and software CRC-32C implementation.
|
||||
*
|
||||
* On first call, checks if the CPU we're running on supports the ARMv8
|
||||
* CRC Extension. If it does, use the special instructions for CRC-32C
|
||||
* computation. Otherwise, fall back to the pure software implementation
|
||||
* (slicing-by-8).
|
||||
*
|
||||
* XXX: The glibc-specific getauxval() function, with the HWCAP_CRC32
|
||||
* flag, is used to determine if the CRC Extension is available on the
|
||||
* current platform. Is there a more portable way to determine that?
|
||||
*
|
||||
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/port/pg_crc32c_armv8_choose.c
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#include "port/pg_crc32c.h"
|
||||
|
||||
static bool
|
||||
pg_crc32c_armv8_available(void)
|
||||
{
|
||||
unsigned long auxv = getauxval(AT_HWCAP);
|
||||
|
||||
return (auxv & HWCAP_CRC32) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets called on the first call. It replaces the function pointer
|
||||
* so that subsequent calls are routed directly to the chosen implementation.
|
||||
*/
|
||||
static pg_crc32c
|
||||
pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
|
||||
{
|
||||
if (pg_crc32c_armv8_available())
|
||||
pg_comp_crc32c = pg_comp_crc32c_armv8;
|
||||
else
|
||||
pg_comp_crc32c = pg_comp_crc32c_sb8;
|
||||
|
||||
return pg_comp_crc32c(crc, data, len);
|
||||
}
|
||||
|
||||
pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
|
||||
Reference in New Issue
Block a user