Various improvements.

This commit is contained in:
levlam 2022-02-10 23:01:28 +03:00
parent 3d8e5e00e4
commit b8ab910b81
11 changed files with 65 additions and 63 deletions

View File

@ -74,11 +74,10 @@ if (NOT WIN32 AND NOT CYGWIN)
endif() endif()
find_package(ABSL QUIET) find_package(ABSL QUIET)
find_package(benchmark QUIET)
find_package(gflags QUIET) find_package(gflags QUIET)
find_package(folly QUIET) find_package(folly QUIET)
if (ABSL_FOUND AND benchmark_FOUND AND gflags_FOUND AND folly_FOUND) if (ABSL_FOUND AND gflags_FOUND AND folly_FOUND)
add_executable(memory-hashset-memprof EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/hashset_memory.cpp) add_executable(memory-hashset-memprof EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/hashset_memory.cpp)
target_compile_definitions(memory-hashset-memprof PRIVATE USE_MEMPROF=1) target_compile_definitions(memory-hashset-memprof PRIVATE USE_MEMPROF=1)
target_link_libraries(memory-hashset-memprof PRIVATE tdutils memprof_stat) target_link_libraries(memory-hashset-memprof PRIVATE tdutils memprof_stat)

View File

@ -5,5 +5,4 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
int main() { int main() {
return 0;
} }

View File

@ -114,5 +114,4 @@ int main() {
// empty // empty
} }
scheduler->finish(); scheduler->finish();
return 0;
} }

View File

