10#include <gtest/gtest.h>
35 std::this_thread::sleep_for(duration);
40 auto result = profiler.record_sample(
"test_operation",
41 std::chrono::nanoseconds(1000000),
44 ASSERT_TRUE(result.is_ok());
45 EXPECT_TRUE(result.value());
47 auto metrics_result = profiler.get_metrics(
"test_operation");
48 ASSERT_TRUE(metrics_result.is_ok());
50 auto metrics = metrics_result.value();
51 EXPECT_EQ(metrics.operation_name,
"test_operation");
52 EXPECT_EQ(metrics.call_count, 1);
53 EXPECT_EQ(metrics.error_count, 0);
54 EXPECT_EQ(metrics.mean_duration.count(), 1000000);
58 std::vector<std::chrono::nanoseconds> durations = {
59 std::chrono::nanoseconds(1000000),
60 std::chrono::nanoseconds(2000000),
61 std::chrono::nanoseconds(3000000),
62 std::chrono::nanoseconds(4000000),
63 std::chrono::nanoseconds(5000000)
66 for (
const auto& duration : durations) {
67 profiler.record_sample(
"multi_operation", duration,
true);
70 auto metrics_result = profiler.get_metrics(
"multi_operation");
71 ASSERT_TRUE(metrics_result.is_ok());
73 auto metrics = metrics_result.value();
74 EXPECT_EQ(metrics.call_count, 5);
75 EXPECT_EQ(metrics.error_count, 0);
76 EXPECT_EQ(metrics.min_duration.count(), 1000000);
77 EXPECT_EQ(metrics.max_duration.count(), 5000000);
78 EXPECT_EQ(metrics.median_duration.count(), 3000000);
79 EXPECT_EQ(metrics.mean_duration.count(), 3000000);
83 profiler.record_sample(
"error_operation", std::chrono::nanoseconds(1000000),
true);
84 profiler.record_sample(
"error_operation", std::chrono::nanoseconds(2000000),
false);
85 profiler.record_sample(
"error_operation", std::chrono::nanoseconds(3000000),
false);
86 profiler.record_sample(
"error_operation", std::chrono::nanoseconds(4000000),
true);
88 auto metrics_result = profiler.get_metrics(
"error_operation");
89 ASSERT_TRUE(metrics_result.is_ok());
91 auto metrics = metrics_result.value();
92 EXPECT_EQ(metrics.call_count, 4);
93 EXPECT_EQ(metrics.error_count, 2);
99 simulate_work(std::chrono::milliseconds(10));
102 auto metrics_result = profiler.get_metrics(
"scoped_operation");
103 ASSERT_TRUE(metrics_result.is_ok());
105 auto metrics = metrics_result.value();
106 EXPECT_EQ(metrics.call_count, 1);
107 EXPECT_GE(metrics.mean_duration.count(), 10000000);
113 simulate_work(std::chrono::milliseconds(5));
117 auto metrics_result = profiler.get_metrics(
"error_scoped_operation");
118 ASSERT_TRUE(metrics_result.is_ok());
120 auto metrics = metrics_result.value();
121 EXPECT_EQ(metrics.call_count, 1);
122 EXPECT_EQ(metrics.error_count, 1);
127 for (
int i = 1; i <= 100; ++i) {
128 profiler.record_sample(
"percentile_test",
129 std::chrono::nanoseconds(i * 1000000),
133 auto metrics_result = profiler.get_metrics(
"percentile_test");
134 ASSERT_TRUE(metrics_result.is_ok());
136 auto metrics = metrics_result.value();
137 EXPECT_EQ(metrics.call_count, 100);
140 EXPECT_GE(metrics.median_duration.count(), 49000000);
141 EXPECT_LE(metrics.median_duration.count(), 51000000);
144 EXPECT_GE(metrics.p95_duration.count(), 94000000);
145 EXPECT_LE(metrics.p95_duration.count(), 96000000);
148 EXPECT_GE(metrics.p99_duration.count(), 98000000);
149 EXPECT_LE(metrics.p99_duration.count(), 100000000);
154 for (
int i = 0; i < 10; ++i) {
155 profiler.record_sample(
"throughput_test",
156 std::chrono::nanoseconds(100000000),
160 auto metrics_result = profiler.get_metrics(
"throughput_test");
161 ASSERT_TRUE(metrics_result.is_ok());
163 auto metrics = metrics_result.value();
164 EXPECT_EQ(metrics.call_count, 10);
166 EXPECT_GE(metrics.throughput, 0.0);
170 profiler.record_sample(
"clear_test", std::chrono::nanoseconds(1000000),
true);
172 auto before_result = profiler.get_metrics(
"clear_test");
173 ASSERT_TRUE(before_result.is_ok());
174 EXPECT_EQ(before_result.value().call_count, 1);
176 auto result = profiler.clear_samples(
"clear_test");
177 ASSERT_TRUE(result.is_ok());
178 EXPECT_TRUE(result.value());
181 auto after_result = profiler.get_metrics(
"clear_test");
182 if (after_result.is_ok()) {
183 EXPECT_EQ(after_result.value().call_count, 0);
188 profiler.record_sample(
"op1", std::chrono::nanoseconds(1000000),
true);
189 profiler.record_sample(
"op2", std::chrono::nanoseconds(2000000),
true);
190 profiler.record_sample(
"op3", std::chrono::nanoseconds(3000000),
true);
192 auto all_metrics = profiler.get_all_metrics();
193 EXPECT_EQ(all_metrics.size(), 3);
195 std::set<std::string> operation_names;
196 for (
const auto& metrics : all_metrics) {
197 operation_names.insert(metrics.operation_name);
200 EXPECT_TRUE(operation_names.count(
"op1") > 0);
201 EXPECT_TRUE(operation_names.count(
"op2") > 0);
202 EXPECT_TRUE(operation_names.count(
"op3") > 0);
206 profiler.set_enabled(
false);
208 auto result = profiler.record_sample(
"disabled_test", std::chrono::nanoseconds(1000000),
true);
209 ASSERT_TRUE(result.is_ok());
212 auto metrics_result = profiler.get_metrics(
"disabled_test");
213 ASSERT_FALSE(metrics_result.is_ok());
215 profiler.set_enabled(
true);
216 profiler.record_sample(
"enabled_test", std::chrono::nanoseconds(1000000),
true);
218 metrics_result = profiler.get_metrics(
"enabled_test");
219 ASSERT_TRUE(metrics_result.is_ok());
226 ASSERT_TRUE(result.is_ok());
228 auto metrics = result.value();
231 EXPECT_GE(metrics.cpu_usage_percent, 0.0);
232 EXPECT_LE(metrics.cpu_usage_percent, 100.0);
234 EXPECT_GE(metrics.memory_usage_percent, 0.0);
235 EXPECT_LE(metrics.memory_usage_percent, 100.0);
237 EXPECT_GT(metrics.memory_usage_bytes, 0);
238 EXPECT_GT(metrics.thread_count, 0);
244 auto start_result = sys_monitor.
start_monitoring(std::chrono::milliseconds(100));
245 ASSERT_TRUE(start_result.is_ok());
248 auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5);
249 std::vector<system_metrics> history;
250 while (std::chrono::steady_clock::now() < deadline) {
251 history = sys_monitor.
get_history(std::chrono::seconds(1));
252 if (history.size() >= 2) {
255 std::this_thread::yield();
258 EXPECT_GE(history.size(), 2);
261 for (
size_t i = 1; i < history.size(); ++i) {
262 EXPECT_GT(history[i].timestamp, history[i - 1].timestamp);
266 ASSERT_TRUE(stop_result.is_ok());
271 monitor.get_profiler().record_sample(
"collect_test", std::chrono::nanoseconds(5000000),
true);
273 auto init_result = monitor.initialize();
274 ASSERT_TRUE(init_result.is_ok());
276 auto snapshot_result = monitor.collect();
277 ASSERT_TRUE(snapshot_result.is_ok());
279 auto snapshot = snapshot_result.value();
280 EXPECT_EQ(snapshot.source_id,
"performance_monitor");
281 EXPECT_GT(snapshot.metrics.size(), 0);
284 bool found_perf_metric =
false;
286 for (
const auto&
metric : snapshot.metrics) {
287 if (
metric.
name.find(
"collect_test") != std::string::npos) {
288 found_perf_metric =
true;
292 EXPECT_TRUE(found_perf_metric);
297 monitor.set_cpu_threshold(0.0);
298 monitor.set_memory_threshold(0.0);
299 monitor.set_latency_threshold(std::chrono::milliseconds(0));
302 monitor.get_profiler().record_sample(
"threshold_test", std::chrono::nanoseconds(1000000),
true);
304 auto init_result = monitor.initialize();
305 ASSERT_TRUE(init_result.is_ok());
307 auto threshold_result = monitor.check_thresholds();
308 ASSERT_TRUE(threshold_result.is_ok());
309 EXPECT_TRUE(threshold_result.value());
317 simulate_work(std::chrono::milliseconds(10));
320 auto metrics_result = global.get_profiler().get_metrics(
"global_test_operation");
321 ASSERT_TRUE(metrics_result.is_ok());
323 auto metrics = metrics_result.value();
324 EXPECT_EQ(metrics.call_count, 1);
325 EXPECT_GE(metrics.mean_duration.count(), 10000000);
333 auto result = benchmark.
run(
"simple_operation", []() {
335 volatile int sum = 0;
336 for (
int i = 0; i < 1000; ++i) {
341 ASSERT_TRUE(result.is_ok());
343 auto metrics = result.value();
344 EXPECT_EQ(metrics.call_count, 100);
345 EXPECT_GT(metrics.mean_duration.count(), 0);
346 EXPECT_GE(metrics.max_duration.count(), metrics.min_duration.count());
354 auto result = benchmark.
compare(
357 volatile int sum = 0;
358 for (
int i = 0; i < 100; ++i) {
364 volatile int sum = 0;
365 for (
int i = 0; i < 10000; ++i) {
370 ASSERT_TRUE(result.is_ok());
372 auto [fast_metrics, slow_metrics] = result.value();
374 EXPECT_EQ(fast_metrics.call_count, 50);
375 EXPECT_EQ(slow_metrics.call_count, 50);
378 EXPECT_LT(fast_metrics.mean_duration, slow_metrics.mean_duration);
382 profiler.set_max_samples(10);
385 for (
int i = 0; i < 20; ++i) {
386 profiler.record_sample(
"limit_test", std::chrono::nanoseconds(i * 1000000),
true);
389 auto metrics_result = profiler.get_metrics(
"limit_test");
390 ASSERT_TRUE(metrics_result.is_ok());
392 auto metrics = metrics_result.value();
394 EXPECT_EQ(metrics.call_count, 20);
398 EXPECT_GE(metrics.min_duration.count(), 10000000);
402 const int num_threads = 10;
403 const int samples_per_thread = 100;
405 std::vector<std::thread> threads;
407 for (
int t = 0; t < num_threads; ++t) {
408 threads.emplace_back([
this, t, samples_per_thread]() {
409 for (
int i = 0; i < samples_per_thread; ++i) {
410 profiler.record_sample(
"concurrent_test",
411 std::chrono::nanoseconds((t + 1) * 1000000),
true);
416 for (
auto& thread : threads) {
420 auto metrics_result = profiler.get_metrics(
"concurrent_test");
421 ASSERT_TRUE(metrics_result.is_ok());
423 auto metrics = metrics_result.value();
424 EXPECT_EQ(metrics.call_count, num_threads * samples_per_thread);
432 auto result = monitor.record_counter(
"requests_total", 1.0);
433 ASSERT_TRUE(result.is_ok());
435 result = monitor.record_counter(
"requests_total", 2.0);
436 ASSERT_TRUE(result.is_ok());
438 auto tagged_metrics = monitor.get_all_tagged_metrics();
439 ASSERT_EQ(tagged_metrics.size(), 1);
441 EXPECT_EQ(tagged_metrics[0].name,
"requests_total");
442 EXPECT_EQ(tagged_metrics[0].value, 3.0);
443 EXPECT_EQ(tagged_metrics[0].type, recorded_metric_type::counter);
444 EXPECT_TRUE(tagged_metrics[0].tags.empty());
448 tag_map tags1 = {{
"method",
"GET"}, {
"endpoint",
"/api/users"}};
449 tag_map tags2 = {{
"method",
"POST"}, {
"endpoint",
"/api/users"}};
451 auto result = monitor.record_counter(
"http_requests", 1.0, tags1);
452 ASSERT_TRUE(result.is_ok());
454 result = monitor.record_counter(
"http_requests", 1.0, tags2);
455 ASSERT_TRUE(result.is_ok());
457 result = monitor.record_counter(
"http_requests", 1.0, tags1);
458 ASSERT_TRUE(result.is_ok());
460 auto tagged_metrics = monitor.get_all_tagged_metrics();
461 ASSERT_EQ(tagged_metrics.size(), 2);
464 auto get_it = std::find_if(tagged_metrics.begin(), tagged_metrics.end(),
466 return m.tags.count(
"method") && m.tags.at(
"method") ==
"GET";
468 ASSERT_NE(get_it, tagged_metrics.end());
469 EXPECT_EQ(get_it->value, 2.0);
472 auto post_it = std::find_if(tagged_metrics.begin(), tagged_metrics.end(),
474 return m.tags.count(
"method") && m.tags.at(
"method") ==
"POST";
476 ASSERT_NE(post_it, tagged_metrics.end());
477 EXPECT_EQ(post_it->value, 1.0);
481 tag_map tags = {{
"pool",
"database"}, {
"host",
"db-primary"}};
483 auto result = monitor.record_gauge(
"active_connections", 10.0, tags);
484 ASSERT_TRUE(result.is_ok());
486 result = monitor.record_gauge(
"active_connections", 15.0, tags);
487 ASSERT_TRUE(result.is_ok());
489 auto tagged_metrics = monitor.get_all_tagged_metrics();
490 ASSERT_EQ(tagged_metrics.size(), 1);
492 EXPECT_EQ(tagged_metrics[0].name,
"active_connections");
493 EXPECT_EQ(tagged_metrics[0].value, 15.0);
494 EXPECT_EQ(tagged_metrics[0].type, recorded_metric_type::gauge);
495 EXPECT_EQ(tagged_metrics[0].tags.size(), 2);
496 EXPECT_EQ(tagged_metrics[0].tags.at(
"pool"),
"database");
500 tag_map tags = {{
"service",
"auth"}, {
"operation",
"login"}};
502 for (
double i = 1.0; i <= 5.0; i += 1.0) {
503 auto result = monitor.record_histogram(
"request_duration_ms", i * 100.0, tags);
504 ASSERT_TRUE(result.is_ok());
507 auto tagged_metrics = monitor.get_all_tagged_metrics();
508 ASSERT_EQ(tagged_metrics.size(), 1);
510 EXPECT_EQ(tagged_metrics[0].name,
"request_duration_ms");
511 EXPECT_EQ(tagged_metrics[0].value, 500.0);
512 EXPECT_EQ(tagged_metrics[0].type, recorded_metric_type::histogram);
516 tag_map tags = {{
"method",
"GET"}, {
"status",
"200"}};
517 monitor.record_counter(
"http_requests", 5.0, tags);
519 auto init_result = monitor.initialize();
520 ASSERT_TRUE(init_result.is_ok());
522 auto snapshot_result = monitor.collect();
523 ASSERT_TRUE(snapshot_result.is_ok());
525 auto snapshot = snapshot_result.value();
529 for (
const auto&
metric : snapshot.metrics) {
543 monitor.record_counter(
"counter1", 1.0);
544 monitor.record_gauge(
"gauge1", 10.0);
546 EXPECT_EQ(monitor.get_all_tagged_metrics().size(), 2);
548 monitor.clear_all_metrics();
550 EXPECT_EQ(monitor.get_all_tagged_metrics().size(), 0);
554 monitor.record_counter(
"test_counter", 1.0);
556 EXPECT_EQ(monitor.get_all_tagged_metrics().size(), 1);
560 EXPECT_EQ(monitor.get_all_tagged_metrics().size(), 0);
564 auto result = monitor.record_counter(
"", 1.0);
565 EXPECT_FALSE(result.is_ok());
570 tag_map tags1 = {{
"a",
"1"}, {
"b",
"2"}};
571 tag_map tags2 = {{
"b",
"2"}, {
"a",
"1"}};
573 monitor.record_counter(
"test_metric", 1.0, tags1);
574 monitor.record_counter(
"test_metric", 1.0, tags2);
576 auto tagged_metrics = monitor.get_all_tagged_metrics();
577 ASSERT_EQ(tagged_metrics.size(), 1);
578 EXPECT_EQ(tagged_metrics[0].value, 2.0);
Scoped performance timer.
std::vector< system_metrics > get_history(std::chrono::seconds duration=std::chrono::seconds(60)) const
Get historical metrics.
common::Result< bool > start_monitoring(std::chrono::milliseconds interval=std::chrono::milliseconds(1000))
Start monitoring system resources.
common::Result< bool > stop_monitoring()
Stop monitoring.
common::Result< system_metrics > get_current_metrics() const
Get current system metrics.
@ timer
StatsD-specific timer metric.
performance_monitor & global_performance_monitor()
Global performance monitor instance.
std::unordered_map< std::string, std::string > tag_map
Type alias for metric tags/labels.
Basic metric structure for interface compatibility.
std::variant< double, int64_t, std::string > value
std::unordered_map< std::string, std::string > tags
Represents a metric value with associated tags.