Commit 70c3e1f2 authored by Daniel Verkamp's avatar Daniel Verkamp Committed by Jim Harris
Browse files

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: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-on: https://review.gerrithub.io/376473


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarCunyin Chang <cunyin.chang@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
parent 491a44a7
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+60 −15
Original line number Diff line number Diff line
@@ -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,
		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;
}
+45 −0
Original line number Diff line number Diff line
@@ -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)
+13 −0
Original line number Diff line number Diff line
@@ -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)