From 86a21aee4e07cd118bbb0458f29ee68e96b92e76 Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Wed, 6 Feb 2019 14:57:44 -0700 Subject: [PATCH] event: Implement context switch monitor without a poller This is much simpler and avoids the problems with requiring it to run on a thread. Change-Id: I811444c5a15d292356703beccc17e505d55d7678 Signed-off-by: Ben Walker Reviewed-on: https://review.gerrithub.io/c/443645 Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto Tested-by: SPDK CI Jenkins --- lib/event/reactor.c | 66 +++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/lib/event/reactor.c b/lib/event/reactor.c index 686c3cebb..1d3fc8ab6 100644 --- a/lib/event/reactor.c +++ b/lib/event/reactor.c @@ -162,10 +162,11 @@ _spdk_event_queue_run_batch(struct spdk_reactor *reactor, struct spdk_thread *th return count; } +#define CONTEXT_SWITCH_MONITOR_PERIOD 1000000 + static int -get_rusage(void *arg) +get_rusage(struct spdk_reactor *reactor) { - struct spdk_reactor *reactor = arg; struct rusage rusage; if (getrusage(RUSAGE_THREAD, &rusage) != 0) { @@ -183,46 +184,14 @@ get_rusage(void *arg) return -1; } -static void -_spdk_reactor_context_switch_monitor_start(void *arg1, void *arg2) -{ - struct spdk_reactor *reactor = arg1; - - if (reactor->rusage_poller == NULL) { - getrusage(RUSAGE_THREAD, &reactor->rusage); - reactor->rusage_poller = spdk_poller_register(get_rusage, reactor, 1000000); - } -} - -static void -_spdk_reactor_context_switch_monitor_stop(void *arg1, void *arg2) -{ - struct spdk_reactor *reactor = arg1; - - if (reactor->rusage_poller != NULL) { - spdk_poller_unregister(&reactor->rusage_poller); - } -} - void spdk_reactor_enable_context_switch_monitor(bool enable) { - struct spdk_reactor *reactor; - spdk_event_fn fn; - uint32_t core; - - if (enable != g_context_switch_monitor_enabled) { - g_context_switch_monitor_enabled = enable; - if (enable) { - fn = _spdk_reactor_context_switch_monitor_start; - } else { - fn = _spdk_reactor_context_switch_monitor_stop; - } - SPDK_ENV_FOREACH_CORE(core) { - reactor = spdk_reactor_get(core); - spdk_event_call(spdk_event_allocate(core, fn, reactor, NULL)); - } - } + /* This global is being read by multiple threads, so this isn't + * strictly thread safe. However, we're toggling between true and + * false here, and if a thread sees the value update later than it + * should, it's no big deal. */ + g_context_switch_monitor_enabled = enable; } bool @@ -236,6 +205,7 @@ _spdk_reactor_run(void *arg) { struct spdk_reactor *reactor = arg; struct spdk_thread *thread; + uint64_t last_rusage = 0; char thread_name[32]; snprintf(thread_name, sizeof(thread_name), "reactor_%u", reactor->lcore); @@ -245,12 +215,6 @@ _spdk_reactor_run(void *arg) } SPDK_NOTICELOG("Reactor started on core %u\n", reactor->lcore); - if (g_context_switch_monitor_enabled) { - spdk_set_thread(thread); - _spdk_reactor_context_switch_monitor_start(reactor, NULL); - spdk_set_thread(NULL); - } - while (1) { _spdk_event_queue_run_batch(reactor, thread); @@ -259,11 +223,17 @@ _spdk_reactor_run(void *arg) if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) { break; } + + if (g_context_switch_monitor_enabled) { + uint64_t now = spdk_get_ticks(); + + if ((last_rusage + CONTEXT_SWITCH_MONITOR_PERIOD) < now) { + get_rusage(reactor); + last_rusage = now; + } + } } - spdk_set_thread(thread); - _spdk_reactor_context_switch_monitor_stop(reactor, NULL); - spdk_thread_exit(thread); return 0; }