Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
test_hot_path_helper.cpp File Reference

Unit tests for hot-path optimization helpers. More...

#include <gtest/gtest.h>
#include <kcenon/monitoring/utils/hot_path_helper.h>
#include <atomic>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
Include dependency graph for test_hot_path_helper.cpp:

Go to the source code of this file.

Classes

class  HotPathHelperTest
 

Functions

 TEST_F (HotPathHelperTest, GetOrCreateNewEntry)
 
 TEST_F (HotPathHelperTest, GetOrCreateExistingEntry)
 
 TEST_F (HotPathHelperTest, GetOrCreateMultipleKeys)
 
 TEST_F (HotPathHelperTest, GetOrCreateWithInitNewEntry)
 
 TEST_F (HotPathHelperTest, GetOrCreateWithInitExistingEntry)
 
 TEST_F (HotPathHelperTest, GetOrCreateAndUpdateNewEntry)
 
 TEST_F (HotPathHelperTest, GetOrCreateAndUpdateExistingEntry)
 
 TEST_F (HotPathHelperTest, ConcurrentGetOrCreate)
 
 TEST_F (HotPathHelperTest, ConcurrentDifferentKeys)
 
 TEST_F (HotPathHelperTest, ConcurrentMixedReadWrite)
 
 TEST_F (HotPathHelperTest, HotPathOptimizationVerification)
 

Detailed Description

Unit tests for hot-path optimization helpers.

Definition in file test_hot_path_helper.cpp.

Function Documentation

◆ TEST_F() [1/11]

TEST_F ( HotPathHelperTest ,
ConcurrentDifferentKeys  )

Definition at line 197 of file test_hot_path_helper.cpp.

197 {
198 std::atomic<int> total_creates{0};
199 const int num_threads = 10;
200 const int keys_per_thread = 100;
201
202 std::vector<std::thread> threads;
203 threads.reserve(num_threads);
204
205 for (int t = 0; t < num_threads; ++t) {
206 threads.emplace_back([this, t, &total_creates, keys_per_thread]() {
207 for (int i = 0; i < keys_per_thread; ++i) {
208 std::string key = "key_" + std::to_string(t) + "_" + std::to_string(i);
209 auto* ptr = get_or_create(
210 map_, mutex_, key,
211 [&total_creates]() {
212 ++total_creates;
213 return std::make_unique<TestData>();
214 });
215 ASSERT_NE(ptr, nullptr);
216 }
217 });
218 }
219
220 for (auto& t : threads) {
221 t.join();
222 }
223
224 EXPECT_EQ(map_.size(), static_cast<size_t>(num_threads * keys_per_thread));
225 EXPECT_EQ(total_creates.load(), num_threads * keys_per_thread);
226}
auto get_or_create(Map &map, std::shared_mutex &mutex, const Key &key, CreateFn create_fn) -> typename std::remove_reference< decltype(*map.begin() ->second)>::type *

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [2/11]

TEST_F ( HotPathHelperTest ,
ConcurrentGetOrCreate  )

Definition at line 167 of file test_hot_path_helper.cpp.

167 {
168 std::atomic<int> create_count{0};
169 const int num_threads = 10;
170 const int iterations_per_thread = 1000;
171
172 std::vector<std::thread> threads;
173 threads.reserve(num_threads);
174
175 for (int t = 0; t < num_threads; ++t) {
176 threads.emplace_back([this, &create_count, iterations_per_thread]() {
177 for (int i = 0; i < iterations_per_thread; ++i) {
178 auto* ptr = get_or_create(
179 map_, mutex_, "shared_key",
180 [&create_count]() {
181 ++create_count;
182 return std::make_unique<TestData>();
183 });
184 ASSERT_NE(ptr, nullptr);
185 }
186 });
187 }
188
189 for (auto& t : threads) {
190 t.join();
191 }
192
193 EXPECT_EQ(map_.size(), 1u);
194 EXPECT_EQ(create_count.load(), 1); // Only one creation should occur
195}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [3/11]

TEST_F ( HotPathHelperTest ,
ConcurrentMixedReadWrite  )

Definition at line 228 of file test_hot_path_helper.cpp.

228 {
229 // Pre-create some entries
230 for (int i = 0; i < 50; ++i) {
231 map_["existing_" + std::to_string(i)] = std::make_unique<TestData>();
232 }
233
234 const int num_threads = 8;
235 const int iterations = 500;
236
237 std::vector<std::thread> threads;
238 threads.reserve(num_threads);
239
240 for (int t = 0; t < num_threads; ++t) {
241 threads.emplace_back([this, t, iterations]() {
242 for (int i = 0; i < iterations; ++i) {
243 // Half the time access existing, half the time create new
244 std::string key = (i % 2 == 0)
245 ? "existing_" + std::to_string(i % 50)
246 : "new_" + std::to_string(t) + "_" + std::to_string(i);
247
248 auto* ptr = get_or_create(
249 map_, mutex_, key,
250 []() { return std::make_unique<TestData>(); });
251 ASSERT_NE(ptr, nullptr);
252 }
253 });
254 }
255
256 for (auto& t : threads) {
257 t.join();
258 }
259
260 EXPECT_GE(map_.size(), 50u); // At least the pre-existing entries
261}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [4/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateAndUpdateExistingEntry  )

Definition at line 146 of file test_hot_path_helper.cpp.

