From 66a144200f0d39ba91a49fe94cf32d0f85dffc11 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 14 Aug 2024 18:29:59 +0800 Subject: [PATCH] add bench and fix (#755) --- include/ylt/metric/counter.hpp | 6 +- include/ylt/metric/thread_local_value.hpp | 10 +- src/metric/benchmark/CMakeLists.txt | 4 + src/metric/benchmark/main.cpp | 107 ++++++++++++++++++++++ 4 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 src/metric/benchmark/CMakeLists.txt create mode 100644 src/metric/benchmark/main.cpp diff --git a/include/ylt/metric/counter.hpp b/include/ylt/metric/counter.hpp index 246b8ed47..90130987f 100644 --- a/include/ylt/metric/counter.hpp +++ b/include/ylt/metric/counter.hpp @@ -72,13 +72,13 @@ class basic_static_counter : public static_metric { // static counter, contains a static labels with atomic value. basic_static_counter(std::string name, std::string help, std::map labels, - size_t dupli_count = 2) + uint32_t dupli_count = 2) : static_metric(MetricType::Counter, std::move(name), std::move(help), std::move(labels)) { init_thread_local(dupli_count); } - void init_thread_local(size_t dupli_count) { + void init_thread_local(uint32_t dupli_count) { if (dupli_count > 0) { dupli_count_ = dupli_count; default_label_value_ = {dupli_count}; @@ -163,7 +163,7 @@ class basic_static_counter : public static_metric { } thread_local_value default_label_value_; - size_t dupli_count_ = 2; + uint32_t dupli_count_ = 2; }; template diff --git a/include/ylt/metric/thread_local_value.hpp b/include/ylt/metric/thread_local_value.hpp index 2a13b2edc..b73789dd8 100644 --- a/include/ylt/metric/thread_local_value.hpp +++ b/include/ylt/metric/thread_local_value.hpp @@ -6,15 +6,15 @@ #include namespace ylt::metric { -inline size_t get_round_index(size_t size) { - static std::atomic round = 0; - static thread_local size_t index = round++; +inline uint32_t get_round_index(uint32_t size) { + static std::atomic round = 0; + static thread_local uint32_t index = round++; return index % size; } template class thread_local_value { public: - thread_local_value(size_t dupli_count = std::thread::hardware_concurrency()) + thread_local_value(uint32_t dupli_count = std::thread::hardware_concurrency()) : duplicates_(dupli_count) {} ~thread_local_value() { @@ -73,7 +73,7 @@ class thread_local_value { value_type reset() { return update(0); } auto &local_value() { - static thread_local auto index = get_round_index(duplicates_.size()); + auto index = get_round_index(duplicates_.size()); return get_value(index); } diff --git a/src/metric/benchmark/CMakeLists.txt b/src/metric/benchmark/CMakeLists.txt new file mode 100644 index 000000000..9c1cc76e4 --- /dev/null +++ b/src/metric/benchmark/CMakeLists.txt @@ -0,0 +1,4 @@ +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/benchmark) + +add_executable(metric_benchmark + main.cpp) diff --git a/src/metric/benchmark/main.cpp b/src/metric/benchmark/main.cpp new file mode 100644 index 000000000..af35ce47a --- /dev/null +++ b/src/metric/benchmark/main.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include + +#include "ylt/metric.hpp" + +using namespace std::chrono_literals; +using namespace ylt::metric; + +void bench_static_counter(size_t thd_num, std::chrono::seconds duration, + size_t dupli_count = 2) { + counter_t counter("qps", "", dupli_count); + std::vector vec; + std::atomic stop = false; + auto start = std::chrono::system_clock::now(); + for (size_t i = 0; i < thd_num; i++) { + vec.push_back(std::thread([&] { + while (!stop) { + counter.inc(1); + } + })); + } + + std::this_thread::sleep_for(duration); + stop = true; + auto end = std::chrono::system_clock::now(); + + auto elaps = + std::chrono::duration_cast(end - start) + .count(); + + double seconds = double(elaps) / 1000; + + auto qps = counter.value() / seconds; + std::cout << "duplicate count: " << dupli_count << ", thd num: " << thd_num + << ", qps: " << (uint64_t)qps << "\n"; + + for (auto& thd : vec) { + thd.join(); + } +} + +auto get_random(size_t range = 10000) { + thread_local std::default_random_engine gen(std::time(nullptr)); + std::uniform_int_distribution<> distr(1, range); + return distr(gen); +} + +void bench_dynamic_counter(size_t thd_num, std::chrono::seconds duration, + size_t dupli_count = 2) { + dynamic_counter_t counter("qps2", "", {"url", "code"}, dupli_count); + std::atomic stop = false; + std::vector vec; + std::array arr{"/test", "200"}; + auto start = std::chrono::system_clock::now(); + for (size_t i = 0; i < thd_num; i++) { + vec.push_back(std::thread([&, i] { + while (!stop) { + counter.inc({"/test", std::to_string(get_random())}, 1); + } + })); + } + std::this_thread::sleep_for(duration); + stop = true; + auto end = std::chrono::system_clock::now(); + + auto elaps = + std::chrono::duration_cast(end - start) + .count(); + + double seconds = double(elaps) / 1000; + std::cout << "run " << elaps << "ms, " << seconds << " seconds\n"; + + size_t total = 0; + for (size_t i = 0; i < 10000; i++) { + total += counter.value({"/test", std::to_string(i)}); + } + auto qps = total / seconds; + std::cout << "duplicate count: " << dupli_count << ", thd num: " << thd_num + << ", qps: " << (int64_t)qps << "\n"; + for (auto& thd : vec) { + thd.join(); + } +} + +int main() { + bench_static_counter(1, 5s); + bench_static_counter(2, 5s); + bench_static_counter(8, 5s); + bench_static_counter(16, 5s); + bench_static_counter(32, 5s); + bench_static_counter(96, 5s); + bench_static_counter(32, 5s, 32); + bench_static_counter(96, 5s, 96); + + bench_dynamic_counter(1, 5s); + bench_dynamic_counter(2, 5s); + bench_dynamic_counter(8, 5s); + bench_dynamic_counter(16, 5s); + bench_dynamic_counter(32, 5s); + bench_dynamic_counter(96, 10s); + bench_dynamic_counter(32, 5s, 32); + bench_dynamic_counter(96, 5s, 96); +}