// // Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #if USE_MEMPROF #include "memprof/memprof_stat.h" #endif #include "td/utils/common.h" #include "td/utils/FlatHashMap.h" #include "td/utils/FlatHashMapChunks.h" #include "td/utils/FlatHashTable.h" #include "td/utils/HashTableUtils.h" #include "td/utils/logging.h" #include "td/utils/MapNode.h" #include "td/utils/misc.h" #include "td/utils/port/Stat.h" #include "td/utils/Slice.h" #include "td/utils/StringBuilder.h" #ifdef SCOPE_EXIT #undef SCOPE_EXIT #endif #include #include #include #include #include #include static int mem_stat_i = -1; static int mem_stat_cur = 0; static bool use_memprof() { #if USE_MEMPROF return mem_stat_i < 0 && is_memprof_on(); #else return mem_stat_i < 0; #endif } static td::uint64 get_memory() { #if USE_MEMPROF if (use_memprof()) { return get_used_memory_size(); } #endif CHECK(!use_memprof()); return td::mem_stat().ok().resident_size_; } template class Generator { public: T next() { UNREACHABLE(); } static size_t dyn_size() { UNREACHABLE(); } }; template class IntGenerator { public: T next() { return ++value; } static size_t dyn_size() { return 0; } private: T value{}; }; template <> class Generator final : public IntGenerator {}; template <> class Generator final : public IntGenerator {}; template class Generator> { public: td::unique_ptr next() { return td::make_unique(); } static std::size_t dyn_size() { return sizeof(T); } }; template static void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slice value_name) { mem_stat_cur++; if (mem_stat_i >= 0 && mem_stat_cur != mem_stat_i) { return; } sb << name << "<" << key_name << "," << value_name << "> " << (use_memprof() ? "memprof" : "os") << "\n"; std::size_t ideal_size = sizeof(KeyT) + sizeof(ValueT) + Generator::dyn_size(); sb << "\tempty:" << sizeof(T); struct Stat { int pi; double min_ratio; double max_ratio; }; td::vector stat; stat.reserve(1024); for (std::size_t size : {1000000u}) { Generator key_generator; Generator value_generator; auto start_mem = get_memory(); T ht; auto ratio = [&] { auto end_mem = get_memory(); auto used_mem = end_mem - start_mem; return static_cast(used_mem) / (static_cast(ideal_size) * static_cast(ht.size())); }; double min_ratio; double max_ratio; auto reset = [&] { min_ratio = 1e100; max_ratio = 0; }; auto update = [&] { auto x = ratio(); min_ratio = td::min(min_ratio, x); max_ratio = td::max(max_ratio, x); }; reset(); int p = 10; int pi = 1; for (std::size_t i = 0; i < size; i++) { ht.emplace(key_generator.next(), value_generator.next()); update(); if ((i + 1) % p == 0) { stat.push_back(Stat{pi, min_ratio, max_ratio}); reset(); pi++; p *= 10; } } } for (auto &s : stat) { sb << " 10^" << s.pi << ":" << s.min_ratio << "->" << s.max_ratio; } sb << '\n'; } template using Bytes = std::array; template