From feaac16804fe93ce0d6b26f71694b6c32f638d74 Mon Sep 17 00:00:00 2001 From: Leonardo Vencovsky Date: Fri, 19 Jun 2020 22:37:25 -0300 Subject: [PATCH] Update benchmark --- benchmarks/C++ Comparison/hashtable/hashmap.c | 48 +++++++++----- .../C++ Comparison/hashtable/hashmultimap.c | 61 ++++++++++++++++++ .../C++ Comparison/hashtable/murmurhash.h | 58 +++++++++++++++++ benchmarks/C++ Comparison/hashtable/script.py | 63 +++++++++---------- .../C++ Comparison/hashtable/unorderedmap.cpp | 26 ++++++-- 5 files changed, 204 insertions(+), 52 deletions(-) create mode 100644 benchmarks/C++ Comparison/hashtable/hashmultimap.c create mode 100644 benchmarks/C++ Comparison/hashtable/murmurhash.h diff --git a/benchmarks/C++ Comparison/hashtable/hashmap.c b/benchmarks/C++ Comparison/hashtable/hashmap.c index d2c4dbe..5956b8b 100644 --- a/benchmarks/C++ Comparison/hashtable/hashmap.c +++ b/benchmarks/C++ Comparison/hashtable/hashmap.c @@ -2,32 +2,42 @@ #error "Please define COUNT" #endif -#include "cmc/hashmap.h" +#include "murmurhash.h" -CMC_CMC_HASHMAP_CORE(PUBLIC, HEADER, (hmi32, hashmapi32, , int32_t, int32_t)) -CMC_CMC_HASHMAP_CORE(PUBLIC, SOURCE, (hmi32, hashmapi32, , int32_t, int32_t)) +#include "macro_collections.h" -int cmp(int32_t a, int32_t b) +#include "../../util/twister.c" + +CMC_CMC_HASHMAP_CORE(PUBLIC, HEADER, (hm, hashmap, , uint64_t, uint64_t)) +CMC_CMC_HASHMAP_CORE(PUBLIC, SOURCE, (hm, hashmap, , uint64_t, uint64_t)) + +int cmp(uint64_t a, uint64_t b) { return (a > b) - (a < b); } -size_t hash(int32_t a) +// size_t hash(uint64_t a) +// { +// size_t x = (size_t)a; +// x = ((x >> 16) ^ x) * 0x45d9f3b; +// x = ((x >> 16) ^ x) * 0x45d9f3b; +// x = (x >> 16) ^ x; +// return x; +// } + +size_t hash(uint64_t k) { - size_t x = (size_t)a; - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = (x >> 16) ^ x; - return x; + static size_t seed = 211106232532969; + return MurMurHash(&k, sizeof(k), seed); } -struct hashmapi32_fkey *fkey = &(struct hashmapi32_fkey) { +struct hashmap_fkey *fkey = &(struct hashmap_fkey) { .cmp = cmp, .hash = hash, NULL }; -struct hashmapi32_fval *fval = &(struct hashmapi32_fval) { +struct hashmap_fval *fval = &(struct hashmap_fval) { .cmp = cmp, .hash = hash, NULL @@ -35,12 +45,18 @@ struct hashmapi32_fval *fval = &(struct hashmapi32_fval) { int main(void) { - struct hashmapi32 *map = hmi32_new(COUNT, 0.6, fkey, fval); + mt_state tw; + twist_init(&tw, 50331653); - for (int32_t i = 0; i < COUNT; i++) - hmi32_insert(map, i, i); + struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval); - hmi32_free(map); + for (uint64_t i = 0; i < COUNT; i++) + { + uint64_t v = twist_uint64(&tw); + hm_insert(map, v, v); + } + + hm_free(map); return 0; } diff --git a/benchmarks/C++ Comparison/hashtable/hashmultimap.c b/benchmarks/C++ Comparison/hashtable/hashmultimap.c new file mode 100644 index 0000000..2bac19a --- /dev/null +++ b/benchmarks/C++ Comparison/hashtable/hashmultimap.c @@ -0,0 +1,61 @@ +#ifndef COUNT +#error "Please define COUNT" +#endif + +#include "murmurhash.h" + +#include "macro_collections.h" + +#include "../../util/twister.c" + +C_MACRO_COLLECTIONS_ALL(CMC, HASHMULTIMAP, (hmm, hashmultimap, , uint64_t, uint64_t)) + +int cmp(uint64_t a, uint64_t b) +{ + return (a > b) - (a < b); +} + +// size_t hash(uint64_t a) +// { +// size_t x = (size_t)a; +// x = ((x >> 16) ^ x) * 0x45d9f3b; +// x = ((x >> 16) ^ x) * 0x45d9f3b; +// x = (x >> 16) ^ x; +// return x; +// } + +size_t hash(uint64_t k) +{ + static size_t seed = 211106232532969; + return MurMurHash(&k, sizeof(k), seed); +} + +struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey) { + .cmp = cmp, + .hash = hash, + NULL +}; + +struct hashmultimap_fval *fval = &(struct hashmultimap_fval) { + .cmp = cmp, + .hash = hash, + NULL +}; + +int main(void) +{ + mt_state tw; + twist_init(&tw, 50331653); + + struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval); + + for (uint64_t i = 0; i < COUNT; i++) + { + uint64_t v = twist_uint64(&tw); + hmm_insert(map, v, v); + } + + hmm_free(map); + + return 0; +} diff --git a/benchmarks/C++ Comparison/hashtable/murmurhash.h b/benchmarks/C++ Comparison/hashtable/murmurhash.h new file mode 100644 index 0000000..a334dd9 --- /dev/null +++ b/benchmarks/C++ Comparison/hashtable/murmurhash.h @@ -0,0 +1,58 @@ +// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc + +#ifndef MURMURHASH +#define MURMURHASH + +#include + +inline size_t unaligned_load(const char *p) +{ + size_t result; + memcpy(&result, p, sizeof(result)); + return result; +} + +inline size_t load_bytes(const char *p, int n) +{ + size_t result = 0; + --n; + do + { + result = (result << 8) + (unsigned char)(p[n]); + } while (--n >= 0); + return result; +} + +inline size_t shift_mix(size_t v) +{ + return v ^ (v >> 47); +} + +size_t MurMurHash(const void *ptr, size_t len, size_t seed) +{ + static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL; + const char *const buf = (const char *)(ptr); + + // Remove the bytes not divisible by the sizeof(size_t). This + // allows the main loop to process the data as 64-bit integers. + const size_t len_aligned = len & ~(size_t)0x7; + const char *const end = buf + len_aligned; + size_t hash = seed ^ (len * mul); + for (const char *p = buf; p != end; p += 8) + { + const size_t data = shift_mix(unaligned_load(p) * mul) * mul; + hash ^= data; + hash *= mul; + } + if ((len & 0x7) != 0) + { + const size_t data = load_bytes(end, len & 0x7); + hash ^= data; + hash *= mul; + } + hash = shift_mix(hash) * mul; + hash = shift_mix(hash); + return hash; +} + +#endif /* MURMURHASH */ diff --git a/benchmarks/C++ Comparison/hashtable/script.py b/benchmarks/C++ Comparison/hashtable/script.py index bcda9fb..bd939ec 100644 --- a/benchmarks/C++ Comparison/hashtable/script.py +++ b/benchmarks/C++ Comparison/hashtable/script.py @@ -1,8 +1,10 @@ +import os import sys import time import subprocess ITERATIONS = 10 +COUNT = 20000000 VERBOSE = False NL = '\n' @@ -11,48 +13,45 @@ INCLUDE = "../../../src" CC = 'gcc' CCPP = 'g++' # LoL OPT = '-O3' -COUNT = 2000000 + +print(f'Using {CC} compiler') + + +def execute_command(commands): + print(' '.join(commands)) + subprocess.run(commands, shell=True) + # Common args args = ['-I', INCLUDE, OPT, f'-DCOUNT={COUNT}', '-DCMC_NO_CALLBACKS'] -c_args = [CC, 'hashmap.c', '-o', 'hashmap.exe'] +map_args = [CC, 'hashmap.c', '-o', 'hashmap.exe'] +mmap_args = [CC, 'hashmultimap.c', '-o', 'hashmultimap.exe'] cpp_args = [CCPP, 'unorderedmap.cpp', '-I', INCLUDE, '-o', 'unorderedmap.exe', OPT, f'-DCOUNT={COUNT}'] -c_args.extend(args) +map_args.extend(args) +mmap_args.extend(args) cpp_args.extend(args) -subprocess.check_output(c_args) -subprocess.check_output(cpp_args) +execute_command(map_args) +execute_command(mmap_args) +execute_command(cpp_args) -total = 0 -for i in range(ITERATIONS): - print(f'{i}...', end='') - sys.stdout.flush() - start_time = time.time() - subprocess.call(['./hashmap.exe']) +programs = ['hashmap.exe', 'hashmultimap.exe', 'unorderedmap.exe'] - delta = time.time() - start_time - total += delta +for prog in programs: + total = 0 + for i in range(ITERATIONS): + print(f'{i}...', end='') + sys.stdout.flush() + start_time = time.time() + subprocess.run(prog, shell=True) - if VERBOSE: - print(f'({delta})') + delta = time.time() - start_time + total += delta -avg = int(((total / ITERATIONS) * 1e9) / COUNT) -print(f'{"" if VERBOSE else NL}{total / ITERATIONS} seconds for {COUNT} -> AVG[{avg} ns] [hashmap.exe]{NL if VERBOSE else ""}') + if VERBOSE: + print(f'({delta})') -total = 0 -for i in range(ITERATIONS): - print(f'{i}...', end='') - sys.stdout.flush() - start_time = time.time() - subprocess.call(['./unorderedmap.exe']) - - delta = time.time() - start_time - total += delta - - if VERBOSE: - print(f'({delta})') - -avg = int(((total / ITERATIONS) * 1e9) / COUNT) -print(f'{"" if VERBOSE else NL}{total / ITERATIONS} seconds for {COUNT} -> AVG[{avg} ns] [unorderedmap.exe]{NL if VERBOSE else ""}') + avg = total / ITERATIONS + print(f'{"" if VERBOSE else NL}{avg} seconds for {COUNT} -> AVG[{int((avg * 1e9) / COUNT)} ns] [{prog}]{NL if VERBOSE else ""}') diff --git a/benchmarks/C++ Comparison/hashtable/unorderedmap.cpp b/benchmarks/C++ Comparison/hashtable/unorderedmap.cpp index 72cbf0b..5f59f00 100644 --- a/benchmarks/C++ Comparison/hashtable/unorderedmap.cpp +++ b/benchmarks/C++ Comparison/hashtable/unorderedmap.cpp @@ -2,15 +2,33 @@ #error "Please define COUNT" #endif +#include "murmurhash.h" + #include -#include + +#include "../../util/twister.c" + +struct IntHasher +{ + std::size_t operator()(const uint64_t& k) const + { + static size_t seed = 211106232532969; + return MurMurHash(&k, sizeof(k), seed); + } +}; int main(void) { - std::unordered_map map(COUNT); + mt_state tw; + twist_init(&tw, 50331653); - for (int32_t i = 0; i < COUNT; i++) - map.insert({i, i}); + std::unordered_map map(COUNT); + + for (uint64_t i = 0; i < COUNT; i++) + { + uint64_t v = twist_uint64(&tw); + map.insert({v, v}); + } return 0; }