libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hash.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE libjmmcg_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include "core/hash.hpp"
25 #include "core/stats_output.hpp"
26 
27 #include <algorithm>
28 #include <iostream>
29 #include <iterator>
30 #include <vector>
31 
32 #include "core/ave_deviation_meter.hpp"
33 
34 #include "absl/hash/hash.h"
35 // TODO #include "folly/hash/Hash.h"
36 #include "src/include/robin_hood.h"
37 
38 #include <boost/functional/hash.hpp>
39 
40 #include <array>
41 #include <chrono>
42 
43 using namespace libjmmcg;
44 
45 const std::array guids{
46  "FA6AF2C3-5957-48CE-A45D-338A71CA5CC1",
47  "D3DA1A9B-DC2A-47A0-9812-A5071CACD4E8",
48  "2B482B48-69C4-469F-9DB2-FF79DED69CFE",
49  "8DA78ED6-8FE2-4C96-A0A7-FF6DB0CEFCFD",
50  "5CA0C6D0-4516-4C26-9C8D-EF159C83CC66",
51  "7B519D94-89C3-4E5C-B3D4-0DE31545CA84",
52  "31652501-0B76-4BFA-B973-8ABC0C95578B",
53  "AC8DDD15-E763-41F0-A111-4100F80DF5BF",
54  "142F635A-6DAA-4F5C-9CD2-93379779FD67",
55  "9609C637-E667-4307-9B16-D20483E6D4DB",
56  "7CA9EA22-D056-4C2B-8C4F-681B4A4AF0FA",
57  "F1DCA9C9-E1AF-4844-A52F-97B5356876E8",
58  "F025908C-9DD6-424A-85A5-1DF65B1973FC",
59  "884C6532-4A3E-4BAE-9D84-7827DEF2B6F1",
60  "C876839F-9EFA-484E-85F8-10D2D67A9738",
61  "3D85A56A-1177-486D-80D3-9A26A47B8905"
62 };
63 
64 /**
65  * \todo Consider using hashes from <a href="https://martin.ankerl.com/2019/04/01/hashmap-benchmarks-01-overview/"/>.
66  */
67 struct abseil_t : absl::Hash<std::string> {
68  using result_type=std::size_t;
69 };
71  using result_type=std::size_t;
72 };
73 using murmur2_t=hashers::murmur2<std::string>;
74 using hsieh_t=hashers::hsieh<std::string>;
75 using hsieh_mpl_t=hashers::mpl::hsieh<std::string, 36>;
76 using hashes_t=std::vector<murmur2_t::result_type>;
77 using timed_results_t=ave_deviation_meter<unsigned long long>;
78 
79 template<class H> void __fastcall
80 hashem(std::ostream &, std::vector<typename H::result_type> &hashes) {
81  typedef std::vector<typename H::result_type> hashes_t;
82  hashes.reserve(guids.size());
83  std::transform(
84  guids.begin(),
85  guids.end(),
86  std::back_insert_iterator<hashes_t>(hashes),
87  H()
88  );
89 // std::copy(hashes.begin(), hashes.end(), std::ostream_iterator<hashes_t::value_type>(os, "\n"));
90  hashes.clear();
91 }
92 
93 template<class H> void __fastcall
94 do_hashing(std::ostream &os, const int num_hashes) {
95  typedef std::vector<typename H::result_type> hashes_t;
96 
97  const unsigned short loops_for_conv=50;
98  const double perc_conv_estimate=5.0;
99 
100  const std::pair<timed_results_t, bool> timed_results(compute_average_deviation<timed_results_t::value_type>(
101  perc_conv_estimate,
102  loops_for_conv,
103  [num_hashes, &os]() {
104  hashes_t hashes;
105  const auto t1=std::chrono::high_resolution_clock::now();
106  for (int i=0; i<num_hashes; ++i) {
107  hashem<H>(os, hashes);
108  }
109  const auto t2=std::chrono::high_resolution_clock::now();
110  return timed_results_t::value_type(static_cast<double>(num_hashes*sizeof(guids)/sizeof(guids[0]))/(static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count())/1000000));
111  }
112  ));
113  std::cout<<typeid(H).name()<<" hashes/sec="<<timed_results.first<<std::endl;
114 #ifdef JMMCG_PERFORMANCE_TESTS
115  os<<timed_results.first.to_csv()<<std::flush;
116  BOOST_CHECK(!timed_results.second);
117 #endif
118 }
119 
120 BOOST_AUTO_TEST_SUITE(hashing)
121 
122 BOOST_AUTO_TEST_CASE(create_murmur2) {
123  [[maybe_unused]] murmur2_t hasher;
124 }
125 
126 BOOST_AUTO_TEST_CASE(create_hsieh) {
127  [[maybe_unused]] hsieh_t hasher;
128 }
129 
130 BOOST_AUTO_TEST_CASE(create_hsieh_mpl) {
131  [[maybe_unused]] hsieh_mpl_t hasher;
132 }
133 
134 BOOST_AUTO_TEST_CASE(hash_murmur2) {
135  murmur2_t hasher;
136  BOOST_CHECK(hasher(guids[0])!=0);
137 }
138 
139 BOOST_AUTO_TEST_CASE(hash_hsieh) {
140  hsieh_t hasher;
141  BOOST_CHECK(hasher(guids[0])!=0);
142 }
143 
144 BOOST_AUTO_TEST_CASE(hash_hsieh_mpl) {
145  hsieh_mpl_t hasher;
146  BOOST_CHECK(hasher(guids[0])!=0);
147 }
148 
149 BOOST_AUTO_TEST_SUITE(performance, *stats_to_csv::make_fixture("hash.csv"))
150 
151 /**
152  \test <a href="./examples/hash.svg">Graph</a> of performance results for the various hash functions.
153  ==========================================================================================
154  Results for 1000000 repetitions:
155  -# Build 1402: g++v4.7.3, boost v1.54:
156  - hashers::murmur2 = 9.53073e+06 hashes/sec
157  - hashers::hsieh = 8.69376e+06 hashes/sec
158  - hashers::mpl::hsieh = 9.82567e+06 hashes/sec
159  - boost::hash = 6.15003e+06 hashes/sec
160  - std::hash = 9.74447e+06 hashes/sec
161  -# Build 1627: g++v4.8.4, boost v1.56:
162  - hashers::murmur2 = 9.477643e+06 hashes/sec
163  - hashers::hsieh = 8.87383e+06 hashes/sec
164  - hashers::mpl::hsieh = 9.901563e+06 hashes/sec
165  - boost::hash = 5.547246e+06 hashes/sec
166  - std::hash = 9.806128e+06 hashes/sec
167 */
168 BOOST_AUTO_TEST_CASE(time_hashes) {
169 #ifdef JMMCG_PERFORMANCE_TESTS
170  const std::size_t num_hashes=1000000;
171 #else
172  const std::size_t num_hashes=100;
173 #endif
174  do_hashing<abseil_t>(stats_to_csv::handle->stats, num_hashes);
175  do_hashing<robin_hood_t>(stats_to_csv::handle->stats, num_hashes);
176  do_hashing<murmur2_t>(stats_to_csv::handle->stats, num_hashes);
177  do_hashing<hsieh_t>(stats_to_csv::handle->stats, num_hashes);
178  do_hashing<hsieh_mpl_t>(stats_to_csv::handle->stats, num_hashes);
179  do_hashing<boost::hash<std::string>>(stats_to_csv::handle->stats, num_hashes);
180  do_hashing<std::hash<std::string>>(stats_to_csv::handle->stats, num_hashes);
181 }
182 
183 BOOST_AUTO_TEST_SUITE_END()
184 
185 BOOST_AUTO_TEST_SUITE_END()