diff --git a/include/spdk/event.h b/include/spdk/event.h index 08c38da3e..65281b985 100644 --- a/include/spdk/event.h +++ b/include/spdk/event.h @@ -176,4 +176,14 @@ void spdk_poller_register(struct spdk_poller **ppoller, void spdk_poller_unregister(struct spdk_poller **ppoller, struct spdk_event *complete); +/** + * \brief Enable or disable monitoring of context switches. + */ +void spdk_reactor_enable_context_switch_monitor(bool enabled); + +/** + * \brief Return whether context switch monitoring is enabled. + */ +bool spdk_reactor_context_switch_monitor_enabled(void); + #endif diff --git a/lib/event/reactor.c b/lib/event/reactor.c index 1ef6e7e87..c26d33203 100644 --- a/lib/event/reactor.c +++ b/lib/event/reactor.c @@ -87,13 +87,13 @@ struct spdk_reactor { /* Socket ID for this reactor. */ uint32_t socket_id; -#ifdef DEBUG + /* Poller for get the rusage for the reactor. */ struct spdk_poller *rusage_poller; /* The last known rusage values */ struct rusage rusage; -#endif + /* * Contains pollers actively running on this reactor. Pollers * are run round-robin. The reactor takes one poller from the head @@ -119,6 +119,8 @@ static struct spdk_reactor g_reactors[SPDK_MAX_REACTORS]; static enum spdk_reactor_state g_reactor_state = SPDK_REACTOR_STATE_INVALID; +static bool g_context_switch_monitor_enabled = true; + static void spdk_reactor_construct(struct spdk_reactor *w, uint32_t lcore, uint64_t max_delay_us); @@ -254,7 +256,6 @@ _spdk_reactor_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx) spdk_event_call(event); } -#ifdef DEBUG static void get_rusage(void *arg) { @@ -266,14 +267,61 @@ get_rusage(void *arg) } if (rusage.ru_nvcsw != reactor->rusage.ru_nvcsw || rusage.ru_nivcsw != reactor->rusage.ru_nivcsw) { - SPDK_DEBUGLOG(SPDK_TRACE_REACTOR, - "Reactor %d: %ld voluntary context switches and %ld involuntary context switches in the last second.\n", - reactor->lcore, rusage.ru_nvcsw - reactor->rusage.ru_nvcsw, - rusage.ru_nivcsw - reactor->rusage.ru_nivcsw); + SPDK_INFOLOG(SPDK_TRACE_REACTOR, + "Reactor %d: %ld voluntary context switches and %ld involuntary context switches in the last second.\n", + reactor->lcore, rusage.ru_nvcsw - reactor->rusage.ru_nvcsw, + rusage.ru_nivcsw - reactor->rusage.ru_nivcsw); } reactor->rusage = rusage; } -#endif + +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); + spdk_poller_register(&reactor->rusage_poller, get_rusage, reactor, reactor->lcore, 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, NULL); + } +} + +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)); + } + } +} + +bool +spdk_reactor_context_switch_monitor_enabled(void) +{ + return g_context_switch_monitor_enabled; +} /** * @@ -317,10 +365,9 @@ _spdk_reactor_run(void *arg) sleep_cycles = reactor->max_delay_us * spdk_get_ticks_hz() / 1000000ULL; idle_started = 0; timer_poll_count = 0; -#ifdef DEBUG - getrusage(RUSAGE_THREAD, &reactor->rusage); - spdk_poller_register(&reactor->rusage_poller, get_rusage, reactor, reactor->lcore, 1000000); -#endif + if (g_context_switch_monitor_enabled) { + _spdk_reactor_context_switch_monitor_start(reactor, NULL); + } while (1) { bool took_action = false; @@ -403,13 +450,11 @@ _spdk_reactor_run(void *arg) } if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) { -#ifdef DEBUG - spdk_poller_unregister(&reactor->rusage_poller, NULL); -#endif break; } } + _spdk_reactor_context_switch_monitor_stop(reactor, NULL); spdk_free_thread(); return 0; } diff --git a/lib/event/rpc/app_rpc.c b/lib/event/rpc/app_rpc.c index 4a384456b..6b2789413 100644 --- a/lib/event/rpc/app_rpc.c +++ b/lib/event/rpc/app_rpc.c @@ -33,6 +33,7 @@ #include "spdk/stdinc.h" +#include "spdk/event.h" #include "spdk/rpc.h" #include "spdk/util.h" @@ -108,3 +109,47 @@ invalid: free_rpc_kill_instance(&req); } SPDK_RPC_REGISTER("kill_instance", spdk_rpc_kill_instance) + + +struct rpc_context_switch_monitor { + bool enabled; +}; + +static const struct spdk_json_object_decoder rpc_context_switch_monitor_decoders[] = { + {"enabled", offsetof(struct rpc_context_switch_monitor, enabled), spdk_json_decode_bool}, +}; + +static void +spdk_rpc_context_switch_monitor(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_context_switch_monitor req = {}; + struct spdk_json_write_ctx *w; + + if (params != NULL) { + if (spdk_json_decode_object(params, rpc_context_switch_monitor_decoders, + SPDK_COUNTOF(rpc_context_switch_monitor_decoders), + &req)) { + SPDK_DEBUGLOG(SPDK_TRACE_REACTOR, "spdk_json_decode_object failed\n"); + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters"); + return; + } + + spdk_reactor_enable_context_switch_monitor(req.enabled); + } + + w = spdk_jsonrpc_begin_result(request); + if (w == NULL) { + return; + } + + spdk_json_write_object_begin(w); + + spdk_json_write_name(w, "enabled"); + spdk_json_write_bool(w, spdk_reactor_context_switch_monitor_enabled()); + + spdk_json_write_object_end(w); + spdk_jsonrpc_end_result(request, w); +} + +SPDK_RPC_REGISTER("context_switch_monitor", spdk_rpc_context_switch_monitor) diff --git a/scripts/rpc.py b/scripts/rpc.py index b93d23a36..809127407 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -564,5 +564,18 @@ def get_rpc_methods(args): p = subparsers.add_parser('get_rpc_methods', help='Get list of supported RPC methods') p.set_defaults(func=get_rpc_methods) +def context_switch_monitor(args): + params = {} + if args.enable: + params['enabled'] = True + if args.disable: + params['enabled'] = False + print_dict(jsonrpc_call('context_switch_monitor', params)) + +p = subparsers.add_parser('context_switch_monitor', help='Control whether the context switch monitor is enabled') +p.add_argument('-e', '--enable', action='store_true', help='Enable context switch monitoring') +p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring') +p.set_defaults(func=context_switch_monitor) + args = parser.parse_args() args.func(args)