@ -4,42 +4,44 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#if USE_MEMPROF #if USE_MEMPROF
#include "memprof/memprof_stat.h" #include "memprof/memprof_stat.h"
#endif #endif
#include "td/utils/check.h" #include "td/utils/common.h"
#include "td/utils/FlatHashMap.h" #include "td/utils/FlatHashMap.h"
#include "td/utils/format.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/port/Stat.h" #include "td/utils/port/Stat.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h"
#include <absl/container/flat_hash_map.h> #include <absl/container/flat_hash_map.h>
#include <array>
#include <folly/container/F14Map.h> #include <folly/container/F14Map.h>
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
int mem_stat_i = -1; static int mem_stat_i = -1;
int mem_stat_cur = 0; static int mem_stat_cur = 0;
bool use_memprof() {
return mem_stat_i < 0 static bool use_memprof() {
#if USE_MEMPROF #if USE_MEMPROF
&& is_memprof_on() return mem_stat_i < 0 && is_memprof_on();
#else
return mem_stat_i < 0;
#endif #endif
;
} }
auto get_memory() {
static auto get_memory() {
#if USE_MEMPROF #if USE_MEMPROF
if (use_memprof()) { if (use_memprof()) {
return get_used_memory_size(); return get_used_memory_size();
} }
#else #endif
CHECK(!use_memprof()); CHECK(!use_memprof());
return td::mem_stat().ok().resident_size_; return td::mem_stat().ok().resident_size_;
#endif }
};
template <class T> template <class T>
class Generator { class Generator {
@ -67,13 +69,9 @@ class IntGenerator {
}; };
template <> template <>
class Generator<uint32_t> : public IntGenerator<uint32_t> { class Generator<td::uint32> final : public IntGenerator<td::uint32> {};
public:
};
template <> template <>
class Generator<uint64_t> : public IntGenerator<uint64_t> { class Generator<td::uint64> final : public IntGenerator<td::uint64> {};
public:
};
template <class T> template <class T>
class Generator<td::unique_ptr<T>> { class Generator<td::unique_ptr<T>> {
@ -81,19 +79,19 @@ class Generator<td::unique_ptr<T>> {
td::unique_ptr<T> next() { td::unique_ptr<T> next() {
return td::make_unique<T>(); return td::make_unique<T>();
} }
static size_t dyn_size() { static std::size_t dyn_size() {
return sizeof(T); return sizeof(T);
} }
}; };
template <class T, class KeyT, class ValueT> template <class T, class KeyT, class ValueT>
void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slice value_name) { static void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slice value_name) {
mem_stat_cur++; mem_stat_cur++;
if (mem_stat_i >= 0 && mem_stat_cur != mem_stat_i) { if (mem_stat_i >= 0 && mem_stat_cur != mem_stat_i) {
return; return;
} }
sb << name << "<" << key_name << "," << value_name << "> " << (use_memprof() ? "memprof" : "os") << "\n"; sb << name << "<" << key_name << "," << value_name << "> " << (use_memprof() ? "memprof" : "os") << "\n";
size_t ideal_size = sizeof(KeyT) + sizeof(ValueT) + Generator<ValueT>::dyn_size(); std::size_t ideal_size = sizeof(KeyT) + sizeof(ValueT) + Generator<ValueT>::dyn_size();
sb << "\tempty:" << sizeof(T); sb << "\tempty:" << sizeof(T);
struct Stat { struct Stat {
@ -101,34 +99,34 @@ void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slic
double min_ratio; double min_ratio;
double max_ratio; double max_ratio;
}; };
std::vector<Stat> stat; td::vector<Stat> stat;
stat.reserve(1024); stat.reserve(1024);
for (size_t size : {10000000u}) { for (std::size_t size : {1000000u}) {
Generator<KeyT> key_generator; Generator<KeyT> key_generator;
Generator<ValueT> value_generator; Generator<ValueT> value_generator;
auto start_mem = get_memory(); auto start_mem = get_memory();
T ht; T ht;
auto ratio = [&]() { auto ratio = [&] {
auto end_mem = get_memory(); auto end_mem = get_memory();
auto used_mem = end_mem - start_mem; auto used_mem = end_mem - start_mem;
return double(used_mem) / double(ideal_size * ht.size()); return static_cast<double>(used_mem) / (static_cast<double>(ideal_size) * static_cast<double>(ht.size()));
}; };
double min_ratio; double min_ratio;
double max_ratio; double max_ratio;
auto reset = [&]() { auto reset = [&] {
min_ratio = 1e100; min_ratio = 1e100;
max_ratio = 0; max_ratio = 0;
}; };
auto update = [&]() { auto update = [&] {
auto x = ratio(); auto x = ratio();
min_ratio = std::min(min_ratio, x); min_ratio = td::min(min_ratio, x);
max_ratio = std::max(max_ratio, x); max_ratio = td::max(max_ratio, x);
}; };
reset(); reset();
int p = 10; int p = 10;
int pi = 1; int pi = 1;
for (size_t i = 0; i < size; i++) { for (std::size_t i = 0; i < size; i++) {
ht.emplace(key_generator.next(), value_generator.next()); ht.emplace(key_generator.next(), value_generator.next());
update(); update();
if ((i + 1) % p == 0) { if ((i + 1) % p == 0) {
@ -140,23 +138,23 @@ void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slic
} }
} }
for (auto &s : stat) { for (auto &s : stat) {
sb << " " << 10 << "^" << s.pi << ":" << s.min_ratio << "->" << s.max_ratio; sb << " 10^" << s.pi << ":" << s.min_ratio << "->" << s.max_ratio;
} }
sb << "\n"; sb << '\n';
} }
template <size_t size> template <std::size_t size>
using Bytes = std::array<uint8_t, size>; using Bytes = std::array<char, size>;
template <template <typename... Args> class T> template <template <typename... Args> class T>
void print_memory_stats(td::Slice name) { void print_memory_stats(td::Slice name) {
std::string big_buff(1 << 16, '\0'); td::string big_buff(1 << 16, '\0');
td::StringBuilder sb(big_buff, false); td::StringBuilder sb(big_buff, false);
#define MEASURE(KeyT, ValueT) measure<T<KeyT, ValueT>, KeyT, ValueT>(sb, name, #KeyT, #ValueT); #define MEASURE(KeyT, ValueT) measure<T<KeyT, ValueT>, KeyT, ValueT>(sb, name, #KeyT, #ValueT);
MEASURE(uint32_t, uint32_t); MEASURE(td::uint32, td::uint32);
MEASURE(uint64_t, td::unique_ptr<Bytes<360>>); MEASURE(td::uint64, td::unique_ptr<Bytes<360>>);
if (!sb.as_cslice().empty()) { if (!sb.as_cslice().empty()) {
LOG(PLAIN) << "\n" << sb.as_cslice() << "\n"; LOG(PLAIN) << '\n' << sb.as_cslice() << '\n';
} }
} }
@ -166,19 +164,18 @@ void print_memory_stats(td::Slice name) {
F(absl::flat_hash_map) \ F(absl::flat_hash_map) \
F(std::unordered_map) \ F(std::unordered_map) \
F(std::map) F(std::map)
#define BENCH_MEMORY(T) print_memory_stats<T>(#T); #define BENCHMARK_MEMORY(T) print_memory_stats<T>(#T);
int main(int argc, const char *argv[]) { int main(int argc, const char *argv[]) {
// Usage: // Usage:
// % benchmark/memory-hashset-os 0 // % benchmark/memory-hashset-os 0
// max_i = 10 // Number of benchmarks = 10
// % for i in {1..10}; do ./benchmark/memory-hashset-os $i; done // % for i in {1..10}; do ./benchmark/memory-hashset-os $i; done
if (argc > 1) { if (argc > 1) {
mem_stat_i = td::to_integer<td::int32>(td::Slice(argv[1])); mem_stat_i = td::to_integer<td::int32>(td::Slice(argv[1]));
} }
FOR_EACH_TABLE(BENCH_MEMORY); FOR_EACH_TABLE(BENCHMARK_MEMORY);
if (mem_stat_i <= 0) { if (mem_stat_i <= 0) {
LOG(PLAIN) << "max_i = " << mem_stat_cur << "\n"; LOG(PLAIN) << "Number of benchmarks = " << mem_stat_cur << "\n";
} }
return 0; }
}

View File

@ -265,12 +265,14 @@ void free(void *data_void) {
#endif #endif
return free_old(info); return free_old(info);
} }
void *calloc(std::size_t size_a, std::size_t size_b) { void *calloc(std::size_t size_a, std::size_t size_b) {
auto size = size_a * size_b; auto size = size_a * size_b;
void *res = malloc_with_frame(size, get_backtrace()); void *res = malloc_with_frame(size, get_backtrace());
std::memset(res, 0, size); std::memset(res, 0, size);
return res; return res;
} }
void *realloc(void *ptr, std::size_t size) { void *realloc(void *ptr, std::size_t size) {
if (ptr == nullptr) { if (ptr == nullptr) {
return malloc_with_frame(size, get_backtrace()); return malloc_with_frame(size, get_backtrace());
@ -282,6 +284,7 @@ void *realloc(void *ptr, std::size_t size) {
free(ptr); free(ptr);
return new_ptr; return new_ptr;
} }
void *memalign(std::size_t aligment, std::size_t size) { void *memalign(std::size_t aligment, std::size_t size) {
my_assert(false && "Memalign is unsupported"); my_assert(false && "Memalign is unsupported");
return nullptr; return nullptr;

View File

@ -4,7 +4,7 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "memprof_stat.h" #include "memprof/memprof_stat.h"
#include "td/utils/port/platform.h" #include "td/utils/port/platform.h"
@ -15,7 +15,6 @@
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <functional>
#include <new> #include <new>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -37,7 +36,8 @@ struct malloc_info {
std::int32_t size; std::int32_t size;
}; };
std::atomic<uint64_t> total_memory_used; static std::atomic<std::size_t> total_memory_used;
void register_xalloc(malloc_info *info, std::int32_t diff) { void register_xalloc(malloc_info *info, std::int32_t diff) {
my_assert(info->size >= 0); my_assert(info->size >= 0);
// TODO: this is very slow in case of several threads. // TODO: this is very slow in case of several threads.
@ -106,12 +106,14 @@ void free(void *data_void) {
#endif #endif
return free_old(info); return free_old(info);
} }
void *calloc(std::size_t size_a, std::size_t size_b) { void *calloc(std::size_t size_a, std::size_t size_b) {
auto size = size_a * size_b; auto size = size_a * size_b;
void *res = do_malloc(size); void *res = do_malloc(size);
std::memset(res, 0, size); std::memset(res, 0, size);
return res; return res;
} }
void *realloc(void *ptr, std::size_t size) { void *realloc(void *ptr, std::size_t size) {
if (ptr == nullptr) { if (ptr == nullptr) {
return do_malloc(size); return do_malloc(size);
@ -123,15 +125,16 @@ void *realloc(void *ptr, std::size_t size) {
free(ptr); free(ptr);
return new_ptr; return new_ptr;
} }
void *memalign(std::size_t alignment, std::size_t size) { void *memalign(std::size_t alignment, std::size_t size) {
auto res = malloc(size); auto res = malloc(size);
my_assert(reinterpret_cast<uint64_t>(res) % alignment == 0); my_assert(reinterpret_cast<std::uintptr_t>(res) % alignment == 0);
return res; return res;
} }
int posix_memalign(void **memptr, size_t alignment, size_t size) { int posix_memalign(void **memptr, size_t alignment, size_t size) {
auto res = malloc(size); auto res = malloc(size);
my_assert(reinterpret_cast<uint64_t>(res) % alignment == 0); my_assert(reinterpret_cast<std::uintptr_t>(res) % alignment == 0);
*memptr = res; *memptr = res;
return 0; return 0;
} }
@ -158,6 +161,6 @@ bool is_memprof_on() {
return false; return false;
} }
std::size_t get_used_memory_size() { std::size_t get_used_memory_size() {
return false; return 0;
} }
#endif #endif

View File

@ -1,6 +1,13 @@
//
// 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)
//
#pragma once #pragma once
#include <cstddef> #include <cstddef>
bool is_memprof_on(); bool is_memprof_on();
std::size_t get_used_memory_size(); std::size_t get_used_memory_size();

View File

@ -36,5 +36,4 @@ EMSCRIPTEN_KEEPALIVE double td_emscripten_get_timeout() {
int main() { int main() {
emscripten_exit_with_live_runtime(); emscripten_exit_with_live_runtime();
return 0;
} }

View File

@ -47,5 +47,4 @@ int main() {
scheduler.run_main(td::Timestamp::in(10)); scheduler.run_main(td::Timestamp::in(10));
} }
scheduler.finish(); scheduler.finish();
return 0;
} }

View File

@ -8,7 +8,6 @@
#include "td/utils/bits.h" #include "td/utils/bits.h"
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/logging.h"
#include <cstddef> #include <cstddef>
#include <functional> #include <functional>
@ -419,12 +418,11 @@ class FlatHashMapImpl {
} }
} }
static bool should_shrink(size_t used_count, size_t bucket_count) { static bool should_shrink(size_t used_count, size_t bucket_count) {
return used_count * 5 < bucket_count; return used_count * 10 < bucket_count;
} }
static size_t normalize(size_t size) { static size_t normalize(size_t size) {
size |= (size != 0) * 7; return static_cast<size_t>(1) << (64 - count_leading_zeroes64(size | 7));
return static_cast<size_t>(1) << (64 - count_leading_zeroes64(size));
} }
void shrink() { void shrink() {
@ -433,7 +431,7 @@ class FlatHashMapImpl {
} }
void grow() { void grow() {
size_t want_size = normalize((used_nodes_ + 1) * 5 / 3 + 1); size_t want_size = normalize(2 * nodes_.size() - 1);
resize(want_size); resize(want_size);
} }

View File

@ -61,5 +61,4 @@ int main(int argc, char **argv) {
#else #else
runner.run_all(); runner.run_all();
#endif #endif
return 0;
} }