mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-30 03:17:15 +02:00
Add memory measurements to string.cpp
This commit is contained in:
@ -15,9 +15,11 @@
|
|||||||
# include "absl/container/flat_hash_map.h"
|
# include "absl/container/flat_hash_map.h"
|
||||||
#endif
|
#endif
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
@ -171,18 +173,78 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector< std::pair<std::string, long long> > times;
|
// counting allocator
|
||||||
|
|
||||||
|
static std::size_t s_alloc_bytes = 0;
|
||||||
|
static std::size_t s_alloc_count = 0;
|
||||||
|
|
||||||
|
template<class T> struct allocator
|
||||||
|
{
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
allocator() = default;
|
||||||
|
|
||||||
|
template<class U> allocator( allocator<U> const & ) noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
T* allocate( std::size_t n ) const
|
||||||
|
{
|
||||||
|
s_alloc_bytes += n;
|
||||||
|
s_alloc_count++;
|
||||||
|
|
||||||
|
return std::allocator<T>().allocate( n );
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate( T* p, std::size_t n ) const noexcept
|
||||||
|
{
|
||||||
|
s_alloc_bytes -= n;
|
||||||
|
s_alloc_count--;
|
||||||
|
|
||||||
|
std::allocator<T>().deallocate( p, n );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
struct record
|
||||||
|
{
|
||||||
|
std::string label_;
|
||||||
|
long long time_;
|
||||||
|
std::size_t bytes_;
|
||||||
|
std::size_t count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<record> times;
|
||||||
|
|
||||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||||
{
|
{
|
||||||
std::cout << label << ":\n\n";
|
std::cout << label << ":\n\n";
|
||||||
|
|
||||||
|
s_alloc_bytes = 0;
|
||||||
|
s_alloc_count = 0;
|
||||||
|
|
||||||
Map<std::string, std::uint32_t> map;
|
Map<std::string, std::uint32_t> map;
|
||||||
|
|
||||||
auto t0 = std::chrono::steady_clock::now();
|
auto t0 = std::chrono::steady_clock::now();
|
||||||
auto t1 = t0;
|
auto t1 = t0;
|
||||||
|
|
||||||
test_insert( map, t1 );
|
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_lookup( map, t1 );
|
||||||
test_iteration( map, t1 );
|
test_iteration( map, t1 );
|
||||||
test_lookup( map, t1 );
|
test_lookup( map, t1 );
|
||||||
@ -191,7 +253,8 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
|||||||
auto tN = std::chrono::steady_clock::now();
|
auto tN = std::chrono::steady_clock::now();
|
||||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
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
|
// multi_index emulation of unordered_map
|
||||||
@ -208,9 +271,30 @@ template<class K, class V> using multi_index_map = multi_index_container<
|
|||||||
pair<K, V>,
|
pair<K, V>,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||||
>
|
>,
|
||||||
|
::allocator< pair<K, V> >
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
// aliases using the counting allocator
|
||||||
|
|
||||||
|
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||||
|
|
||||||
|
template<class K, class V> using std_unordered_map =
|
||||||
|
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
|
template<class K, class V> using boost_unordered_map =
|
||||||
|
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
|
template<class K, class V> using absl_node_hash_map =
|
||||||
|
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
|
template<class K, class V> using absl_flat_hash_map =
|
||||||
|
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// fnv1a_hash
|
// fnv1a_hash
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
template<int Bits> struct fnv1a_hash_impl;
|
||||||
@ -256,36 +340,38 @@ template<> struct fnv1a_hash_impl<64>
|
|||||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
|
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map_fnv1a =
|
template<class K, class V> using std_unordered_map_fnv1a =
|
||||||
std::unordered_map<K, V, fnv1a_hash>;
|
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||||
boost::unordered_map<K, V, fnv1a_hash>;
|
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||||
pair<K, V>,
|
pair<K, V>,
|
||||||
indexed_by<
|
indexed_by<
|
||||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
||||||
>
|
>,
|
||||||
|
::allocator< pair<K, V> >
|
||||||
>;
|
>;
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||||
absl::node_hash_map<K, V, fnv1a_hash>;
|
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||||
absl::flat_hash_map<K, V, fnv1a_hash>;
|
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
init_indices();
|
init_indices();
|
||||||
|
|
||||||
test<std::unordered_map>( "std::unordered_map" );
|
test<std_unordered_map>( "std::unordered_map" );
|
||||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||||
test<boost::unordered_map>( "boost::unordered_map" );
|
test<boost_unordered_map>( "boost::unordered_map" );
|
||||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||||
test<multi_index_map>( "multi_index_map" );
|
test<multi_index_map>( "multi_index_map" );
|
||||||
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||||
@ -294,10 +380,10 @@ int main()
|
|||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
test<absl::node_hash_map>( "absl::node_hash_map" );
|
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||||
|
|
||||||
test<absl::flat_hash_map>( "absl::flat_hash_map" );
|
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -306,7 +392,7 @@ int main()
|
|||||||
|
|
||||||
for( auto const& x: times )
|
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";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user