Created
May 15, 2025 12:51
-
-
Save eao197/8c562f62877142d27f46a2a5c51ec240 to your computer and use it in GitHub Desktop.
Замеры производительности emplace/try_emplace для std::unordered_map
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <chrono> | |
#include <iostream> | |
#include <string> | |
#include <unordered_map> | |
#include <utility> | |
namespace test | |
{ | |
using key_t = std::pair<std::size_t, std::string>; | |
using values_map_t = std::unordered_map< key_t, int >; | |
} /* namespace test */ | |
template<> | |
struct std::hash<test::key_t> | |
{ | |
std::size_t | |
operator()(const test::key_t & k) const noexcept | |
{ | |
return std::hash<std::size_t>{}(k.first) + 0x9e3779b9 + | |
std::hash<std::string>{}(k.second); | |
} | |
}; | |
namespace test | |
{ | |
const std::array<std::string, 10> strings{ | |
"a rather long string value to avoid small string optimization 001", | |
"a rather long string value to avoid small string optimization 002", | |
"a rather long string value to avoid small string optimization 003", | |
"a rather long string value to avoid small string optimization 004", | |
"a rather long string value to avoid small string optimization 005", | |
"a rather long string value to avoid small string optimization 006", | |
"a rather long string value to avoid small string optimization 007", | |
"a rather long string value to avoid small string optimization 008", | |
"a rather long string value to avoid small string optimization 009", | |
"a rather long string value to avoid small string optimization 010" | |
}; | |
const std::size_t map_size = 100; | |
const std::size_t insertions = 10'000'000; | |
[[nodiscard]] | |
values_map_t | |
make_values() | |
{ | |
values_map_t result; | |
int value = 0; | |
for(std::size_t i = 0; i != map_size; ++i, ++value) | |
{ | |
const std::string & sk = strings[i % std::size(strings)]; | |
result.emplace(key_t{ i, sk }, value); | |
} | |
return result; | |
} | |
[[nodiscard]] | |
std::pair<std::size_t, const std::string &> | |
keys_from_i(std::size_t i) | |
{ | |
return { i % map_size, strings[i % std::size(strings)] }; | |
} | |
void | |
simple_emplace( | |
values_map_t & to) | |
{ | |
int value = 0; | |
for(std::size_t i = 0; i != insertions; ++i, ++value) | |
{ | |
const auto keys = keys_from_i(i); | |
to.emplace(key_t{ keys.first, keys.second }, value); | |
} | |
} | |
void | |
try_emplace( | |
values_map_t & to) | |
{ | |
int value = 0; | |
for(std::size_t i = 0; i != insertions; ++i, ++value) | |
{ | |
const auto keys = keys_from_i(i); | |
to.try_emplace(key_t{ keys.first, keys.second }, value); | |
} | |
} | |
void | |
emplace_via_piecewise_construct( | |
values_map_t & to) | |
{ | |
int value = 0; | |
for(std::size_t i = 0; i != insertions; ++i, ++value) | |
{ | |
const auto keys = keys_from_i(i); | |
to.emplace( | |
std::piecewise_construct, | |
std::forward_as_tuple(keys.first, keys.second), | |
std::forward_as_tuple(value) ); | |
} | |
} | |
} /* namespace test */ | |
class duration_meter | |
{ | |
const char * _name; | |
const std::chrono::high_resolution_clock::time_point _started_at; | |
public: | |
duration_meter( const char * name ) | |
: _name{ name } | |
, _started_at{ std::chrono::high_resolution_clock::now() } | |
{} | |
~duration_meter() | |
{ | |
const auto f = std::chrono::high_resolution_clock::now(); | |
std::cout << "*** " << _name << ": " | |
<< std::chrono::duration_cast<std::chrono::microseconds>( | |
f - _started_at ).count() | |
<< "us *** " << std::endl; | |
} | |
}; | |
template<typename Lambda> | |
decltype(auto) | |
measure( const char * name, Lambda && lambda ) | |
{ | |
duration_meter meter{ name }; | |
return lambda(); | |
} | |
using namespace test; | |
int main() | |
{ | |
auto values = make_values(); | |
measure( "simple_emplace", [&values]() { | |
simple_emplace(values); | |
}); | |
std::cout << "values size: " << values.size() << std::endl;; | |
measure( "try_emplace", [&values]() { | |
try_emplace(values); | |
}); | |
std::cout << "values size: " << values.size() << std::endl;; | |
measure( "emplace_via_piecewise_construct", [&values]() { | |
emplace_via_piecewise_construct(values); | |
}); | |
std::cout << "values size: " << values.size() << std::endl;; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment