diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d4f0cf392d36822bb238fc6cff1f290f3935ff2a..0ff78c22d2cc5a72ff40666e8d16d17ad3cd2c0b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -117,7 +117,7 @@ clang-tidy: .emper-stats: variables: - EMPER_STATS: 'true' + EMPER_STATS_ALL: 'true' .emper-userspace-rcu: variables: diff --git a/emper/Blockable.hpp b/emper/Blockable.hpp index fa7019264be11def44de57ab3ed6087771c308ef..e5ba18c2664c8494a9a136b53b2028fa0f23a2d3 100644 --- a/emper/Blockable.hpp +++ b/emper/Blockable.hpp @@ -1,5 +1,5 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020-2021 Florian Schmaus +// Copyright © 2020-2022 Florian Schmaus #pragma once #include <utility> @@ -42,7 +42,7 @@ class Blockable : public Logger<logSubsystem> { blockablePurpose(blockablePurpose) {} void maybeSetAffinity() { - if constexpr (!emper::SET_AFFINITY_ON_BLOCK && !emper::STATS) return; + if constexpr (!emper::SET_AFFINITY_ON_BLOCK && !emper::STATS_BLOCKED_CONTEXT) return; // TODO: At some point we may want to have something like // Runtime::isAffinityCapable() and return here if it is @@ -58,7 +58,7 @@ class Blockable : public Logger<logSubsystem> { this->affinity = &affinity_buffer; } - if (emper::STATS || setAffinityBuffer) { + if (emper::STATS_BLOCKED_CONTEXT || setAffinityBuffer) { affinity_buffer = Runtime::getWorkerId(); } } @@ -75,23 +75,19 @@ class Blockable : public Logger<logSubsystem> { maybeSetAffinity(); - decltype(blockedContexts)::set_type::size_type blockedContextCount = 0; + if constexpr (emper::STATS_BLOCKED_CONTEXT_COUNT) { + size_t blockedContextCount = + runtime.blockedContextCount.fetch_add(1, std::memory_order_relaxed) + 1; + emper::stats::worker->recordBlockedContextCount(blockedContextCount); + } + if constexpr (emper::BLOCKED_CONTEXT_SET) { auto* currentContext = Context::getCurrentContext(); - - if constexpr (emper::STATS) { - blockedContextCount = blockedContexts.insertAndGetSize(currentContext); - } else { - blockedContexts.insert(currentContext); - } + blockedContexts.insert(currentContext); } - if constexpr (emper::STATS) { - // Note that blockedContextCount may not been set here if - // emper::BLOCKED_CONTEXT_SET is not enabled. But we will at - // least record a blocked context here if emper::STATS is - // enabled. - emper::stats::worker->recordBlockedContext(blockedContextCount, blockablePurpose); + if constexpr (emper::STATS_BLOCKED_CONTEXT) { + emper::stats::worker->recordBlockedContext(blockablePurpose); } contextManager.saveAndStartNew(std::move(freshContextHook)); @@ -99,11 +95,14 @@ class Blockable : public Logger<logSubsystem> { auto unblockAndGetContinuation(Context* context) -> Fiber* { assert(context != nullptr); + if constexpr (emper::STATS_BLOCKED_CONTEXT_COUNT) { + runtime.blockedContextCount.fetch_sub(1, std::memory_order_relaxed); + } if constexpr (emper::BLOCKED_CONTEXT_SET) { blockedContexts.erase(context); } - if constexpr (emper::STATS) { + if constexpr (emper::STATS_BLOCKED_CONTEXT) { if (likely(emper::stats::worker)) { emper::stats::worker->recordUnblockedContext(affinity_buffer, blockablePurpose); } else { diff --git a/emper/Emper.hpp b/emper/Emper.hpp index 02df6edf814c1231191add6857956f1ecfda8b95..77c40ed1c3b0c9eeb40161f29f1abc5e0733de1c 100644 --- a/emper/Emper.hpp +++ b/emper/Emper.hpp @@ -35,13 +35,18 @@ const StatsStackUsage STATS_STACK_USAGE = StatsStackUsage::EMPER_STATS_STACK_USA const bool STATS_STACK_USAGE_ENABLED = STATS_STACK_USAGE != StatsStackUsage::disabled; +constexpr bool STATS_WORKER_SLEEP = EMPER_STATS_WORKER_SLEEP; +constexpr bool STATS_BLOCKED_CONTEXT = EMPER_STATS_BLOCKED_CONTEXT; +constexpr bool STATS_BLOCKED_CONTEXT_COUNT = EMPER_STATS_BLOCKED_CONTEXT_COUNT; + const bool STATS = #ifdef EMPER_STATS true #else false #endif - || STATS_STACK_USAGE_ENABLED; + || STATS_STACK_USAGE_ENABLED || STATS_WORKER_SLEEP || STATS_BLOCKED_CONTEXT || + STATS_BLOCKED_CONTEXT_COUNT; template <typename C> void statsIncr(C& counter) { @@ -317,12 +322,4 @@ const bool STACK_GUARD_PAGE = #endif ; -constexpr bool STATS_WORKER_SLEEP = -#ifdef EMPER_STATS_WORKER_SLEEP - true -#else - false -#endif - ; - } // namespace emper diff --git a/emper/Runtime.hpp b/emper/Runtime.hpp index 9546b932d79e1d1efc001298c5a59fd479a598df..b8388f878b1d04137bcea6cb7749d1bdc419245e 100644 --- a/emper/Runtime.hpp +++ b/emper/Runtime.hpp @@ -121,6 +121,9 @@ class Runtime : public Logger<LogSubsystem::RUNTI> { WorkerSleepStrategy workerSleepStrategy; emper::WakeupStrategy wakeupStrategy; + // Per runtime-system stats + ALIGN_TO_CACHE_LINE std::atomic<size_t> blockedContextCount{0}; + static StrategyFactory DEFAULT_STRATEGY_FACTORY; static void printLastRuntimeStats(std::ostream& out = std::cout); diff --git a/emper/stats/Worker.cpp b/emper/stats/Worker.cpp index a984564ca09d8700100ac77830b99afee1ac90d0..3b2cac4e7d358f122927483db3447cc5516bba8c 100644 --- a/emper/stats/Worker.cpp +++ b/emper/stats/Worker.cpp @@ -20,9 +20,11 @@ Worker::Worker(workerid_t workerCount) unblockAffinitiesIo(std::vector<uint32_t>(workerCount)), lastStackUsage(32) {} -void Worker::recordBlockedContext(size_t blockedContextCount, BlockablePurpose blockablePurpose) { +void Worker::recordBlockedContextCount(size_t blockedContextCount) { maxBlockedContexts = std::max(maxBlockedContexts, blockedContextCount); +} +void Worker::recordBlockedContext(BlockablePurpose blockablePurpose) { switch (blockablePurpose) { case BlockablePurpose::GENERIC: blockedGeneric++; @@ -66,14 +68,19 @@ void Worker::recordSleep(std::chrono::time_point<std::chrono::system_clock>& sle } auto Worker::operator+=(const Worker& other) -> Worker& { - maxBlockedContexts = std::max(maxBlockedContexts, other.maxBlockedContexts); - blockedGeneric += other.blockedGeneric; - blockedIo += other.blockedIo; - - for (decltype(unblockAffinitiesGeneric)::size_type i = 0; i < unblockAffinitiesGeneric.size(); - i++) { - unblockAffinitiesGeneric[i] += other.unblockAffinitiesGeneric[i]; - unblockAffinitiesIo[i] += other.unblockAffinitiesIo[i]; + if constexpr (emper::STATS_BLOCKED_CONTEXT_COUNT) { + maxBlockedContexts = std::max(maxBlockedContexts, other.maxBlockedContexts); + } + + if constexpr (emper::STATS_BLOCKED_CONTEXT) { + blockedGeneric += other.blockedGeneric; + blockedIo += other.blockedIo; + + for (decltype(unblockAffinitiesGeneric)::size_type i = 0; i < unblockAffinitiesGeneric.size(); + i++) { + unblockAffinitiesGeneric[i] += other.unblockAffinitiesGeneric[i]; + unblockAffinitiesIo[i] += other.unblockAffinitiesIo[i]; + } } if constexpr (emper::STATS_STACK_USAGE_ENABLED) { @@ -99,17 +106,22 @@ auto Worker::operator+=(const Worker& other) -> Worker& { } void Worker::print(std::ostream& out) { - out << "max-blocked-contexts: " << std::to_string(maxBlockedContexts) << std::endl - << "blocked-generic: " << std::to_string(blockedGeneric) << std::endl; - for (decltype(unblockAffinitiesGeneric)::size_type i = 0; i < unblockAffinitiesGeneric.size(); - ++i) { - out << "unblock-affinities-generic" << std::to_string(i) << ": " - << std::to_string(unblockAffinitiesGeneric[i]) << std::endl; + if constexpr (emper::STATS_BLOCKED_CONTEXT_COUNT) { + out << "max-blocked-contexts: " << std::to_string(maxBlockedContexts) << std::endl; } - out << "blocked-io: " << std::to_string(blockedIo) << std::endl; - for (decltype(unblockAffinitiesIo)::size_type i = 0; i < unblockAffinitiesIo.size(); ++i) { - out << "unblock-affinities-io" << std::to_string(i) << ": " - << std::to_string(unblockAffinitiesIo[i]) << std::endl; + + if constexpr (emper::STATS_BLOCKED_CONTEXT) { + out << "blocked-generic: " << std::to_string(blockedGeneric) << std::endl; + for (decltype(unblockAffinitiesGeneric)::size_type i = 0; i < unblockAffinitiesGeneric.size(); + ++i) { + out << "unblock-affinities-generic" << std::to_string(i) << ": " + << std::to_string(unblockAffinitiesGeneric[i]) << std::endl; + } + out << "blocked-io: " << std::to_string(blockedIo) << std::endl; + for (decltype(unblockAffinitiesIo)::size_type i = 0; i < unblockAffinitiesIo.size(); ++i) { + out << "unblock-affinities-io" << std::to_string(i) << ": " + << std::to_string(unblockAffinitiesIo[i]) << std::endl; + } } if constexpr (emper::STATS_STACK_USAGE_ENABLED) { diff --git a/emper/stats/Worker.hpp b/emper/stats/Worker.hpp index c70dd52adf10ef9e0ef51f0af006c2f78c98fbd6..f302ddf9ef71d5606b29fdb4c758f4fa56312452 100644 --- a/emper/stats/Worker.hpp +++ b/emper/stats/Worker.hpp @@ -34,8 +34,8 @@ class Worker { Worker(workerid_t workerCount); - void recordBlockedContext(size_t blockedContextCount, BlockablePurpose blockablePurpose); - + void recordBlockedContextCount(size_t blockedContextCount); + void recordBlockedContext(BlockablePurpose blockablePurpose); void recordUnblockedContext(workeraffinity_t workerAffinity, BlockablePurpose blockablePurpose); size_t maxStackUsage = 0; diff --git a/meson.build b/meson.build index 9499fc8884237ddc99d50c45a36b4c60a9c4741e..d08933072666fc92f59feb13559ef2a59ef0a4f2 100644 --- a/meson.build +++ b/meson.build @@ -58,15 +58,12 @@ ws_queue_scheduler = get_option('ws_queue_scheduler') assume_page_size = get_option('assume_page_size') assume_cache_line_size = get_option('assume_cache_line_size') -stats = get_option('stats') - stats_all = get_option('stats_all') stats_worker_sleep_option = get_option('stats_worker_sleep') -if stats_worker_sleep_option == 'enabled' or (stats_all and stats_worker_sleep_option == 'auto') - stats_worker_sleep = true - stats = true +if stats_worker_sleep_option == 'true' or (stats_all and stats_worker_sleep_option == 'auto') + stats_worker_sleep = 'true' else - stats_worker_sleep = false + stats_worker_sleep = 'false' endif stats_stack_usage_option = get_option('stats_stack_usage') if stats_stack_usage_option == 'auto' @@ -78,8 +75,17 @@ if stats_stack_usage_option == 'auto' else stats_stack_usage = stats_stack_usage_option endif -if stats_stack_usage != 'disabled' - stats = true +stats_blocked_context_option = get_option('stats_blocked_context') +if stats_blocked_context_option == 'true' or (stats_all and stats_blocked_context_option == 'auto') + stats_blocked_context = 'true' +else + stats_blocked_context = 'false' +endif +stats_blocked_context_count_option = get_option('stats_blocked_context_count') +if stats_blocked_context_count_option == 'true' or (stats_all and stats_blocked_context_count_option == 'auto') + stats_blocked_context_count = 'true' +else + stats_blocked_context_count = 'false' endif @@ -88,7 +94,7 @@ conf_data.set('EMPER_WORKER_WAKEUP_STRATEGY', get_option('worker_wakeup_strategy conf_data.set('EMPER_WORKER_IGNORE_WAKEUP_HINT', get_option('worker_ignore_wakeup_hint')) conf_data.set('EMPER_LOCKED_MPSC_QUEUE', get_option('locked_mpsc_queue')) conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) -conf_data.set('EMPER_STATS', stats) +conf_data.set('EMPER_STATS', get_option('stats')) conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) conf_data.set('EMPER_BLOCKED_CONTEXT_SET', get_option('blocked_context_set')) conf_data.set('EMPER_SET_AFFINITY_ON_BLOCK', get_option('set_affinity_on_block')) @@ -104,6 +110,8 @@ conf_data.set('EMPER_ASSUME_CACHE_LINE_SIZE', assume_cache_line_size) conf_data.set('EMPER_STACK_GUARD_PAGE', get_option('stack_guard_page')) conf_data.set('EMPER_STATS_STACK_USAGE', stats_stack_usage) conf_data.set('EMPER_STATS_WORKER_SLEEP', stats_worker_sleep) +conf_data.set('EMPER_STATS_BLOCKED_CONTEXT', stats_blocked_context) +conf_data.set('EMPER_STATS_BLOCKED_CONTEXT_COUNT', stats_blocked_context_count) context_alignment = get_option('context_alignment') if context_alignment == 'none' diff --git a/meson_options.txt b/meson_options.txt index 71da8976fe6eff571a2b6964da754f86c543b736..8762050f217ce4ae936c5cc54ceb6c92a4ec6517 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -138,13 +138,35 @@ option( 'stats_worker_sleep', type: 'combo', choices: [ - 'disabled', + 'false', 'auto', - 'enabled', + 'true', ], value: 'auto', description: 'Collect stats about worker sleep', ) +option( + 'stats_blocked_context', + type: 'combo', + choices: [ + 'false', + 'auto', + 'true', + ], + value: 'auto', + description: 'Collect stats about blocked contexts', +) +option( + 'stats_blocked_context_count', + type: 'combo', + choices: [ + 'false', + 'auto', + 'true', + ], + value: 'auto', + description: 'Collect stats about number of blocked contexts', +) option( 'stats_all', type: 'boolean',