reactor: add context_switch_monitor RPC

This allows the user to enable/disable getrusage() monitoring at
runtime.

Also change the log level to INFO and enable the monitoring in all
builds, not just #ifdef DEBUG.

Change-Id: I2f5c3bc8cd83dcb2a72dc7078bf2cb43aa28827c
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/376473
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Cunyin Chang <cunyin.chang@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Daniel Verkamp 2017-08-30 20:51:19 -07:00 committed by Jim Harris
parent 491a44a71c
commit 70c3e1f2eb
4 changed files with 128 additions and 15 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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)