userver: /data/code/userver/libraries/multi-index-lru/src/main_benchmark.cpp Source File
Loading...
Searching...
No Matches
main_benchmark.cpp
1#include <userver/multi-index-lru/container.hpp>
2#include <userver/utils/rand.hpp>
3
4#include <random>
5#include <string>
6#include <vector>
7
8#include <benchmark/benchmark.h>
9#include <boost/multi_index/member.hpp>
10
11USERVER_NAMESPACE_BEGIN
12
13namespace benchmarks {
14
15const std::size_t kOperationsNumber = 100000;
16const int kMaxIdSize = 50000;
17
18struct IdTag {};
19struct EmailTag {};
20struct NameTag {};
21
22struct User {
23 int id;
24 std::string email;
25 std::string name;
26
27 bool operator==(const User& other) const { return id == other.id && email == other.email && name == other.name; }
28};
29
30namespace {
31User GenerateUser() {
32 std::string email = "email" + std::to_string(utils::RandRange<int>(0, kMaxIdSize));
33 std::string name = "name" + std::to_string(utils::RandRange<int>(0, kMaxIdSize));
34 return User{utils::RandRange<int>(0, kMaxIdSize), email, name};
35}
36
37int GenerateId() { return utils::RandRange<int>(0, kMaxIdSize); }
38
39std::string GenerateName() { return "name" + std::to_string(utils::RandRange<int>(0, kMaxIdSize)); }
40
41std::string GenerateEmail() { return "email" + std::to_string(utils::RandRange<int>(0, kMaxIdSize)); }
42} // namespace
43
44using UserCache = multi_index_lru::Container<
45 User,
46 boost::multi_index::indexed_by<
47 boost::multi_index::ordered_unique<
48 boost::multi_index::tag<IdTag>,
49 boost::multi_index::member<User, int, &User::id>>,
50 boost::multi_index::ordered_unique<
51 boost::multi_index::tag<EmailTag>,
52 boost::multi_index::member<User, std::string, &User::email>>,
53 boost::multi_index::ordered_non_unique<
54 boost::multi_index::tag<NameTag>,
55 boost::multi_index::member<User, std::string, &User::name>>>>;
56
57void LruFindEmplaceMix(benchmark::State& state) {
58 const std::size_t size = state.range(0);
59
60 UserCache cache(size);
61 for (std::size_t i = 0; i < size; ++i) {
62 cache.emplace(GenerateUser());
63 }
64
65 std::size_t reading_kOperationsNumber = kOperationsNumber * 4 / 5;
66 std::size_t writing_kOperationsNumber = kOperationsNumber / 5;
67
68 std::vector<std::string> names, emails;
69 std::vector<int> ids;
70 std::vector<User> users;
71
72 for (std::size_t i = 0; i < reading_kOperationsNumber; ++i) {
73 names.push_back(GenerateName());
74 emails.push_back(GenerateEmail());
75 ids.push_back(GenerateId());
76 }
77
78 for (std::size_t i = 0; i < writing_kOperationsNumber; ++i) {
79 users.push_back(GenerateUser());
80 }
81
82 for ([[maybe_unused]] auto _ : state) {
83 for (std::size_t i = 0; i < reading_kOperationsNumber; ++i) {
84 cache.find<NameTag, std::string>(names[i]);
85 cache.find<EmailTag, std::string>(emails[i]);
86 cache.find<IdTag, int>(ids[i]);
87 }
88
89 for (std::size_t i = 0; i < writing_kOperationsNumber; ++i) {
90 cache.emplace(users[i]);
91 }
92 }
93}
94
95BENCHMARK(LruFindEmplaceMix)->RangeMultiplier(10)->Range(100, 1000000);
96
97static void prepareCache(UserCache& cache, std::size_t size) {
98 for (std::size_t i = 0; i < size; ++i) {
99 cache.emplace(GenerateUser());
100 }
101}
102
103static void GetOperations(::benchmark::State& state) {
104 const std::size_t cache_size = state.range(0);
105 const std::size_t operations_count = kOperationsNumber;
106
107 UserCache cache(cache_size);
108 prepareCache(cache, cache_size);
109
110 for (auto _ : state) {
111 state.PauseTiming();
112 std::vector<std::string> names, emails;
113 std::vector<int> ids;
114 for (std::size_t i = 0; i < operations_count; ++i) {
115 names.push_back(GenerateName());
116 emails.push_back(GenerateEmail());
117 ids.push_back(GenerateId());
118 }
119 state.ResumeTiming();
120
121 for (std::size_t i = 0; i < operations_count; ++i) {
122 ::benchmark::DoNotOptimize(cache.find<NameTag, std::string>(names[i]));
123 ::benchmark::DoNotOptimize(cache.find<EmailTag, std::string>(emails[i]));
124 ::benchmark::DoNotOptimize(cache.find<IdTag, int>(ids[i]));
125 }
126 }
127
128 state.SetItemsProcessed(state.iterations() * operations_count * 3);
129 state.SetComplexityN(cache_size);
130}
131
132BENCHMARK(GetOperations)->RangeMultiplier(10)->Range(100, 1000000);
133
134static void EmplaceOperations(::benchmark::State& state) {
135 const std::size_t cache_size = state.range(0);
136 const std::size_t operations_count = kOperationsNumber;
137
138 UserCache cache(cache_size);
139 prepareCache(cache, cache_size);
140
141 for (auto _ : state) {
142 state.PauseTiming();
143 std::vector<User> users;
144 for (std::size_t i = 0; i < operations_count; ++i) {
145 users.push_back(GenerateUser());
146 }
147 state.ResumeTiming();
148
149 for (std::size_t i = 0; i < operations_count; ++i) {
150 cache.emplace(users[i]);
151 }
152 }
153
154 state.SetItemsProcessed(state.iterations() * operations_count);
155 state.SetComplexityN(cache_size);
156}
157
158BENCHMARK(EmplaceOperations)->RangeMultiplier(10)->Range(100, 1000000);
159
160} // namespace benchmarks
161
162USERVER_NAMESPACE_END