diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 6988601ab..54b331b68 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -560,7 +560,6 @@ Example response: "id": 1, "result": { "tick_rate": 2400000000, - "ticks": 2523538189523655, "threads": [ { "name": "app_thread", @@ -616,6 +615,54 @@ Example response: } ~~~ +## thread_get_pollers {#rpc_thread_get_pollers} + +Retrieve current pollers of all the threads. + +### Parameters + +This method has no parameters. + +### Response + +The response is an array of objects containing pollers of all the threads. + +### Example + +Example request: +~~~ +{ + "jsonrpc": "2.0", + "method": "thread_get_pollers", + "id": 1 +} +~~~ + +Example response: +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "tick_rate": 2500000000, + "threads": [ + { + "name": "app_thread", + "active_pollers": [], + "timed_pollers": [ + { + "name": "spdk_rpc_subsystem_poll", + "state": "waiting", + "period_ticks": 10000000 + } + ], + "paused_pollers": [] + } + ] + } +} +~~~ + # Block Device Abstraction Layer {#jsonrpc_components_bdev} ## bdev_set_options {#rpc_bdev_set_options} diff --git a/include/spdk_internal/thread.h b/include/spdk_internal/thread.h index 99dc03525..d4bf64bc5 100644 --- a/include/spdk_internal/thread.h +++ b/include/spdk_internal/thread.h @@ -111,4 +111,6 @@ struct spdk_thread { uint8_t ctx[0]; }; +const char *spdk_poller_state_str(enum spdk_poller_state state); + #endif /* SPDK_THREAD_INTERNAL_H_ */ diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 5ef3858a1..80ccf1c8f 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -993,6 +993,25 @@ spdk_poller_resume(struct spdk_poller *poller) poller->state = SPDK_POLLER_STATE_WAITING; } +const char * +spdk_poller_state_str(enum spdk_poller_state state) +{ + switch (state) { + case SPDK_POLLER_STATE_WAITING: + return "waiting"; + case SPDK_POLLER_STATE_RUNNING: + return "running"; + case SPDK_POLLER_STATE_UNREGISTERED: + return "unregistered"; + case SPDK_POLLER_STATE_PAUSING: + return "pausing"; + case SPDK_POLLER_STATE_PAUSED: + return "paused"; + default: + return NULL; + } +} + struct call_thread { struct spdk_thread *cur_thread; spdk_msg_fn fn; diff --git a/module/event/rpc/app_rpc.c b/module/event/rpc/app_rpc.c index 531d21618..3e25aaa62 100644 --- a/module/event/rpc/app_rpc.c +++ b/module/event/rpc/app_rpc.c @@ -42,6 +42,7 @@ #include "spdk_internal/log.h" #include "spdk_internal/event.h" +#include "spdk_internal/thread.h" struct rpc_spdk_kill_instance { char *sig_name; @@ -170,6 +171,27 @@ rpc_thread_get_stats_done(void *arg) free(ctx); } +static void +rpc_thread_get_stats_for_each(struct spdk_jsonrpc_request *request, spdk_msg_fn fn) +{ + struct rpc_get_stats_ctx *ctx; + + 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_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); + spdk_json_write_named_array_begin(ctx->w, "threads"); + + spdk_for_each_thread(fn, ctx, rpc_thread_get_stats_done); +} + static void rpc_thread_get_stats(void *arg) { @@ -193,32 +215,75 @@ static void spdk_rpc_thread_get_stats(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, "'thread_get_stats' 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_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz()); - spdk_json_write_named_array_begin(ctx->w, "threads"); - - spdk_for_each_thread(rpc_thread_get_stats, ctx, rpc_thread_get_stats_done); + rpc_thread_get_stats_for_each(request, rpc_thread_get_stats); } SPDK_RPC_REGISTER("thread_get_stats", spdk_rpc_thread_get_stats, SPDK_RPC_RUNTIME) +static void +rpc_get_poller(struct spdk_poller *poller, struct spdk_json_write_ctx *w) +{ + spdk_json_write_object_begin(w); + spdk_json_write_named_string(w, "name", poller->name); + spdk_json_write_named_string(w, "state", spdk_poller_state_str(poller->state)); + if (poller->period_ticks) { + spdk_json_write_named_uint64(w, "period_ticks", poller->period_ticks); + } + spdk_json_write_object_end(w); +} + +static void +rpc_thread_get_pollers(void *arg) +{ + struct rpc_get_stats_ctx *ctx = arg; + struct spdk_thread *thread = spdk_get_thread(); + struct spdk_poller *poller; + + spdk_json_write_object_begin(ctx->w); + spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(thread)); + + spdk_json_write_named_array_begin(ctx->w, "active_pollers"); + TAILQ_FOREACH(poller, &thread->active_pollers, tailq) { + rpc_get_poller(poller, ctx->w); + } + spdk_json_write_array_end(ctx->w); + + spdk_json_write_named_array_begin(ctx->w, "timed_pollers"); + TAILQ_FOREACH(poller, &thread->timed_pollers, tailq) { + rpc_get_poller(poller, ctx->w); + } + spdk_json_write_array_end(ctx->w); + + spdk_json_write_named_array_begin(ctx->w, "paused_pollers"); + TAILQ_FOREACH(poller, &thread->paused_pollers, tailq) { + rpc_get_poller(poller, ctx->w); + } + spdk_json_write_array_end(ctx->w); + + spdk_json_write_object_end(ctx->w); +} + +static void +spdk_rpc_thread_get_pollers(struct spdk_jsonrpc_request *request, + const struct spdk_json_val *params) +{ + if (params) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, + "'thread_get_pollers' requires no arguments"); + return; + } + + rpc_thread_get_stats_for_each(request, rpc_thread_get_pollers); +} + +SPDK_RPC_REGISTER("thread_get_pollers", spdk_rpc_thread_get_pollers, SPDK_RPC_RUNTIME) + static void rpc_framework_get_reactors_done(void *arg1, void *arg2) { diff --git a/scripts/rpc.py b/scripts/rpc.py index ea8bcf180..18b5dbcdf 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2283,6 +2283,13 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-m', '--cpumask', help='cpumask for this thread') p.set_defaults(func=thread_set_cpumask) + def thread_get_pollers(args): + print_dict(rpc.app.thread_get_pollers(args.client)) + + p = subparsers.add_parser( + 'thread_get_pollers', help='Display current pollers of all the threads') + p.set_defaults(func=thread_get_pollers) + def env_dpdk_get_mem_stats(args): print_dict(rpc.env_dpdk.env_dpdk_get_mem_stats(args.client)) diff --git a/scripts/rpc/app.py b/scripts/rpc/app.py index 570422f89..64b21322b 100644 --- a/scripts/rpc/app.py +++ b/scripts/rpc/app.py @@ -58,3 +58,12 @@ def thread_set_cpumask(client, id, cpumask): """ params = {'id': id, 'cpumask': cpumask} return client.call('thread_set_cpumask', params) + + +def thread_get_pollers(client): + """Query current pollers. + + Returns: + Current pollers. + """ + return client.call('thread_get_pollers')