From 7535cdbd622ca23282ed02d9d8f07a8a69a76177 Mon Sep 17 00:00:00 2001 From: Evgeniy Kochetov Date: Sat, 2 Mar 2019 08:32:19 +0000 Subject: [PATCH] rpc: Add thread_get_stats RPC method SPDK threads collect busy and idle time statistics. This commit adds thread_get_stats RPC method to retrieve these values. Signed-off-by: Evgeniy Kochetov Change-Id: I8ed8041c6164eb0c0a9336f4e50b5f26a3f20190 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/445285 Tested-by: SPDK CI Jenkins Reviewed-by: Shuhei Matsumoto Reviewed-by: Seth Howell Reviewed-by: Darek Stojaczyk Reviewed-by: Ben Walker Reviewed-by: Paul Luse --- CHANGELOG.md | 4 +++ doc/jsonrpc.md | 41 +++++++++++++++++++++++ lib/event/rpc/app_rpc.c | 72 +++++++++++++++++++++++++++++++++++++++-- scripts/rpc.py | 7 ++++ scripts/rpc/app.py | 9 ++++++ 5 files changed, 131 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43d5e2350..02c018dce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,10 @@ sock groups. This API is intended to provide the user with that information. spdk_sock_group_get_ctx() was added to return the context of the spdk_sock_group. spdk_sock_group_create() is updated to allow input the user provided ctx. +### rpc + +Added thread_get_stats RPC method to retrieve existing statistics. + ## v19.04: ### nvme diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index 56e0a8f3e..8cea5cbed 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -484,6 +484,47 @@ Example response: } ~~~ +## thread_get_stats {#rpc_thread_get_stats} + +Retrieve current statistics of all the threads. + +### Parameters + +This method has no parameters. + +### Response + +The response is an array of objects containing threads statistics. + +### Example + +Example request: +~~~ +{ + "jsonrpc": "2.0", + "method": "thread_get_stats", + "id": 1 +} +~~~ + +Example response: +~~~ +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "tick_rate": 2400000000, + "threads": [ + { + "name": "reactor_0", + "busy": 139223208, + "idle": 8641080608 + } + ] + } +} +~~~ + # Block Device Abstraction Layer {#jsonrpc_components_bdev} ## set_bdev_options {#rpc_set_bdev_options} diff --git a/lib/event/rpc/app_rpc.c b/lib/event/rpc/app_rpc.c index 6f663f130..d98c13d3c 100644 --- a/lib/event/rpc/app_rpc.c +++ b/lib/event/rpc/app_rpc.c @@ -1,8 +1,8 @@ /*- * BSD LICENSE * - * Copyright (c) Intel Corporation. - * All rights reserved. + * Copyright (c) Intel Corporation. All rights reserved. + * Copyright (c) 2019 Mellanox Technologies LTD. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,6 +37,8 @@ #include "spdk/rpc.h" #include "spdk/string.h" #include "spdk/util.h" +#include "spdk/env.h" +#include "spdk/thread.h" #include "spdk_internal/log.h" @@ -153,3 +155,69 @@ spdk_rpc_context_switch_monitor(struct spdk_jsonrpc_request *request, } SPDK_RPC_REGISTER("context_switch_monitor", spdk_rpc_context_switch_monitor, SPDK_RPC_RUNTIME) + +struct rpc_thread_get_stats_ctx { + struct spdk_jsonrpc_request *request; + struct spdk_json_write_ctx *w; +}; + +static void +rpc_thread_get_stats_done(void *arg) +{ + struct rpc_thread_get_stats_ctx *ctx = arg; + + 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_thread_get_stats(void *arg) +{ + struct rpc_thread_get_stats_ctx *ctx = arg; + struct spdk_thread_stats stats; + + if (0 == spdk_thread_get_stats(&stats)) { + spdk_json_write_object_begin(ctx->w); + spdk_json_write_named_string(ctx->w, "name", spdk_thread_get_name(spdk_get_thread())); + spdk_json_write_named_uint64(ctx->w, "busy", stats.busy_tsc); + spdk_json_write_named_uint64(ctx->w, "idle", stats.idle_tsc); + spdk_json_write_object_end(ctx->w); + } +} + +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; + + 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); + if (NULL == ctx->w) { + free(ctx); + return; + } + 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); +} + +SPDK_RPC_REGISTER("thread_get_stats", spdk_rpc_thread_get_stats, SPDK_RPC_RUNTIME) diff --git a/scripts/rpc.py b/scripts/rpc.py index 1f2bce21d..d882ef658 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -1813,6 +1813,13 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-n', '--max', help="""Maximum number of notifications to return in response""", type=int) p.set_defaults(func=get_notifications) + def thread_get_stats(args): + print_dict(rpc.app.thread_get_stats(args.client)) + + p = subparsers.add_parser( + 'thread_get_stats', help='Display current statistics of all the threads') + p.set_defaults(func=thread_get_stats) + def check_called_name(name): if name in deprecated_aliases: print("{} is deprecated, use {} instead.".format(name, deprecated_aliases[name]), file=sys.stderr) diff --git a/scripts/rpc/app.py b/scripts/rpc/app.py index c9b088f83..9e8a0fc87 100644 --- a/scripts/rpc/app.py +++ b/scripts/rpc/app.py @@ -21,3 +21,12 @@ def context_switch_monitor(client, enabled=None): if enabled is not None: params['enabled'] = enabled return client.call('context_switch_monitor', params) + + +def thread_get_stats(client): + """Query threads statistics. + + Returns: + Current threads statistics. + """ + return client.call('thread_get_stats')