From 876fdf2a5967e57275697d7a87e03afddbe329ce Mon Sep 17 00:00:00 2001 From: Shuhei Matsumoto Date: Tue, 17 Dec 2019 17:32:51 -0500 Subject: [PATCH] event/rpc: Add framework_get_reactors RPC Add an new RPC `framework_get_reactors` to retrieve list of all reactors. Running threads on each reactor are included in the output. Update jsonrpc.md and CHANGELOG accordingly. Signed-off-by: Shuhei Matsumoto Change-Id: I985d087dd41afe3033b7678af141ec8e5a2a822e Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/478027 Tested-by: SPDK CI Jenkins Community-CI: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Tomasz Zawadzki Reviewed-by: Alexey Marchuk --- CHANGELOG.md | 2 + doc/jsonrpc.md | 44 ++++++++++++++++++++ module/event/rpc/app_rpc.c | 82 ++++++++++++++++++++++++++++++++++++-- scripts/rpc.py | 7 ++++ scripts/rpc/app.py | 9 +++++ 5 files changed, 140 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3d6c8383..1474b7b40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ processing function. Batching is controlled by 'delay_cmd_submit' qpair option. Added optional 'delay_cmd_submit' parameter to 'bdev_nvme_set_options' RPC method. +An new RPC `framework_get_reactors` has been added to retrieve list of all reactors. + ### dpdk Updated DPDK submodule to DPDK 19.11. diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 996f2776b..30356bc8a 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -485,6 +485,50 @@ Example response: } ~~~ +## framework_get_reactors {#rpc_framework_get_reactors} + +Retrieve an array of all reactors. + +### Parameters + +This method has no parameters. + +### Response + +The response is an array of all reactors. + +### Example + +Example request: +~~~ +{ + "jsonrpc": "2.0", + "method": "framework_get_reactors", + "id": 1 +} +~~~ + +Example response: +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "reactors": [ + { + "lcore": 0, + "lw_threads": [ + { + "name": "app_thread", + "cpumask": "1" + } + ] + } + ] + } +} +~~~ + ## thread_get_stats {#rpc_thread_get_stats} Retrieve current statistics of all the threads. diff --git a/module/event/rpc/app_rpc.c b/module/event/rpc/app_rpc.c index 999ac4929..3385e63ec 100644 --- a/module/event/rpc/app_rpc.c +++ b/module/event/rpc/app_rpc.c @@ -41,6 +41,7 @@ #include "spdk/thread.h" #include "spdk_internal/log.h" +#include "spdk_internal/event.h" struct rpc_spdk_kill_instance { char *sig_name; @@ -152,7 +153,7 @@ SPDK_RPC_REGISTER("framework_monitor_context_switch", spdk_rpc_framework_monitor SPDK_RPC_RUNTIME) SPDK_RPC_REGISTER_ALIAS_DEPRECATED(framework_monitor_context_switch, context_switch_monitor) -struct rpc_thread_get_stats_ctx { +struct rpc_get_stats_ctx { struct spdk_jsonrpc_request *request; struct spdk_json_write_ctx *w; }; @@ -160,7 +161,7 @@ struct rpc_thread_get_stats_ctx { static void rpc_thread_get_stats_done(void *arg) { - struct rpc_thread_get_stats_ctx *ctx = arg; + struct rpc_get_stats_ctx *ctx = arg; spdk_json_write_array_end(ctx->w); spdk_json_write_object_end(ctx->w); @@ -172,7 +173,7 @@ rpc_thread_get_stats_done(void *arg) static void rpc_thread_get_stats(void *arg) { - struct rpc_thread_get_stats_ctx *ctx = arg; + struct rpc_get_stats_ctx *ctx = arg; struct spdk_thread *thread = spdk_get_thread(); struct spdk_thread_stats stats; @@ -191,7 +192,7 @@ static void spdk_rpc_thread_get_stats(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) { - struct rpc_thread_get_stats_ctx *ctx; + struct rpc_get_stats_ctx *ctx; if (params) { spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, @@ -216,3 +217,76 @@ spdk_rpc_thread_get_stats(struct spdk_jsonrpc_request *request, } SPDK_RPC_REGISTER("thread_get_stats", spdk_rpc_thread_get_stats, SPDK_RPC_RUNTIME) + +static void +rpc_framework_get_reactors_done(void *arg1, void *arg2) +{ + struct rpc_get_stats_ctx *ctx = arg1; + + spdk_json_write_array_end(ctx->w); + spdk_json_write_object_end(ctx->w); + spdk_jsonrpc_end_result(ctx->request, ctx->w); + + free(ctx); +} + +static void +rpc_framework_get_reactors(void *arg1, void *arg2) +{ + struct rpc_get_stats_ctx *ctx = arg1; + uint32_t current_core; + struct spdk_reactor *reactor; + struct spdk_lw_thread *lw_thread; + struct spdk_thread *thread; + + current_core = spdk_env_get_current_core(); + reactor = spdk_reactor_get(current_core); + + spdk_json_write_object_begin(ctx->w); + spdk_json_write_named_uint32(ctx->w, "lcore", current_core); + + spdk_json_write_named_array_begin(ctx->w, "lw_threads"); + TAILQ_FOREACH(lw_thread, &reactor->threads, link) { + thread = spdk_thread_get_from_ctx(lw_thread); + + spdk_json_write_object_begin(ctx->w); + spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); + spdk_json_write_named_string(ctx->w, "cpumask", + spdk_cpuset_fmt(spdk_thread_get_cpumask(thread))); + spdk_json_write_object_end(ctx->w); + } + spdk_json_write_array_end(ctx->w); + + spdk_json_write_object_end(ctx->w); +} + +static void +spdk_rpc_framework_get_reactors(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + struct rpc_get_stats_ctx *ctx; + + if (params) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "`framework_get_reactors` requires no arguments"); + return; + } + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, + "Memory allocation error"); + return; + } + + ctx->request = request; + ctx->w = spdk_jsonrpc_begin_result(ctx->request); + + spdk_json_write_object_begin(ctx->w); + spdk_json_write_named_array_begin(ctx->w, "reactors"); + + spdk_for_each_reactor(rpc_framework_get_reactors, ctx, NULL, + rpc_framework_get_reactors_done); +} + +SPDK_RPC_REGISTER("framework_get_reactors", spdk_rpc_framework_get_reactors, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index 5ac8b313a..7683d9b9a 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -135,6 +135,13 @@ if __name__ == "__main__": p.add_argument('-d', '--disable', action='store_true', help='Disable context switch monitoring') p.set_defaults(func=framework_monitor_context_switch) + def framework_get_reactors(args): + print_dict(rpc.app.framework_get_reactors(args.client)) + + p = subparsers.add_parser( + 'framework_get_reactors', help='Display list of all reactors') + p.set_defaults(func=framework_get_reactors) + # bdev def bdev_set_options(args): rpc.bdev.bdev_set_options(args.client, diff --git a/scripts/rpc/app.py b/scripts/rpc/app.py index 4fc3a9ff4..531015782 100644 --- a/scripts/rpc/app.py +++ b/scripts/rpc/app.py @@ -28,6 +28,15 @@ def framework_monitor_context_switch(client, enabled=None): return client.call('framework_monitor_context_switch', params) +def framework_get_reactors(client): + """Query list of all reactors. + + Returns: + List of all reactors. + """ + return client.call('framework_get_reactors') + + def thread_get_stats(client): """Query threads statistics.