Last active
May 25, 2020 13:43
-
-
Save nmoinvaz/e0931461822440a5ab7aae077fa60889 to your computer and use it in GitHub Desktop.
Google benchmark for zlib-ng hashing functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* hash_benchmark.cc -- test hash function variants | |
* Copyright (C) 2020 Nathan Moinvaziri | |
* For conditions of distribution and use, see copyright notice in zlib.h | |
*/ | |
/* | |
cmake . -A Win32 -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL -DBUILD_SHARED_LIBS=OFF | |
cmake_minimum_required(VERSION 3.17) | |
project(hash_benchmark) | |
add_executable(hash_benchmark) | |
target_sources(hash_benchmark PRIVATE hash_benchmark.cc) | |
target_include_directories(hash_benchmark PRIVATE benchmark/include) | |
target_link_directories(hash_benchmark PRIVATE benchmark/build/src/Release) | |
target_link_libraries(hash_benchmark benchmark shlwapi) | |
*/ | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <immintrin.h> | |
#ifdef _MSC_VER | |
# include <nmmintrin.h> | |
#endif | |
#include <benchmark/benchmark.h> | |
#define MAX_RANDOM_INTS (1024 * 1024) | |
static uint32_t *random_ints = NULL; | |
static inline uint32_t crc32_hash(uint32_t val) { | |
return _mm_crc32_u32(0, val); | |
} | |
static inline uint32_t zlib_hash(uint32_t val) { | |
return ((val & 0xff) << 8) ^ ((val >> 16) & 0xff); | |
} | |
static inline uint32_t zlib_ng_hash(uint32_t val) { | |
return ((3483 * ((val) & 0xff)) + | |
(23081 * (((val) >> 8) & 0xff)) + | |
(6954 * (((val) >> 16) & 0xff)) + | |
(20947 * (((val) >> 24) & 0xff))); | |
} | |
static inline uint32_t knuth_hash(uint32_t val) { | |
return (val * 2654435761) >> (32 - 15); | |
} | |
static inline uint32_t knuth_hash_mod(uint32_t val) { | |
val ^= val >> (32 - 15); | |
return (val * 2654435761) >> (32 - 15); | |
} | |
static inline uint32_t fib_hash(uint32_t val) { | |
return (uint64_t)(((uint64_t)val * 11400714819323198485ULL) >> (12)); | |
} | |
static inline uint32_t fib_hash_mod(uint32_t val) { | |
uint64_t val64 = (uint64_t)val; | |
val64 ^= val64 >> (12); | |
return (uint32_t)((val64 * 11400714819323198485ULL) >> (12)); | |
} | |
static void crc32_hash_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = crc32_hash(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(crc32_hash_bench); | |
static void zlib_hash_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = zlib_hash(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(zlib_hash_bench); | |
static void zlib_ng_hash_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = zlib_ng_hash(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(zlib_ng_hash_bench); | |
static void knuth_hash_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = knuth_hash(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(knuth_hash_bench); | |
static void knuth_hash_mod_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = knuth_hash_mod(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(knuth_hash_mod_bench); | |
static void fib_hash_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = fib_hash(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(fib_hash_bench); | |
static void fib_hash_mod_bench(benchmark::State& state) { | |
int32_t j = 0; | |
while (state.KeepRunning()) { | |
uint32_t hash = fib_hash_mod(random_ints[j]); | |
benchmark::DoNotOptimize(hash); | |
if (++j >= MAX_RANDOM_INTS) j = 0; | |
} | |
} | |
BENCHMARK(fib_hash_mod_bench); | |
int main(int argc, char** argv) | |
{ | |
int32_t random_ints_size = MAX_RANDOM_INTS * sizeof(uint32_t); | |
random_ints = (uint32_t *)malloc(random_ints_size); | |
for (int32_t i = 0; i < MAX_RANDOM_INTS; i++) { | |
random_ints[i] = rand(); | |
} | |
::benchmark::Initialize(&argc, argv); | |
::benchmark::RunSpecifiedBenchmarks(); | |
free(random_ints); | |
} |
If you want to play around with it, it can be found here:
http://quick-bench.com/kKBjZnuTo-E0Dw1EVJJ2anADZYo
It is also possible to view the Compiler Explorer output of the code from that page to view the disassembly.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Results from Google benchmark: