aboutsummaryrefslogtreecommitdiffhomepage
path: root/tdutils/test/hashset_memory.cpp
blob: eb8fd55bfa0ab704fe24c0a276e8567e2a076842 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//
// 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)
//

#include "memprof/memprof.h"
#include "td/utils/check.h"
#include "td/utils/Slice.h"
#include "td/utils/FlatHashMap.h"
#include "td/utils/format.h"
#include "td/utils/UInt.h"

#include <folly/container/F14Map.h>
#include <absl/container/flat_hash_map.h>
#include <map>
#include <unordered_map>

template <class T>
class Generator {
 public:
   T next() {
     UNREACHABLE();
   }
};

template <class T>
class IntGenerator {
 public:
  T next() {
    return ++value;
  }
 private:
  T value{};
};

template <>
class Generator<uint32_t> : public IntGenerator<uint32_t> {
 public:
};
template <>
class Generator<uint64_t> : public IntGenerator<uint64_t> {
 public:
};

template <class T, class KeyT, class ValueT>
void measure(td::StringBuilder &sb, td::Slice name, td::Slice key_name, td::Slice value_name) {
  sb << name << "<" << key_name << "," << value_name << ">:\n";
  size_t ideal_size = sizeof(KeyT) + sizeof(ValueT);

  sb << "\tempty:" << sizeof(T);
  struct Stat {
    int pi;
    double min_ratio;
    double max_ratio;
  };
  std::vector<Stat> stat;
  stat.reserve(1024);
  for (size_t size : {10000000u}) {
    Generator<KeyT> key_generator;
    auto start_mem = get_used_memory_size();
    T ht;
    auto ratio = [&]() {
      auto end_mem = get_used_memory_size();
      auto used_mem = end_mem - start_mem;
      return double(used_mem) / double(ideal_size * ht.size());
    };
    double min_ratio;
    double max_ratio;
    auto reset = [&]() {
      min_ratio = 1e100;
      max_ratio = 0;
    };
    auto update = [&]() {
      auto x = ratio();
      min_ratio = std::min(min_ratio, x);
      max_ratio = std::max(max_ratio, x);
      if (x > 14) {
        LOG(ERROR) << "WTF";
      }
    };
    reset();

    int p = 10;
    int pi = 1;
    for (size_t i = 0; i < size; i++) {
      ht.emplace(key_generator.next(), ValueT{});
      update();
      if ((i + 1) % p == 0) {
        stat.emplace_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 <template<typename... Args> class T>
void print_memory_stats(td::Slice name) {
  std::string big_buff(1<<16, '\0');
  td::StringBuilder sb(big_buff, false);
#define MEASURE(KeyT, ValueT) \
  measure<T<KeyT, ValueT>, KeyT, ValueT>(sb, name, #KeyT, #ValueT);
  MEASURE(uint32_t, uint32_t)
  // MEASURE(uint64_t, td::UInt256)
  LOG(ERROR) << "\n" << sb.as_cslice();
}

#define FOR_EACH_TABLE(F) \
  F(td::FlatHashMapImpl)  \
  F(folly::F14FastMap)    \
  F(absl::flat_hash_map)  \
  F(std::unordered_map)   \
  F(std::map)
#define BENCH_MEMORY(T) print_memory_stats<T>(#T);

int main() {
  CHECK(get_used_memory_size());
  FOR_EACH_TABLE(BENCH_MEMORY);
  return 0;
}