Home | History | Annotate | Download | only in benchmarks
      1 #include <unordered_set>
      2 #include <vector>
      3 #include <functional>
      4 #include <cstdint>
      5 #include <cstdlib>
      6 #include <cstring>
      7 
      8 #include "benchmark/benchmark_api.h"
      9 
     10 #include "ContainerBenchmarks.hpp"
     11 #include "GenerateInput.hpp"
     12 
     13 using namespace ContainerBenchmarks;
     14 
     15 constexpr std::size_t TestNumInputs = 1024;
     16 
     17 template <class _Size>
     18 inline __attribute__((__always_inline__))
     19 _Size loadword(const void* __p) {
     20     _Size __r;
     21     std::memcpy(&__r, __p, sizeof(__r));
     22     return __r;
     23 }
     24 
     25 inline __attribute__((__always_inline__))
     26 std::size_t rotate_by_at_least_1(std::size_t __val, int __shift) {
     27     return (__val >> __shift) | (__val << (64 - __shift));
     28 }
     29 
     30 inline __attribute__((__always_inline__))
     31 std::size_t hash_len_16(std::size_t __u, std::size_t __v) {
     32     const  std::size_t __mul = 0x9ddfea08eb382d69ULL;
     33     std::size_t __a = (__u ^ __v) * __mul;
     34     __a ^= (__a >> 47);
     35     std::size_t __b = (__v ^ __a) * __mul;
     36     __b ^= (__b >> 47);
     37     __b *= __mul;
     38     return __b;
     39 }
     40 
     41 
     42 template <std::size_t _Len>
     43 inline __attribute__((__always_inline__))
     44 std::size_t hash_len_0_to_8(const char* __s) {
     45     static_assert(_Len == 4 || _Len == 8, "");
     46     const uint64_t __a = loadword<uint32_t>(__s);
     47     const uint64_t __b = loadword<uint32_t>(__s + _Len - 4);
     48     return hash_len_16(_Len + (__a << 3), __b);
     49 }
     50 
     51 struct UInt32Hash {
     52   UInt32Hash() = default;
     53   inline __attribute__((__always_inline__))
     54   std::size_t operator()(uint32_t data) const {
     55       return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data));
     56   }
     57 };
     58 
     59 struct UInt64Hash {
     60   UInt64Hash() = default;
     61   inline __attribute__((__always_inline__))
     62   std::size_t operator()(uint64_t data) const {
     63       return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
     64   }
     65 };
     66 
     67 struct UInt128Hash {
     68   UInt128Hash() = default;
     69   inline __attribute__((__always_inline__))
     70   std::size_t operator()(__uint128_t data) const {
     71       const __uint128_t __mask = static_cast<std::size_t>(-1);
     72       const std::size_t __a = (std::size_t)(data & __mask);
     73       const std::size_t __b = (std::size_t)((data & (__mask << 64)) >> 64);
     74       return hash_len_16(__a, rotate_by_at_least_1(__b + 16, 16)) ^ __b;
     75   }
     76 };
     77 
     78 struct UInt32Hash2 {
     79   UInt32Hash2() = default;
     80   inline __attribute__((__always_inline__))
     81   std::size_t operator()(uint32_t data) const {
     82       const uint32_t __m = 0x5bd1e995;
     83       const uint32_t __r = 24;
     84       uint32_t __h = 4;
     85       uint32_t __k = data;
     86         __k *= __m;
     87         __k ^= __k >> __r;
     88         __k *= __m;
     89         __h *= __m;
     90         __h ^= __k;
     91         __h ^= __h >> 13;
     92         __h *= __m;
     93         __h ^= __h >> 15;
     94     return __h;
     95   }
     96 };
     97 
     98 struct UInt64Hash2 {
     99   UInt64Hash2() = default;
    100   inline __attribute__((__always_inline__))
    101   std::size_t operator()(uint64_t data) const {
    102       return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
    103   }
    104 };
    105 
    106 //----------------------------------------------------------------------------//
    107 //                               BM_Hash
    108 // ---------------------------------------------------------------------------//
    109 
    110 template <class HashFn, class GenInputs>
    111 void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
    112     auto in = gen(st.range(0));
    113     const auto end = in.data() + in.size();
    114     std::size_t last_hash = 0;
    115     benchmark::DoNotOptimize(&last_hash);
    116     while (st.KeepRunning()) {
    117         for (auto it = in.data(); it != end; ++it) {
    118             benchmark::DoNotOptimize(last_hash += fn(*it));
    119         }
    120         benchmark::ClobberMemory();
    121     }
    122 }
    123 
    124 BENCHMARK_CAPTURE(BM_Hash,
    125     uint32_random_std_hash,
    126     std::hash<uint32_t>{},
    127     getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
    128 
    129 BENCHMARK_CAPTURE(BM_Hash,
    130     uint32_random_custom_hash,
    131     UInt32Hash{},
    132     getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
    133 
    134 BENCHMARK_CAPTURE(BM_Hash,
    135     uint32_top_std_hash,
    136     std::hash<uint32_t>{},
    137     getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
    138 
    139 BENCHMARK_CAPTURE(BM_Hash,
    140     uint32_top_custom_hash,
    141     UInt32Hash{},
    142     getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
    143 
    144 
    145 //----------------------------------------------------------------------------//
    146 //                       BM_InsertValue
    147 // ---------------------------------------------------------------------------//
    148 
    149 
    150 // Sorted Assending //
    151 BENCHMARK_CAPTURE(BM_InsertValue,
    152     unordered_set_uint32,
    153     std::unordered_set<uint32_t>{},
    154     getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    155 
    156 BENCHMARK_CAPTURE(BM_InsertValue,
    157     unordered_set_uint32_sorted,
    158     std::unordered_set<uint32_t>{},
    159     getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    160 
    161 // Top Bytes //
    162 BENCHMARK_CAPTURE(BM_InsertValue,
    163     unordered_set_top_bits_uint32,
    164     std::unordered_set<uint32_t>{},
    165     getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    166 
    167 BENCHMARK_CAPTURE(BM_InsertValueRehash,
    168     unordered_set_top_bits_uint32,
    169     std::unordered_set<uint32_t, UInt32Hash>{},
    170     getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    171 
    172 // String //
    173 BENCHMARK_CAPTURE(BM_InsertValue,
    174     unordered_set_string,
    175     std::unordered_set<std::string>{},
    176     getRandomStringInputs)->Arg(TestNumInputs);
    177 
    178 BENCHMARK_CAPTURE(BM_InsertValueRehash,
    179     unordered_set_string,
    180     std::unordered_set<std::string>{},
    181     getRandomStringInputs)->Arg(TestNumInputs);
    182 
    183 //----------------------------------------------------------------------------//
    184 //                         BM_Find
    185 // ---------------------------------------------------------------------------//
    186 
    187 // Random //
    188 BENCHMARK_CAPTURE(BM_Find,
    189     unordered_set_random_uint64,
    190     std::unordered_set<uint64_t>{},
    191     getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    192 
    193 BENCHMARK_CAPTURE(BM_FindRehash,
    194     unordered_set_random_uint64,
    195     std::unordered_set<uint64_t, UInt64Hash>{},
    196     getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    197 
    198 // Sorted //
    199 BENCHMARK_CAPTURE(BM_Find,
    200     unordered_set_sorted_uint64,
    201     std::unordered_set<uint64_t>{},
    202     getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    203 
    204 BENCHMARK_CAPTURE(BM_FindRehash,
    205     unordered_set_sorted_uint64,
    206     std::unordered_set<uint64_t, UInt64Hash>{},
    207     getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    208 
    209 
    210 // Sorted //
    211 #if 1
    212 BENCHMARK_CAPTURE(BM_Find,
    213     unordered_set_sorted_uint128,
    214     std::unordered_set<__uint128_t, UInt128Hash>{},
    215     getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
    216 
    217 BENCHMARK_CAPTURE(BM_FindRehash,
    218     unordered_set_sorted_uint128,
    219     std::unordered_set<__uint128_t, UInt128Hash>{},
    220     getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
    221 #endif
    222 
    223 // Sorted //
    224 BENCHMARK_CAPTURE(BM_Find,
    225     unordered_set_sorted_uint32,
    226     std::unordered_set<uint32_t>{},
    227     getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    228 
    229 BENCHMARK_CAPTURE(BM_FindRehash,
    230     unordered_set_sorted_uint32,
    231     std::unordered_set<uint32_t, UInt32Hash2>{},
    232     getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
    233 
    234 // Sorted Ascending //
    235 BENCHMARK_CAPTURE(BM_Find,
    236     unordered_set_sorted_large_uint64,
    237     std::unordered_set<uint64_t>{},
    238     getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    239 
    240 BENCHMARK_CAPTURE(BM_FindRehash,
    241     unordered_set_sorted_large_uint64,
    242     std::unordered_set<uint64_t, UInt64Hash>{},
    243     getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    244 
    245 
    246 // Top Bits //
    247 BENCHMARK_CAPTURE(BM_Find,
    248     unordered_set_top_bits_uint64,
    249     std::unordered_set<uint64_t>{},
    250     getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    251 
    252 BENCHMARK_CAPTURE(BM_FindRehash,
    253     unordered_set_top_bits_uint64,
    254     std::unordered_set<uint64_t, UInt64Hash>{},
    255     getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
    256 
    257 // String //
    258 BENCHMARK_CAPTURE(BM_Find,
    259     unordered_set_string,
    260     std::unordered_set<std::string>{},
    261     getRandomStringInputs)->Arg(TestNumInputs);
    262 
    263 BENCHMARK_CAPTURE(BM_FindRehash,
    264     unordered_set_string,
    265     std::unordered_set<std::string>{},
    266     getRandomStringInputs)->Arg(TestNumInputs);
    267 
    268 ///////////////////////////////////////////////////////////////////////////////
    269 BENCHMARK_CAPTURE(BM_InsertDuplicate,
    270     unordered_set_int,
    271     std::unordered_set<int>{},
    272     getRandomIntegerInputs<int>)->Arg(TestNumInputs);
    273 BENCHMARK_CAPTURE(BM_InsertDuplicate,
    274     unordered_set_string,
    275     std::unordered_set<std::string>{},
    276     getRandomStringInputs)->Arg(TestNumInputs);
    277 
    278 BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
    279     unordered_set_int,
    280     std::unordered_set<int>{},
    281     getRandomIntegerInputs<int>)->Arg(TestNumInputs);
    282 BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
    283     unordered_set_string,
    284     std::unordered_set<std::string>{},
    285     getRandomStringInputs)->Arg(TestNumInputs);
    286 
    287 BENCHMARK_CAPTURE(BM_InsertDuplicate,
    288     unordered_set_int_insert_arg,
    289     std::unordered_set<int>{},
    290     getRandomIntegerInputs<int>)->Arg(TestNumInputs);
    291 BENCHMARK_CAPTURE(BM_InsertDuplicate,
    292     unordered_set_string_insert_arg,
    293     std::unordered_set<std::string>{},
    294     getRandomStringInputs)->Arg(TestNumInputs);
    295 
    296 BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
    297     unordered_set_int_insert_arg,
    298     std::unordered_set<int>{},
    299     getRandomIntegerInputs<unsigned>)->Arg(TestNumInputs);
    300 
    301 BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
    302     unordered_set_string_arg,
    303     std::unordered_set<std::string>{},
    304     getRandomCStringInputs)->Arg(TestNumInputs);
    305 
    306 BENCHMARK_MAIN()
    307