From 2b9cc262086b0446596780f29f5338e2869f42b9 Mon Sep 17 00:00:00 2001 From: Aaditya Ravindran Date: Thu, 17 Apr 2025 13:59:43 -0400 Subject: [PATCH 1/4] Make send thread safe --- include/cpp-statsd-client/StatsdClient.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/cpp-statsd-client/StatsdClient.hpp b/include/cpp-statsd-client/StatsdClient.hpp index 7114432..eab5705 100644 --- a/include/cpp-statsd-client/StatsdClient.hpp +++ b/include/cpp-statsd-client/StatsdClient.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -165,6 +166,9 @@ class StatsdClient { //! The buffer string format our stats before sending them mutable std::string m_buffer; + //! The mutex to lock m_buffer + mutable std::mutex m_buffer_mutex; + //! Fixed floating point precision of gauges int m_gaugePrecision; }; @@ -291,6 +295,7 @@ inline void StatsdClient::send(const std::string& key, std::stringstream valueStream; valueStream << std::fixed << std::setprecision(m_gaugePrecision) << value; + std::lock_guard buffer_lock(m_buffer_mutex); m_buffer.clear(); m_buffer.append(m_prefix); From 933caf6485330eac875c754c9e583b55d5798535 Mon Sep 17 00:00:00 2001 From: Aaditya Ravindran Date: Thu, 17 Apr 2025 19:19:43 -0400 Subject: [PATCH 2/4] Use local buffer --- include/cpp-statsd-client/StatsdClient.hpp | 41 +++++++++------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/include/cpp-statsd-client/StatsdClient.hpp b/include/cpp-statsd-client/StatsdClient.hpp index eab5705..e9b219c 100644 --- a/include/cpp-statsd-client/StatsdClient.hpp +++ b/include/cpp-statsd-client/StatsdClient.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -163,12 +162,6 @@ class StatsdClient { //! The random number generator for handling sampling mutable std::mt19937 m_randomEngine; - //! The buffer string format our stats before sending them - mutable std::string m_buffer; - - //! The mutex to lock m_buffer - mutable std::mutex m_buffer_mutex; - //! Fixed floating point precision of gauges int m_gaugePrecision; }; @@ -200,8 +193,6 @@ inline StatsdClient::StatsdClient(const std::string& host, m_gaugePrecision(gaugePrecision) { // Initialize the random generator to be used for sampling seed(); - // Avoid re-allocations by reserving a generous buffer - m_buffer.reserve(256); } inline void StatsdClient::setConfig(const std::string& host, @@ -295,36 +286,36 @@ inline void StatsdClient::send(const std::string& key, std::stringstream valueStream; valueStream << std::fixed << std::setprecision(m_gaugePrecision) << value; - std::lock_guard buffer_lock(m_buffer_mutex); - m_buffer.clear(); + std::string buffer; + buffer.reserve(256); - m_buffer.append(m_prefix); + buffer.append(m_prefix); if (!m_prefix.empty() && !key.empty()) { - m_buffer.push_back('.'); + buffer.push_back('.'); } - m_buffer.append(key); - m_buffer.push_back(':'); - m_buffer.append(valueStream.str()); - m_buffer.push_back('|'); - m_buffer.append(type); + buffer.append(key); + buffer.push_back(':'); + buffer.append(valueStream.str()); + buffer.push_back('|'); + buffer.append(type); if (frequency < 1.f) { - m_buffer.append("|@0."); - m_buffer.append(std::to_string(static_cast(frequency * 100))); + buffer.append("|@0."); + buffer.append(std::to_string(static_cast(frequency * 100))); } if (!tags.empty()) { - m_buffer.append("|#"); + buffer.append("|#"); for (const auto& tag : tags) { - m_buffer.append(tag); - m_buffer.push_back(','); + buffer.append(tag); + buffer.push_back(','); } - m_buffer.pop_back(); + buffer.pop_back(); } // Send the message via the UDP sender - m_sender->send(m_buffer); + m_sender->send(buffer); } inline void StatsdClient::seed(unsigned int seed) noexcept { From 2fd731f1554da6528b70fba834cecfcf1ab40f45 Mon Sep 17 00:00:00 2001 From: Aaditya Ravindran Date: Mon, 21 Apr 2025 09:58:39 -0400 Subject: [PATCH 3/4] static thread_local string buffer --- include/cpp-statsd-client/StatsdClient.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/cpp-statsd-client/StatsdClient.hpp b/include/cpp-statsd-client/StatsdClient.hpp index e9b219c..edb973d 100644 --- a/include/cpp-statsd-client/StatsdClient.hpp +++ b/include/cpp-statsd-client/StatsdClient.hpp @@ -286,7 +286,8 @@ inline void StatsdClient::send(const std::string& key, std::stringstream valueStream; valueStream << std::fixed << std::setprecision(m_gaugePrecision) << value; - std::string buffer; + static thread_local std::string buffer; + buffer.clear(); buffer.reserve(256); buffer.append(m_prefix); From deb4df9cedceffb39757ed1b62eaa20a9f3070fa Mon Sep 17 00:00:00 2001 From: Aaditya Ravindran Date: Mon, 21 Apr 2025 10:09:20 -0400 Subject: [PATCH 4/4] comment --- include/cpp-statsd-client/StatsdClient.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/cpp-statsd-client/StatsdClient.hpp b/include/cpp-statsd-client/StatsdClient.hpp index edb973d..37a5837 100644 --- a/include/cpp-statsd-client/StatsdClient.hpp +++ b/include/cpp-statsd-client/StatsdClient.hpp @@ -286,6 +286,8 @@ inline void StatsdClient::send(const std::string& key, std::stringstream valueStream; valueStream << std::fixed << std::setprecision(m_gaugePrecision) << value; + // the thread keeps this buffer around and reuses it, clear should be O(1) + // and reserve should only have to do so the first time, after that, it's a no-op static thread_local std::string buffer; buffer.clear(); buffer.reserve(256);