diff --git a/benchmark/string.cpp b/benchmark/string.cpp index d2930455..0e438519 100644 --- a/benchmark/string.cpp +++ b/benchmark/string.cpp @@ -15,9 +15,11 @@ # include "absl/container/flat_hash_map.h" #endif #include -#include +#include +#include #include #include +#include #include using namespace std::chrono_literals; @@ -171,18 +173,78 @@ template BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead std::cout << std::endl; } -static std::vector< std::pair > times; +// counting allocator + +static std::size_t s_alloc_bytes = 0; +static std::size_t s_alloc_count = 0; + +template struct allocator +{ + using value_type = T; + + allocator() = default; + + template allocator( allocator const & ) noexcept + { + } + + template bool operator==( allocator const & ) const noexcept + { + return true; + } + + template bool operator!=( allocator const& ) const noexcept + { + return false; + } + + T* allocate( std::size_t n ) const + { + s_alloc_bytes += n; + s_alloc_count++; + + return std::allocator().allocate( n ); + } + + void deallocate( T* p, std::size_t n ) const noexcept + { + s_alloc_bytes -= n; + s_alloc_count--; + + std::allocator().deallocate( p, n ); + } +}; + +// + +struct record +{ + std::string label_; + long long time_; + std::size_t bytes_; + std::size_t count_; +}; + +static std::vector times; template class Map> BOOST_NOINLINE void test( char const* label ) { std::cout << label << ":\n\n"; + s_alloc_bytes = 0; + s_alloc_count = 0; + Map map; auto t0 = std::chrono::steady_clock::now(); auto t1 = t0; test_insert( map, t1 ); + + std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n"; + + record rec = { label, 0, s_alloc_bytes, s_alloc_count }; + test_lookup( map, t1 ); test_iteration( map, t1 ); test_lookup( map, t1 ); @@ -191,7 +253,8 @@ template class Map> BOOST_NOINLINE void test( char const* lab auto tN = std::chrono::steady_clock::now(); std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n"; - times.push_back( { label, ( tN - t0 ) / 1ms } ); + rec.time_ = ( tN - t0 ) / 1ms; + times.push_back( rec ); } // multi_index emulation of unordered_map @@ -208,9 +271,30 @@ template using multi_index_map = multi_index_container< pair, indexed_by< hashed_unique< member, K, &pair::first> > - > + >, + ::allocator< pair > >; +// aliases using the counting allocator + +template using allocator_for = ::allocator< std::pair >; + +template using std_unordered_map = + std::unordered_map, std::equal_to, allocator_for>; + +template using boost_unordered_map = + boost::unordered_map, std::equal_to, allocator_for>; + +#ifdef HAVE_ABSEIL + +template using absl_node_hash_map = + absl::node_hash_map, absl::container_internal::hash_default_eq, allocator_for>; + +template using absl_flat_hash_map = + absl::flat_hash_map, absl::container_internal::hash_default_eq, allocator_for>; + +#endif + // fnv1a_hash template struct fnv1a_hash_impl; @@ -256,36 +340,38 @@ template<> struct fnv1a_hash_impl<64> struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits::digits > {}; template using std_unordered_map_fnv1a = - std::unordered_map; +std::unordered_map, allocator_for>; template using boost_unordered_map_fnv1a = - boost::unordered_map; + boost::unordered_map, allocator_for>; template using multi_index_map_fnv1a = multi_index_container< pair, indexed_by< hashed_unique< member, K, &pair::first>, fnv1a_hash > - > + >, + ::allocator< pair > >; #ifdef HAVE_ABSEIL template using absl_node_hash_map_fnv1a = - absl::node_hash_map; + absl::node_hash_map, allocator_for>; template using absl_flat_hash_map_fnv1a = - absl::flat_hash_map; + absl::flat_hash_map, allocator_for>; #endif + // int main() { init_indices(); - test( "std::unordered_map" ); + test( "std::unordered_map" ); test( "std::unordered_map, FNV-1a" ); - test( "boost::unordered_map" ); + test( "boost::unordered_map" ); test( "boost::unordered_map, FNV-1a" ); test( "multi_index_map" ); test( "multi_index_map, FNV-1a" ); @@ -294,10 +380,10 @@ int main() #ifdef HAVE_ABSEIL - test( "absl::node_hash_map" ); + test( "absl::node_hash_map" ); test( "absl::node_hash_map, FNV-1a" ); - test( "absl::flat_hash_map" ); + test( "absl::flat_hash_map" ); test( "absl::flat_hash_map, FNV-1a" ); #endif @@ -306,7 +392,7 @@ int main() for( auto const& x: times ) { - std::cout << x.first << ": " << x.second << " ms\n"; + std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 8 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n"; } }