Commit f48bac81 authored by dguyot's avatar dguyot
Browse files

Initial commit for xxhash64.c

parent 805c6154
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <immintrin.h>
static const uint64_t PRIME64_1 = 11400714785074694791ULL;
static const uint64_t PRIME64_2 = 14029467366897019727ULL;
static const uint64_t PRIME64_3 = 1609587929392839161ULL;
static const uint64_t PRIME64_4 = 9650029242287828579ULL;
static const uint64_t PRIME64_5 = 2870177450012600261ULL;
#define rotateleft(X,R) ((X << R) | (X >> (64 - R)))
//#define rotateleft(X,R) _rotl64(X,R)
static inline uint64_t xxround(uint64_t accN, uint64_t* lane){
accN = accN + (*lane * PRIME64_2);
accN = rotateleft(accN, 31);
return (accN * PRIME64_1);
}
static inline void xxroundN(uint64_t* accN, uint64_t* lane){
//~ for (int i = 0; i < 4; i++){
//~ accN[i] = accN[i] + (lane[i] * PRIME64_2);
//~ accN[i] = rotateleft(accN[i], 31);
//~ accN[i] = accN[i] * PRIME64_1;
//~ }
accN[0] = accN[0] + (lane[0] * PRIME64_2);
accN[1] = accN[1] + (lane[1] * PRIME64_2);
accN[2] = accN[2] + (lane[2] * PRIME64_2);
accN[3] = accN[3] + (lane[3] * PRIME64_2);
accN[0] = rotateleft(accN[0], 31);
accN[1] = rotateleft(accN[1], 31);
accN[2] = rotateleft(accN[2], 31);
accN[3] = rotateleft(accN[3], 31);
accN[0] = accN[0] * PRIME64_1;
accN[1] = accN[1] * PRIME64_1;
accN[2] = accN[2] * PRIME64_1;
accN[3] = accN[3] * PRIME64_1;
}
uint64_t mergeacc(uint64_t acc, uint64_t accN){
acc = acc ^ xxround(0, &accN);
acc = acc * PRIME64_1;
return (acc + PRIME64_4);
}
void printacc(uint64_t* accN){
int i;
for (i = 0; i < 4; i++){
printf("%016" PRIx64 "\t", accN[i]);
}
printf("\n");
}
static inline void xxh64_init(uint64_t seed, uint64_t* accN, uint64_t* acc){
*acc = seed + PRIME64_5;
accN[0] = seed + PRIME64_1 + PRIME64_2;
accN[1] = seed + PRIME64_2;
accN[2] = seed + 0;
accN[3] = seed - PRIME64_1;
}
static inline void xxh64_process(uint64_t* accN, uint64_t* lane, char *buf, size_t len){
//there is 32 bytes into a lane, number of stripes is the integer value of len/32 == len >> 5
size_t stripes = len >> 5;
lane = (uint64_t*)buf;
while (stripes--){
xxroundN(accN, lane);
lane += 4;
}
}
static inline void xxh64_convergence(uint64_t* accN, uint64_t* acc){
*acc = rotateleft(accN[0], 1) + rotateleft(accN[1], 7) + rotateleft(accN[2], 12) + rotateleft(accN[3], 18);
*acc = mergeacc(*acc, accN[0]);
*acc = mergeacc(*acc, accN[1]);
*acc = mergeacc(*acc, accN[2]);
*acc = mergeacc(*acc, accN[3]);
}
static inline void xxh64_addlen(uint64_t* acc, size_t len){
*acc = *acc + len;
}
static inline void xxh64_consume(char* buf, size_t len, uint64_t* acc){
//size of remainning buffer (last bloc of lenght < 32 bytes)
size_t remlen = len % 32;
//location of remainning buffer (last bloc of lenght < 32 bytes)
char* rembuf = buf + len - remlen;
uint64_t* remlane64;
uint32_t* remlane32;
uint8_t* remlane8;
while (remlen >= 8){
remlane64 = (uint64_t*)rembuf;
*acc = *acc ^ xxround(0, remlane64);
*acc = rotateleft(*acc, 27) * PRIME64_1;
*acc = *acc + PRIME64_4;
rembuf += 8;
remlen -= 8;
}
if (remlen >= 4){
remlane32 = (uint32_t*)rembuf;
*acc = *acc ^ (*remlane32 * PRIME64_1);
*acc = rotateleft(*acc, 23) * PRIME64_2;
*acc = *acc + PRIME64_3;
rembuf += 4;
remlen -= 4;
}
while (remlen >= 1){
remlane8 = (uint8_t*)rembuf;
*acc = *acc ^ (*remlane8 * PRIME64_5);
*acc = rotateleft(*acc, 11) * PRIME64_1;
rembuf += 1;
remlen -= 1;
}
}
static inline void xxh64_avalanche(uint64_t* acc){
*acc = *acc ^ (*acc >> 33);
*acc = *acc * PRIME64_2;
*acc = *acc ^ (*acc >> 29);
*acc = *acc * PRIME64_3;
*acc = *acc ^ (*acc >> 32);
}
/*
* each step is described here: https://github.com/Cyan4973/xxHash/blob/dev/doc/xxhash_spec.md#xxh64-algorithm-description
*/
uint64_t xxhash64(char* buf, size_t len){
uint64_t* lane = (uint64_t*) buf;
uint64_t accN[4];
uint64_t acc;
xxh64_init(0, accN, &acc);
xxh64_process(accN, lane, buf, len);
xxh64_convergence(accN, &acc);
xxh64_addlen(&acc, len);
xxh64_consume(buf, len, &acc);
xxh64_avalanche(&acc);
return (acc);
}
int main(int argc, char** argv){
uint64_t chk;
struct stat sfd;
int fd;
size_t size;
char* mmfile;
int i;
fd = open(argv[1], O_RDONLY);
fstat(fd,&sfd);
size = sfd.st_size;
mmfile = (char *)mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_DENYWRITE, fd, 0);
close(fd);
chk = xxhash64(mmfile, size);
printf("%" PRIx64 "\n", chk);
return(0);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment