mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 10:51:54 -04:00
Add MetroHash128 for speed measurement
This commit is contained in:
parent
d294c11b43
commit
b725333a49
6 changed files with 162 additions and 0 deletions
|
|
@ -83,6 +83,7 @@ noinst_HEADERS = \
|
|||
cmdline/murmur3test.c \
|
||||
cmdline/spooky2.c \
|
||||
cmdline/spooky2test.c \
|
||||
cmdline/metro.c \
|
||||
cmdline/fnmatch.h \
|
||||
cmdline/import.h \
|
||||
cmdline/search.h \
|
||||
|
|
|
|||
108
cmdline/metro.c
Normal file
108
cmdline/metro.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (C) 2019 Andrea Mazzoleni
|
||||
*
|
||||
* 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Derivative work from metrohash128.cpp
|
||||
*
|
||||
* metrohash128.cpp
|
||||
*
|
||||
* Copyright 2015-2018 J. Andrew Rogers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
static const uint64_t k0 = 0xC83A91E1;
|
||||
static const uint64_t k1 = 0x8648DBDB;
|
||||
static const uint64_t k2 = 0x7BDEC03B;
|
||||
static const uint64_t k3 = 0x2F5870A5;
|
||||
|
||||
void MetroHash128(const void* data, size_t size, const uint8_t* seed, uint8_t* digest)
|
||||
{
|
||||
const uint8_t* ptr = data;
|
||||
uint64_t v[4];
|
||||
|
||||
v[0] = (util_read64(seed) - k0) * k3;
|
||||
v[1] = (util_read64(seed + 8) + k1) * k2;
|
||||
|
||||
if (size >= 32) {
|
||||
v[2] = (util_read64(seed) + k0) * k2;
|
||||
v[3] = (util_read64(seed + 8) - k1) * k3;
|
||||
|
||||
do {
|
||||
v[0] += util_read64(ptr) * k0; ptr += 8; v[0] = util_rotr64(v[0], 29) + v[2];
|
||||
v[1] += util_read64(ptr) * k1; ptr += 8; v[1] = util_rotr64(v[1], 29) + v[3];
|
||||
v[2] += util_read64(ptr) * k2; ptr += 8; v[2] = util_rotr64(v[2], 29) + v[0];
|
||||
v[3] += util_read64(ptr) * k3; ptr += 8; v[3] = util_rotr64(v[3], 29) + v[1];
|
||||
size -= 32;
|
||||
} while (size >= 32);
|
||||
|
||||
v[2] ^= util_rotr64(((v[0] + v[3]) * k0) + v[1], 21) * k1;
|
||||
v[3] ^= util_rotr64(((v[1] + v[2]) * k1) + v[0], 21) * k0;
|
||||
v[0] ^= util_rotr64(((v[0] + v[2]) * k0) + v[3], 21) * k1;
|
||||
v[1] ^= util_rotr64(((v[1] + v[3]) * k1) + v[2], 21) * k0;
|
||||
}
|
||||
|
||||
if (size >= 16) {
|
||||
v[0] += util_read64(ptr) * k2; ptr += 8; v[0] = util_rotr64(v[0], 33) * k3;
|
||||
v[1] += util_read64(ptr) * k2; ptr += 8; v[1] = util_rotr64(v[1], 33) * k3;
|
||||
v[0] ^= util_rotr64((v[0] * k2) + v[1], 45) * k1;
|
||||
v[1] ^= util_rotr64((v[1] * k3) + v[0], 45) * k0;
|
||||
size -= 16;
|
||||
}
|
||||
|
||||
if (size >= 8) {
|
||||
v[0] += util_read64(ptr) * k2; ptr += 8; v[0] = util_rotr64(v[0], 33) * k3;
|
||||
v[0] ^= util_rotr64((v[0] * k2) + v[1], 27) * k1;
|
||||
size -= 8;
|
||||
}
|
||||
|
||||
if (size >= 4) {
|
||||
v[1] += util_read32(ptr) * k2; ptr += 4; v[1] = util_rotr64(v[1], 33) * k3;
|
||||
v[1] ^= util_rotr64((v[1] * k3) + v[0], 46) * k0;
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
if (size >= 2) {
|
||||
v[0] += util_read16(ptr) * k2; ptr += 2; v[0] = util_rotr64(v[0], 33) * k3;
|
||||
v[0] ^= util_rotr64((v[0] * k2) + v[1], 22) * k1;
|
||||
size -= 2;
|
||||
}
|
||||
|
||||
if (size >= 1) {
|
||||
v[1] += util_read8(ptr) * k2; v[1] = util_rotr64(v[1], 33) * k3;
|
||||
v[1] ^= util_rotr64((v[1] * k3) + v[0], 58) * k0;
|
||||
}
|
||||
|
||||
v[0] += util_rotr64((v[0] * k0) + v[1], 13);
|
||||
v[1] += util_rotr64((v[1] * k1) + v[0], 37);
|
||||
v[0] += util_rotr64((v[0] * k2) + v[1], 13);
|
||||
v[1] += util_rotr64((v[1] * k3) + v[0], 37);
|
||||
|
||||
util_write64(digest, v[0]);
|
||||
util_write64(digest + 8, v[0]);
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +216,7 @@ void speed(int period)
|
|||
printf("%8s", "best");
|
||||
printf("%8s", "murmur3");
|
||||
printf("%8s", "spooky2");
|
||||
printf("%8s", "metro");
|
||||
printf("\n");
|
||||
|
||||
printf("%8s", "hash");
|
||||
|
|
@ -245,6 +246,14 @@ void speed(int period)
|
|||
memhash(HASH_SPOOKY2, seed, digest, v[j], size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("%8" PRIu64, ds / dt);
|
||||
fflush(stdout);
|
||||
|
||||
SPEED_START {
|
||||
for (j = 0; j < nd; ++j)
|
||||
memhash(HASH_METRO, seed, digest, v[j], size);
|
||||
} SPEED_STOP
|
||||
|
||||
printf("%8" PRIu64, ds / dt);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
|
|
|
|||
|
|
@ -2406,6 +2406,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
|
|||
case 'k' :
|
||||
state->hash = HASH_SPOOKY2;
|
||||
break;
|
||||
case 'm' :
|
||||
state->hash = HASH_METRO;
|
||||
break;
|
||||
default :
|
||||
/* LCOV_EXCL_START */
|
||||
decoding_error(path, f);
|
||||
|
|
@ -2433,6 +2436,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
|
|||
case 'k' :
|
||||
state->prevhash = HASH_SPOOKY2;
|
||||
break;
|
||||
case 'm' :
|
||||
state->prevhash = HASH_METRO;
|
||||
break;
|
||||
default :
|
||||
/* LCOV_EXCL_START */
|
||||
decoding_error(path, f);
|
||||
|
|
@ -2955,6 +2961,8 @@ static void* state_write_thread(void* arg)
|
|||
sputc('u', f);
|
||||
} else if (state->hash == HASH_SPOOKY2) {
|
||||
sputc('k', f);
|
||||
} else if (state->hash == HASH_METRO) {
|
||||
sputc('m', f);
|
||||
} else {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Unexpected hash when writing the content file '%s'.\n", serrorfile(f));
|
||||
|
|
@ -2978,6 +2986,8 @@ static void* state_write_thread(void* arg)
|
|||
sputc('u', f);
|
||||
} else if (state->prevhash == HASH_SPOOKY2) {
|
||||
sputc('k', f);
|
||||
} else if (state->prevhash == HASH_METRO) {
|
||||
sputc('m', f);
|
||||
} else {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Unexpected prevhash when writing the content file '%s'.\n", serrorfile(f));
|
||||
|
|
|
|||
|
|
@ -470,6 +470,22 @@ static inline uint64_t util_rotl64(uint64_t x, int8_t r)
|
|||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate right.
|
||||
* In x86/x64 they are optimized with a single assembler instruction.
|
||||
*/
|
||||
#if 0 /* unused */
|
||||
static inline uint32_t util_rotr32(uint32_t x, int8_t r)
|
||||
{
|
||||
return (x >> r) | (x << (32 - r));
|
||||
}
|
||||
#endif
|
||||
static inline uint64_t util_rotr64(uint64_t x, int8_t r)
|
||||
{
|
||||
return (x >> r) | (x << (64 - r));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swap endianess.
|
||||
* They are needed only if BigEndian.
|
||||
|
|
@ -502,6 +518,18 @@ static inline uint64_t util_swap64(uint64_t v)
|
|||
}
|
||||
#endif
|
||||
|
||||
static inline uint8_t util_read8(const void* void_ptr)
|
||||
{
|
||||
const uint8_t* ptr = void_ptr;
|
||||
return ptr[0];
|
||||
}
|
||||
|
||||
static inline uint16_t util_read16(const void* void_ptr)
|
||||
{
|
||||
const uint8_t* ptr = void_ptr;
|
||||
return ptr[0] + (ptr[1] << 8);
|
||||
}
|
||||
|
||||
static inline uint32_t util_read32(const void* ptr)
|
||||
{
|
||||
uint32_t v;
|
||||
|
|
@ -543,6 +571,7 @@ static inline void util_write64(void* ptr, uint64_t v)
|
|||
|
||||
#include "murmur3.c"
|
||||
#include "spooky2.c"
|
||||
#include "metro.c"
|
||||
|
||||
void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size)
|
||||
{
|
||||
|
|
@ -553,6 +582,9 @@ void memhash(unsigned kind, const unsigned char* seed, void* digest, const void*
|
|||
case HASH_SPOOKY2 :
|
||||
SpookyHash128(src, size, seed, digest);
|
||||
break;
|
||||
case HASH_METRO :
|
||||
MetroHash128(src, size, seed, digest);
|
||||
break;
|
||||
default :
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Internal inconsistency in hash function %u\n", kind);
|
||||
|
|
@ -568,6 +600,7 @@ const char* hash_config_name(unsigned kind)
|
|||
case HASH_UNDEFINED : return "undefined";
|
||||
case HASH_MURMUR3 : return "murmur3";
|
||||
case HASH_SPOOKY2 : return "spooky2";
|
||||
case HASH_METRO : return "metro";
|
||||
default :
|
||||
/* LCOV_EXCL_START */
|
||||
return "unknown";
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ void crc32c_init(void);
|
|||
#define HASH_UNDEFINED 0
|
||||
#define HASH_MURMUR3 1
|
||||
#define HASH_SPOOKY2 2
|
||||
#define HASH_METRO 3
|
||||
|
||||
/**
|
||||
* Compute the HASH of a memory block.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue