snapraid/cmdline/util.h
Andrea Mazzoleni e63e79d51a Parallel hashes
2026-07-13 11:03:58 +02:00

313 lines
7.8 KiB
C

// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef __UTIL_H
#define __UTIL_H
#include "tommyds/tommytypes.h"
/****************************************************************************/
/* memory */
/**
* Safe aligned malloc.
* If no memory is available, it aborts.
*/
void* malloc_nofail_align(size_t size, void** freeptr);
/**
* Safe aligned malloc. Usable for direct io.
*/
void* malloc_nofail_direct(size_t size, void** freeptr);
/**
* Safe aligned vector allocation.
* If no memory is available, it aborts.
*/
void** malloc_nofail_vector_align(int n, size_t size, void** freeptr);
/**
* Safe page vector allocation. Usable for direct io.
* If no memory is available, it aborts.
*/
void** malloc_nofail_vector_direct(int n, size_t size, void** freeptr);
/**
* Safe allocation with memory test.
*/
void* malloc_nofail_test(size_t size);
/**
* Test the memory vector for RAM problems.
* If a problem is found, it crashes.
*/
void mtest_vector(int n, size_t size, void** vv);
/****************************************************************************/
/* crc */
/**
* CRC initial value.
* Using a not zero value allows to detect a leading run of zeros.
*/
#define CRC_IV 0xffffffffU
/**
* CRC-32 (Castagnoli) table.
*/
extern uint32_t CRC32C_0[256];
extern uint32_t CRC32C_1[256];
extern uint32_t CRC32C_2[256];
extern uint32_t CRC32C_3[256];
/**
* If the CPU support the CRC instructions.
*/
#if CONFIG_X86
extern int crc_x86;
#endif
/**
* Compute CRC-32 (Castagnoli) for a single byte without the IV.
*/
static inline uint32_t crc32c_plain_char(uint32_t crc, unsigned char c)
{
#if CONFIG_X86
if (tommy_likely(crc_x86)) {
asm ("crc32b %1, %0\n" : "+r" (crc) : "m" (c));
return crc;
}
#endif
#if CONFIG_ARM_CRC
asm ("crc32cb %w0, %w0, %w1\n" : "+r" (crc) : "r" (c));
return crc;
#else
return CRC32C_0[(crc ^ c) & 0xff] ^ (crc >> 8);
#endif
}
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
static inline uint32_t crc32c_gen_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
while (size >= 4) {
crc ^= ptr[0] | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[3] << 24;
crc = CRC32C_3[crc & 0xff] ^ CRC32C_2[(crc >> 8) & 0xff] ^ CRC32C_1[(crc >> 16) & 0xff] ^ CRC32C_0[crc >> 24];
ptr += 4;
size -= 4;
}
while (size) {
crc = CRC32C_0[(crc ^ *ptr) & 0xff] ^ (crc >> 8);
++ptr;
--size;
}
return crc;
}
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
#if CONFIG_X86
static inline uint32_t crc32c_x86_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
#ifdef CONFIG_X86_64
uint64_t crc64 = crc;
while (size >= 8) {
asm ("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)ptr));
ptr += 8;
size -= 8;
}
crc = (uint32_t)crc64;
#else
while (size >= 4) {
asm ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
ptr += 4;
size -= 4;
}
#endif
while (size) {
asm ("crc32b %1, %0\n" : "+r" (crc) : "m" (*ptr));
++ptr;
--size;
}
return crc;
}
#endif
#if CONFIG_ARM_CRC
static inline uint32_t crc32c_arm64_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
while (size >= 8) {
uint64_t val;
__builtin_memcpy(&val, ptr, 8);
asm ("crc32cx %w0, %w0, %x1\n" : "+r" (crc) : "r" (val));
ptr += 8;
size -= 8;
}
if (size >= 4) {
uint32_t val;
__builtin_memcpy(&val, ptr, 4);
asm ("crc32cw %w0, %w0, %w1\n" : "+r" (crc) : "r" (val));
ptr += 4;
size -= 4;
}
while (size) {
asm ("crc32cb %w0, %w0, %w1\n" : "+r" (crc) : "r" (*ptr));
++ptr;
--size;
}
return crc;
}
#endif
/**
* Compute CRC-32 (Castagnoli) without the IV.
*/
static inline uint32_t crc32c_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
#if CONFIG_X86
if (tommy_likely(crc_x86)) {
return crc32c_x86_plain(crc, ptr, size);
}
#endif
#if CONFIG_ARM_CRC
return crc32c_arm64_plain(crc, ptr, size);
#else
return crc32c_gen_plain(crc, ptr, size);
#endif
}
/**
* Compute the CRC-32 (Castagnoli)
*/
extern uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, size_t size);
/**
* Internal entry points for testing.
*/
uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, size_t size);
uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, size_t size);
uint32_t crc32c_arm64(uint32_t crc, const unsigned char* ptr, size_t size);
/**
* Initialize the CRC-32 (Castagnoli) support.
*/
void crc32c_init(void);
/****************************************************************************/
/* hash */
/**
* Size of the hash.
*/
#define HASH_MAX 16
/**
* Hash kinds.
*/
#define HASH_UNDEFINED 0
#define HASH_MURMUR3 1
#define HASH_SPOOKY2 2
#define HASH_METRO 3
#define HASH_MUSEAIR 4
/**
* Return the hash that is expected to be the fastest in this architecture
*/
unsigned membesthash(void);
/**
* Return the name of the hash
*/
const char* memhashname(unsigned kind);
/**
* Compute the HASH of a memory block.
* Seed is a 128 bit vector.
*/
void SpookyHash128(const void* data, size_t size, const uint8_t* seed, uint8_t* digest);
void SpookyHash128SSE(const void* data0, const void* data1, size_t size, const uint8_t* seed0, const uint8_t* seed1, uint8_t* digest0, uint8_t* digest1);
void SpookyHash128AVX(const void* data0, const void* data1, const void* data2, const void* data3, size_t size, const uint8_t* seed0, const uint8_t* seed1, const uint8_t* seed2, const uint8_t* seed3, uint8_t* digest0, uint8_t* digest1, uint8_t* digest2, uint8_t* digest3);
void MuseAirLoongSSE(const void* data0, const void* data1, size_t size, const uint8_t* seed0, const uint8_t* seed1, uint8_t* digest0, uint8_t* digest1);
void MuseAirLoongAVX(const void* data0, const void* data1, const void* data2, const void* data3, size_t size, const uint8_t* seed0, const uint8_t* seed1, const uint8_t* seed2, const uint8_t* seed3, uint8_t* digest0, uint8_t* digest1, uint8_t* digest2, uint8_t* digest3);
void MuseAirLoong(const void* bytes, size_t len, const uint8_t* seed, uint8_t* out);
void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size);
/**
* Compute the HASH of multiple memory blocks at the same time.
* Seed is a 128 bit vector.
*/
void memhash_multi(unsigned kind, const unsigned char* seed, void** digest, const void** src, const size_t* size, unsigned count);
/**
* Return the hash name.
*/
const char* hash_config_name(unsigned kind);
/**
* Count the number of different bits in the two buffers.
*/
unsigned memdiff(const unsigned char* data1, const unsigned char* data2, size_t size);
/**
* Unit test
*/
int util_selftest(void);
/****************************************************************************/
/* lock */
/**
* Create and locks the lock file.
* Return -1 on error, otherwise it's the file handle to pass to lock_unlock().
*/
int lock_lock(const char* file);
/**
* Unlock the lock file.
* Return -1 on error.
*/
int lock_unlock(int f);
/****************************************************************************/
/* bitvect */
typedef unsigned char bit_vect_t;
#define BIT_VECT_SIZE (sizeof(bit_vect_t) * 8)
static inline size_t bit_vect_size(size_t max)
{
return (max + BIT_VECT_SIZE - 1) / BIT_VECT_SIZE;
}
static inline void bit_vect_set(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
bit_vect[off / BIT_VECT_SIZE] |= mask;
}
static inline void bit_vect_clear(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
bit_vect[off / BIT_VECT_SIZE] &= ~mask;
}
static inline int bit_vect_test(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
return (bit_vect[off / BIT_VECT_SIZE] & mask) != 0;
}
/****************************************************************************/
/* muldiv */
unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div);
unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div);
#endif