123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #include <unordered_set>
- #include <vector>
- #include <functional>
- #include <cstdint>
- #include <cstdlib>
- #include <cstring>
- #include "benchmark/benchmark_api.h"
- #include "ContainerBenchmarks.hpp"
- #include "GenerateInput.hpp"
- using namespace ContainerBenchmarks;
- constexpr std::size_t TestNumInputs = 1024;
- template <class _Size>
- inline __attribute__((__always_inline__))
- _Size loadword(const void* __p) {
- _Size __r;
- std::memcpy(&__r, __p, sizeof(__r));
- return __r;
- }
- inline __attribute__((__always_inline__))
- std::size_t rotate_by_at_least_1(std::size_t __val, int __shift) {
- return (__val >> __shift) | (__val << (64 - __shift));
- }
- inline __attribute__((__always_inline__))
- std::size_t hash_len_16(std::size_t __u, std::size_t __v) {
- const std::size_t __mul = 0x9ddfea08eb382d69ULL;
- std::size_t __a = (__u ^ __v) * __mul;
- __a ^= (__a >> 47);
- std::size_t __b = (__v ^ __a) * __mul;
- __b ^= (__b >> 47);
- __b *= __mul;
- return __b;
- }
- template <std::size_t _Len>
- inline __attribute__((__always_inline__))
- std::size_t hash_len_0_to_8(const char* __s) {
- static_assert(_Len == 4 || _Len == 8, "");
- const uint64_t __a = loadword<uint32_t>(__s);
- const uint64_t __b = loadword<uint32_t>(__s + _Len - 4);
- return hash_len_16(_Len + (__a << 3), __b);
- }
- struct UInt32Hash {
- UInt32Hash() = default;
- inline __attribute__((__always_inline__))
- std::size_t operator()(uint32_t data) const {
- return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data));
- }
- };
- struct UInt64Hash {
- UInt64Hash() = default;
- inline __attribute__((__always_inline__))
- std::size_t operator()(uint64_t data) const {
- return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
- }
- };
- struct UInt128Hash {
- UInt128Hash() = default;
- inline __attribute__((__always_inline__))
- std::size_t operator()(__uint128_t data) const {
- const __uint128_t __mask = static_cast<std::size_t>(-1);
- const std::size_t __a = (std::size_t)(data & __mask);
- const std::size_t __b = (std::size_t)((data & (__mask << 64)) >> 64);
- return hash_len_16(__a, rotate_by_at_least_1(__b + 16, 16)) ^ __b;
- }
- };
- struct UInt32Hash2 {
- UInt32Hash2() = default;
- inline __attribute__((__always_inline__))
- std::size_t operator()(uint32_t data) const {
- const uint32_t __m = 0x5bd1e995;
- const uint32_t __r = 24;
- uint32_t __h = 4;
- uint32_t __k = data;
- __k *= __m;
- __k ^= __k >> __r;
- __k *= __m;
- __h *= __m;
- __h ^= __k;
- __h ^= __h >> 13;
- __h *= __m;
- __h ^= __h >> 15;
- return __h;
- }
- };
- struct UInt64Hash2 {
- UInt64Hash2() = default;
- inline __attribute__((__always_inline__))
- std::size_t operator()(uint64_t data) const {
- return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
- }
- };
- //----------------------------------------------------------------------------//
- // BM_Hash
- // ---------------------------------------------------------------------------//
- template <class HashFn, class GenInputs>
- void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
- auto in = gen(st.range_x());
- const auto end = in.data() + in.size();
- std::size_t last_hash = 0;
- benchmark::DoNotOptimize(&last_hash);
- while (st.KeepRunning()) {
- for (auto it = in.data(); it != end; ++it) {
- benchmark::DoNotOptimize(last_hash += fn(*it));
- }
- benchmark::ClobberMemory();
- }
- }
- BENCHMARK_CAPTURE(BM_Hash,
- uint32_random_std_hash,
- std::hash<uint32_t>{},
- getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_Hash,
- uint32_random_custom_hash,
- UInt32Hash{},
- getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_Hash,
- uint32_top_std_hash,
- std::hash<uint32_t>{},
- getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_Hash,
- uint32_top_custom_hash,
- UInt32Hash{},
- getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
- //----------------------------------------------------------------------------//
- // BM_InsertValue
- // ---------------------------------------------------------------------------//
- // Sorted Assending //
- BENCHMARK_CAPTURE(BM_InsertValue,
- unordered_set_uint32,
- std::unordered_set<uint32_t>{},
- getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertValue,
- unordered_set_uint32_sorted,
- std::unordered_set<uint32_t>{},
- getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- // Top Bytes //
- BENCHMARK_CAPTURE(BM_InsertValue,
- unordered_set_top_bits_uint32,
- std::unordered_set<uint32_t>{},
- getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertValueRehash,
- unordered_set_top_bits_uint32,
- std::unordered_set<uint32_t, UInt32Hash>{},
- getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- // String //
- BENCHMARK_CAPTURE(BM_InsertValue,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertValueRehash,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- //----------------------------------------------------------------------------//
- // BM_Find
- // ---------------------------------------------------------------------------//
- // Random //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_random_uint64,
- std::unordered_set<uint64_t>{},
- getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_random_uint64,
- std::unordered_set<uint64_t, UInt64Hash>{},
- getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- // Sorted //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_sorted_uint64,
- std::unordered_set<uint64_t>{},
- getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_sorted_uint64,
- std::unordered_set<uint64_t, UInt64Hash>{},
- getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- // Sorted //
- #if 1
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_sorted_uint128,
- std::unordered_set<__uint128_t, UInt128Hash>{},
- getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_sorted_uint128,
- std::unordered_set<__uint128_t, UInt128Hash>{},
- getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
- #endif
- // Sorted //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_sorted_uint32,
- std::unordered_set<uint32_t>{},
- getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_sorted_uint32,
- std::unordered_set<uint32_t, UInt32Hash2>{},
- getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
- // Sorted Ascending //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_sorted_large_uint64,
- std::unordered_set<uint64_t>{},
- getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_sorted_large_uint64,
- std::unordered_set<uint64_t, UInt64Hash>{},
- getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- // Top Bits //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_top_bits_uint64,
- std::unordered_set<uint64_t>{},
- getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_top_bits_uint64,
- std::unordered_set<uint64_t, UInt64Hash>{},
- getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
- // String //
- BENCHMARK_CAPTURE(BM_Find,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_FindRehash,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- ///////////////////////////////////////////////////////////////////////////////
- BENCHMARK_CAPTURE(BM_InsertDuplicate,
- unordered_set_int,
- std::unordered_set<int>{},
- getRandomIntegerInputs<int>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertDuplicate,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
- unordered_set_int,
- std::unordered_set<int>{},
- getRandomIntegerInputs<int>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
- unordered_set_string,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertDuplicate,
- unordered_set_int_insert_arg,
- std::unordered_set<int>{},
- getRandomIntegerInputs<int>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_InsertDuplicate,
- unordered_set_string_insert_arg,
- std::unordered_set<std::string>{},
- getRandomStringInputs)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
- unordered_set_int_insert_arg,
- std::unordered_set<int>{},
- getRandomIntegerInputs<unsigned>)->Arg(TestNumInputs);
- BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
- unordered_set_string_arg,
- std::unordered_set<std::string>{},
- getRandomCStringInputs)->Arg(TestNumInputs);
- BENCHMARK_MAIN()
|