From 5ea44519f3e51144861bc50f750c4d32c38b4b18 Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fl.fischer@fau.de>
Date: Tue, 23 Mar 2021 14:31:27 +0100
Subject: [PATCH] [IO] make the behavior of the completer thread configurable

Available behaviors:
  * none - the completer thread is not started

  * schedule (default) - the completer thread will reap and schedule available
                         completions from worker IoContexts

  * wakeup - the completer thread will wakeup all workers if it observes completions
             in a worker IoContext. The Fiber produced by the completion will
             be scheduled when the worker in which's IoContext the cqe lies
             reaps its completions.
---
 emper/Emper.hpp              |  9 +++++++++
 emper/Runtime.cpp            | 10 +++++++---
 emper/io/GlobalIoContext.cpp | 11 +++++++++--
 meson.build                  | 10 ++++++++++
 meson_options.txt            |  7 +++++++
 5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/emper/Emper.hpp b/emper/Emper.hpp
index 2138be46..2bfbf49f 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 43ba9be7..e4b18974 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 27b4b075..83799c78 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 9a6bca81..276a7c4e 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 06bd0206..ac1f842c 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',
+)
-- 
GitLab