Skip to content

Instantly share code, notes, and snippets.

@nmoinvaz
Last active May 25, 2020 13:43
Show Gist options
  • Save nmoinvaz/e0931461822440a5ab7aae077fa60889 to your computer and use it in GitHub Desktop.
Save nmoinvaz/e0931461822440a5ab7aae077fa60889 to your computer and use it in GitHub Desktop.
Google benchmark for zlib-ng hashing functions
/* 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);
}
@nmoinvaz
Copy link
Author

nmoinvaz commented May 7, 2020

Results from Google benchmark:

image

@nmoinvaz
Copy link
Author

nmoinvaz commented May 7, 2020

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.

@nmoinvaz
Copy link
Author

nmoinvaz commented May 10, 2020

I have added crc32 intrinics comparison:

image

So we see that crc32 and knuth are best performers speed-wise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment