From 11106441b37f020e4b2a99ae34c38d581b1e9aee Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sun, 9 Aug 2026 14:18:44 +0000 Subject: [PATCH 1/2] fix: use calibrated TSC frequency --- CMakeLists.txt | 2 +- src/storage/shard.cpp | 86 +++++++------------------------------------ 2 files changed, 15 insertions(+), 73 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68d076ac..2b9ddc08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,7 +166,7 @@ target_include_directories(eloqstore PRIVATE ${LIBZMQ_INCLUDE_DIRS}) # PUBLIC: engine public headers (async_io_manager.h, kill_point.h) include # glog/logging.h. target_link_libraries(eloqstore PUBLIC glog::glog) -target_link_libraries(eloqstore PRIVATE ${URING_LIB} absl::flat_hash_map ${BOOST_CONTEXT_TARGET} ${CURL_LIBRARIES} jsoncpp_lib ${ZSTD_LIBRARY} aws-cpp-sdk-core OpenSSL::Crypto ${LIBZMQ_LIBRARIES}) +target_link_libraries(eloqstore PRIVATE ${URING_LIB} absl::base absl::flat_hash_map ${BOOST_CONTEXT_TARGET} ${CURL_LIBRARIES} jsoncpp_lib ${ZSTD_LIBRARY} aws-cpp-sdk-core OpenSSL::Crypto ${LIBZMQ_LIBRARIES}) set(ELOQ_STORE_CAPI_INCLUDE ${ELOQ_STORE_INCLUDE} diff --git a/src/storage/shard.cpp b/src/storage/shard.cpp index ed01eae8..4de0aafc 100644 --- a/src/storage/shard.cpp +++ b/src/storage/shard.cpp @@ -14,6 +14,7 @@ #include #if defined(__x86_64__) || defined(_M_X64) +#include #include // For __rdtsc() #endif @@ -1422,12 +1423,7 @@ bool Shard::HasPendingRequests() const return requests_.size_approx() > 0; } -/** @brief - * Measure TSC frequency by sleeping for 1ms and measuring cycles. - * Retries until stable (within 1% difference) or up to 16ms total. - * Should be called once during data substrate initialization. - * This function is thread-safe and will only execute once. - */ +/** @brief Initialize the hardware-counter frequency once. */ void Shard::InitializeTscFrequency() { #if defined(__x86_64__) || defined(_M_X64) @@ -1435,72 +1431,18 @@ void Shard::InitializeTscFrequency() tsc_frequency_initialized_, []() { - constexpr uint64_t SLEEP_MICROSECONDS = 1000; // 1ms - constexpr uint64_t MAX_TOTAL_MICROSECONDS = 16000; // 16ms max - constexpr double STABILITY_THRESHOLD = - 0.01; // 1% difference for stability - - uint64_t prev_freq = 0; - uint64_t total_slept = 0; - int stable_count = 0; - constexpr int REQUIRED_STABLE_COUNT = - 2; // Need 2 consecutive stable measurements - - while (total_slept < MAX_TOTAL_MICROSECONDS) - { - uint64_t start_cycles = __rdtsc(); - std::this_thread::sleep_for( - std::chrono::microseconds(SLEEP_MICROSECONDS)); - uint64_t end_cycles = __rdtsc(); - uint64_t elapsed_cycles = end_cycles - start_cycles; - uint64_t freq = elapsed_cycles / - SLEEP_MICROSECONDS; // cycles per microsecond - - total_slept += SLEEP_MICROSECONDS; - - // Check if frequency is stable (within 1% of previous - // measurement) - if (prev_freq > 0) - { - double diff_ratio = - (freq > prev_freq) - ? static_cast(freq - prev_freq) / prev_freq - : static_cast(prev_freq - freq) / prev_freq; - if (diff_ratio <= STABILITY_THRESHOLD) - { - stable_count++; - if (stable_count >= REQUIRED_STABLE_COUNT) - { - // Frequency is stable, use the average - tsc_cycles_per_microsecond_.store( - (prev_freq + freq) / 2, - std::memory_order_release); - return; - } - } - else - { - stable_count = 0; // Reset stability counter - } - } - - prev_freq = freq; - } - - // If we couldn't get stable measurement, use the last measured - // value - if (prev_freq > 0) - { - tsc_cycles_per_microsecond_.store(prev_freq, - std::memory_order_release); - } - else - { - // Fallback to approximate value if measurement failed - tsc_cycles_per_microsecond_.store(2000, - std::memory_order_release); - } - }); // End of lambda passed to std::call_once + // sleep_for() may oversleep when the initializing thread is + // descheduled. Dividing the elapsed TSC ticks by the requested + // sleep duration then overestimates the frequency and makes all + // work-loop budgets run long. Abseil calibrates the raw TSC + // against the actual elapsed monotonic time instead. + const double frequency_hz = + absl::base_internal::NominalCPUFrequency(); + const uint64_t cycles_per_microsecond = std::max( + 1, static_cast(frequency_hz / 1'000'000.0)); + tsc_cycles_per_microsecond_.store(cycles_per_microsecond, + std::memory_order_release); + }); #elif defined(__aarch64__) std::call_once(tsc_frequency_initialized_, []() From 12f1bdc05cc6f5d03fb8e2cc20fc3389a4e86df5 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Sun, 9 Aug 2026 14:24:30 +0000 Subject: [PATCH 2/2] docs: clarify TSC frequency source --- src/storage/shard.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/storage/shard.cpp b/src/storage/shard.cpp index 4de0aafc..babf7651 100644 --- a/src/storage/shard.cpp +++ b/src/storage/shard.cpp @@ -1431,11 +1431,7 @@ void Shard::InitializeTscFrequency() tsc_frequency_initialized_, []() { - // sleep_for() may oversleep when the initializing thread is - // descheduled. Dividing the elapsed TSC ticks by the requested - // sleep duration then overestimates the frequency and makes all - // work-loop budgets run long. Abseil calibrates the raw TSC - // against the actual elapsed monotonic time instead. + // This frequency uses the same raw TSC scale as __rdtsc(). const double frequency_hz = absl::base_internal::NominalCPUFrequency(); const uint64_t cycles_per_microsecond = std::max(