146 {
147 // Pre-create an entry
148 map_["key1"] = std::make_unique<TestData>();
149 map_["key1"]->value = 10;
150
151 int result = get_or_create_and_update(
152 map_, mutex_, "key1",
153 []() { return std::make_unique<TestData>(); },
154 [](TestData& d) {
155 d.value += 5;
156 return d.value;
157 });
158
159 EXPECT_EQ(result, 15);
160 EXPECT_EQ(map_["key1"]->value, 15);
161}
auto get_or_create_and_update(Map &map, std::shared_mutex &mutex, const Key &key, CreateFn create_fn, UpdateFn update_fn) -> decltype(update_fn(*map.begin() ->second))

References kcenon::monitoring::hot_path::get_or_create_and_update().

Here is the call graph for this function:

◆ TEST_F() [5/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateAndUpdateNewEntry  )

Definition at line 133 of file test_hot_path_helper.cpp.

133 {
134 int result = get_or_create_and_update(
135 map_, mutex_, "key1",
136 []() { return std::make_unique<TestData>(); },
137 [](TestData& d) {
138 d.value = 42;
139 return d.value;
140 });
141
142 EXPECT_EQ(result, 42);
143 EXPECT_EQ(map_["key1"]->value, 42);
144}

References kcenon::monitoring::hot_path::get_or_create_and_update().

Here is the call graph for this function:

◆ TEST_F() [6/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateExistingEntry  )

Definition at line 57 of file test_hot_path_helper.cpp.

57 {
58 // Pre-create an entry
59 map_["key1"] = std::make_unique<TestData>();
60 map_["key1"]->value = 42;
61
62 int create_count = 0;
63 auto* ptr = get_or_create(
64 map_, mutex_, "key1",
65 [&create_count]() {
66 ++create_count;
67 return std::make_unique<TestData>();
68 });
69
70 ASSERT_NE(ptr, nullptr);
71 EXPECT_EQ(map_.size(), 1u);
72 EXPECT_EQ(ptr->value, 42);
73 EXPECT_EQ(create_count, 0); // Factory should not be called
74}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [7/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateMultipleKeys  )

Definition at line 76 of file test_hot_path_helper.cpp.

76 {
77 auto* ptr1 = get_or_create(
78 map_, mutex_, "key1",
79 []() { return std::make_unique<TestData>(); });
80 auto* ptr2 = get_or_create(
81 map_, mutex_, "key2",
82 []() { return std::make_unique<TestData>(); });
83
84 ASSERT_NE(ptr1, nullptr);
85 ASSERT_NE(ptr2, nullptr);
86 EXPECT_NE(ptr1, ptr2);
87 EXPECT_EQ(map_.size(), 2u);
88}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [8/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateNewEntry  )

Definition at line 47 of file test_hot_path_helper.cpp.

47 {
48 auto* ptr = get_or_create(
49 map_, mutex_, "key1",
50 []() { return std::make_unique<TestData>(); });
51
52 ASSERT_NE(ptr, nullptr);
53 EXPECT_EQ(map_.size(), 1u);
54 EXPECT_EQ(ptr->value, 0);
55}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function:

◆ TEST_F() [9/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateWithInitExistingEntry  )

Definition at line 108 of file test_hot_path_helper.cpp.

108 {
109 // Pre-create an entry
110 map_["key1"] = std::make_unique<TestData>();
111 map_["key1"]->value = 42;
112 map_["key1"]->name = "original";
113
114 int init_count = 0;
115 auto* ptr = get_or_create_with_init(
116 map_, mutex_, "key1",
117 []() { return std::make_unique<TestData>(); },
118 [&init_count](TestData& d) {
119 ++init_count;
120 d.value = 100;
121 });
122
123 ASSERT_NE(ptr, nullptr);
124 EXPECT_EQ(ptr->value, 42); // Should not be modified
125 EXPECT_EQ(ptr->name, "original");
126 EXPECT_EQ(init_count, 0); // Init should not be called
127}
auto get_or_create_with_init(Map &map, std::shared_mutex &mutex, const Key &key, CreateFn create_fn, InitFn init_fn) -> typename std::remove_reference< decltype(*map.begin() ->second)>::type *

References kcenon::monitoring::hot_path::get_or_create_with_init().

Here is the call graph for this function:

◆ TEST_F() [10/11]

TEST_F ( HotPathHelperTest ,
GetOrCreateWithInitNewEntry  )

Definition at line 94 of file test_hot_path_helper.cpp.

94 {
95 auto* ptr = get_or_create_with_init(
96 map_, mutex_, "key1",
97 []() { return std::make_unique<TestData>(); },
98 [](TestData& d) {
99 d.value = 100;
100 d.name = "initialized";
101 });
102
103 ASSERT_NE(ptr, nullptr);
104 EXPECT_EQ(ptr->value, 100);
105 EXPECT_EQ(ptr->name, "initialized");
106}

References kcenon::monitoring::hot_path::get_or_create_with_init().

Here is the call graph for this function:

◆ TEST_F() [11/11]

TEST_F ( HotPathHelperTest ,
HotPathOptimizationVerification  )

Definition at line 267 of file test_hot_path_helper.cpp.

267 {
268 // Create entry first
269 map_["hot_key"] = std::make_unique<TestData>();
270
271 std::atomic<int> create_calls{0};
272 const int hot_path_iterations = 10000;
273
274 // Simulate hot path - many reads, no creates
275 for (int i = 0; i < hot_path_iterations; ++i) {
276 auto* ptr = get_or_create(
277 map_, mutex_, "hot_key",
278 [&create_calls]() {
279 ++create_calls;
280 return std::make_unique<TestData>();
281 });
282 ASSERT_NE(ptr, nullptr);
283 }
284
285 // Verify factory was never called (hot path optimization working)
286 EXPECT_EQ(create_calls.load(), 0);
287}

References kcenon::monitoring::hot_path::get_or_create().

Here is the call graph for this function: