diff --git a/emper/Emper.hpp b/emper/Emper.hpp index 2138be46e5fbbe281492ff551e587464010de8dc..2bfbf49f739dd04d5a0418db7f96a5490b6079e6 100644 --- a/emper/Emper.hpp +++ b/emper/Emper.hpp @@ -97,4 +97,13 @@ static const bool IO_URING_SHARED_WQ = false #endif ; + +enum class IoCompleterBehavior { + schedule, + wakeup, + none, +}; + +static const enum IoCompleterBehavior IO_COMPLETER_BEHAVIOR = + IoCompleterBehavior::EMPER_IO_COMPLETER_BEHAVIOR; } // namespace emper diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp index 43ba9be7f3dfa3aef7e1905b90c52f9e108bd65c..e4b189749222f0913beda1faf4059a5c1e805074 100644 --- a/emper/Runtime.cpp +++ b/emper/Runtime.cpp @@ -92,7 +92,9 @@ Runtime::Runtime(workerid_t workerCount, RuntimeStrategyFactory& strategyFactory // for each worker's IoContext one eventfd read is prepared before the // globalCompleter is started and submits all previously prepared sqes. globalIo = new GlobalIoContext(*this, workerCount); - globalIo->startGlobalCompleter(); + if constexpr (emper::IO_COMPLETER_BEHAVIOR != emper::IoCompleterBehavior::none) { + globalIo->startGlobalCompleter(); + } if constexpr (emper::STATS) { globalIo->stats.workerId = -1; @@ -196,8 +198,10 @@ auto Runtime::workerLoop(Worker* worker) -> void* { if constexpr (emper::IO) { auto* workerIo = new IoContext(*this); - // submit the workers' CQ eventfds to the global IoContext - globalIo->registerWorkerIo(*workerIo); + if constexpr (emper::IO_COMPLETER_BEHAVIOR != emper::IoCompleterBehavior::none) { + // submit the workers' CQ eventfds to the global IoContext + globalIo->registerWorkerIo(*workerIo); + } // notify the globalCompleter that we have registered our eventfd ioReadySem.notify(); diff --git a/emper/io/GlobalIoContext.cpp b/emper/io/GlobalIoContext.cpp index 27b4b0752f5f813676f839a3f7c3e73bc14e0c08..83799c7829130fab1908727fcfbb6994f33faeec 100644 --- a/emper/io/GlobalIoContext.cpp +++ b/emper/io/GlobalIoContext.cpp @@ -14,6 +14,7 @@ #include "CallerEnvironment.hpp" #include "Common.hpp" +#include "Emper.hpp" #include "Runtime.hpp" #include "io/Future.hpp" #include "io/IoContext.hpp" @@ -82,7 +83,7 @@ auto GlobalIoContext::globalCompleterFunc(void* arg) -> void* { // -> there are completions on this worker IoContext switch (tag) { // clang-11 does not support [[likely]] yet - // TODO: remove the preprocessor check if clang ass [[likely]] support + // TODO: remove the preprocessor check if clang has [[likely]] support #if defined __has_attribute #if __has_attribute(likely) [[likely]] // NOLINT(clang-diagnostic-unknown-attributes) @@ -103,7 +104,13 @@ auto GlobalIoContext::globalCompleterFunc(void* arg) -> void* { assert(submitted == 1); - worker_io->reapAndScheduleCompletions<CallerEnvironment::ANYWHERE>(); + if constexpr (emper::IO_COMPLETER_BEHAVIOR == emper::IoCompleterBehavior::wakeup) { + // Only wakeup sleeping workers and hope that the worker which + // has ready cqes will reap them soon. + globalIoContext->runtime.wakeupSleepingWorkers<CallerEnvironment::ANYWHERE>(); + } else { + worker_io->reapAndScheduleCompletions<CallerEnvironment::ANYWHERE>(); + } } break; diff --git a/meson.build b/meson.build index 9a6bca81395dbc6709f34424cceb7d1d02aca18a..276a7c4e1dd24563e7229d6aa5db5d999d2c9cb5 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,16 @@ endforeach io_cq_lock_impl = get_option('io_cq_lock_implementation') conf_data.set('EMPER_IO_CQ_LOCK_' + io_cq_lock_impl.to_upper(), true) +io_completer_behavior = get_option('io_completer_behavior') +if io_completer_behavior == 'maybe_wakeup' + if get_option('worker_sleep') + io_completer_behavior = 'wakeup' + else + io_completer_behavior = 'none' + endif +endif +conf_data.set('EMPER_IO_COMPLETER_BEHAVIOR', io_completer_behavior) + subdir('emper') subdir('tests') subdir('apps') diff --git a/meson_options.txt b/meson_options.txt index 06bd0206e6218ed75a6d44f669ca504ea368ef4e..ac1f842cd90c82f09a9b80c5cd3538b34b724f9b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -122,3 +122,10 @@ option( choices: ['spin_lock', 'counting_try_lock', 'mutex'], value: 'counting_try_lock', ) +option( + 'io_completer_behavior', + type: 'combo', + description: 'The behaviour of the IO completer thread', + choices: ['schedule', 'maybe_wakeup'], + value: 'schedule', +)