From 0f81ba102b5b73f288955c28d15b7ccc6acb288c Mon Sep 17 00:00:00 2001 From: Konrad Sztyber Date: Tue, 28 Feb 2023 07:58:27 +0100 Subject: [PATCH] accel: add accel_get_stats The RPC allows the user to retrieve accel framework's statistics. Signed-off-by: Konrad Sztyber Change-Id: I5cd1b45686504c08eda50513ad1dae2f8d65013b Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17191 Community-CI: Mellanox Build Bot Reviewed-by: Shuhei Matsumoto Reviewed-by: Jim Harris Tested-by: SPDK CI Jenkins --- doc/jsonrpc.md | 51 ++++++++++++++++++++++++++++++++++++ lib/accel/accel.c | 53 ++++++++++++++++++++++++++++++++++++++ lib/accel/accel_internal.h | 2 ++ lib/accel/accel_rpc.c | 43 +++++++++++++++++++++++++++++++ python/spdk/rpc/accel.py | 6 +++++ scripts/rpc.py | 6 +++++ 6 files changed, 161 insertions(+) diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index bcb12f8c7..40a2ecbba 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -1981,6 +1981,57 @@ Example response: } ~~~ +### accel_get_stats {#rpc_accel_get_stats} + +Retrieve accel framework's statistics. Statistics for opcodes that have never been executed (i.e. +all their stats are at 0) aren't included in the `operations` array. + +#### Parameters + +None. + +#### Example + +Example request: + +~~~json +{ + "jsonrpc": "2.0", + "method": "accel_get_stats", + "id": 1 +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "sequence_executed": 256, + "sequence_failed": 0, + "operations": [ + { + "opcode": "copy", + "executed": 256, + "failed": 0 + }, + { + "opcode": "encrypt", + "executed": 128, + "failed": 0 + }, + { + "opcode": "decrypt", + "executed": 128, + "failed": 0 + } + ] + } +} +~~~ + ### compressdev_scan_accel_module {#rpc_compressdev_scan_accel_module} Set config and enable compressdev accel module offload. diff --git a/lib/accel/accel.c b/lib/accel/accel.c index df87d15d4..ccc40cab3 100644 --- a/lib/accel/accel.c +++ b/lib/accel/accel.c @@ -2520,4 +2520,57 @@ spdk_accel_get_opts(struct spdk_accel_opts *opts) opts->size = size; } +struct accel_get_stats_ctx { + struct accel_stats stats; + accel_get_stats_cb cb_fn; + void *cb_arg; +}; + +static void +accel_get_channel_stats_done(struct spdk_io_channel_iter *iter, int status) +{ + struct accel_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter); + + ctx->cb_fn(&ctx->stats, ctx->cb_arg); + free(ctx); +} + +static void +accel_get_channel_stats(struct spdk_io_channel_iter *iter) +{ + struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter); + struct accel_io_channel *accel_ch = spdk_io_channel_get_ctx(ch); + struct accel_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter); + struct accel_stats *stats = &ctx->stats; + int i; + + stats->sequence_executed += accel_ch->stats.sequence_executed; + stats->sequence_failed += accel_ch->stats.sequence_failed; + for (i = 0; i < ACCEL_OPC_LAST; ++i) { + stats->operations[i].executed += accel_ch->stats.operations[i].executed; + stats->operations[i].failed += accel_ch->stats.operations[i].failed; + } + + spdk_for_each_channel_continue(iter, 0); +} + +int +accel_get_stats(accel_get_stats_cb cb_fn, void *cb_arg) +{ + struct accel_get_stats_ctx *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + return -ENOMEM; + } + + ctx->cb_fn = cb_fn; + ctx->cb_arg = cb_arg; + + spdk_for_each_channel(&spdk_accel_module_list, accel_get_channel_stats, ctx, + accel_get_channel_stats_done); + + return 0; +} + SPDK_LOG_REGISTER_COMPONENT(accel) diff --git a/lib/accel/accel_internal.h b/lib/accel/accel_internal.h index 7bebe677d..9908cc38d 100644 --- a/lib/accel/accel_internal.h +++ b/lib/accel/accel_internal.h @@ -36,5 +36,7 @@ void _accel_for_each_module(struct module_info *info, _accel_for_each_module_fn int _accel_get_opc_name(enum accel_opcode opcode, const char **opcode_name); void _accel_crypto_key_dump_param(struct spdk_json_write_ctx *w, struct spdk_accel_crypto_key *key); void _accel_crypto_keys_dump_param(struct spdk_json_write_ctx *w); +typedef void (*accel_get_stats_cb)(struct accel_stats *stats, void *cb_arg); +int accel_get_stats(accel_get_stats_cb cb_fn, void *cb_arg); #endif diff --git a/lib/accel/accel_rpc.c b/lib/accel/accel_rpc.c index 64ad47be8..764f90506 100644 --- a/lib/accel/accel_rpc.c +++ b/lib/accel/accel_rpc.c @@ -397,3 +397,46 @@ rpc_accel_set_options(struct spdk_jsonrpc_request *request, const struct spdk_js spdk_jsonrpc_send_bool_response(request, true); } SPDK_RPC_REGISTER("accel_set_options", rpc_accel_set_options, SPDK_RPC_STARTUP) + +static void +rpc_accel_get_stats_done(struct accel_stats *stats, void *cb_arg) +{ + struct spdk_jsonrpc_request *request = cb_arg; + struct spdk_json_write_ctx *w; + const char *name; + int i; + + w = spdk_jsonrpc_begin_result(request); + spdk_json_write_object_begin(w); + + spdk_json_write_named_uint64(w, "sequence_executed", stats->sequence_executed); + spdk_json_write_named_uint64(w, "sequence_failed", stats->sequence_failed); + spdk_json_write_named_array_begin(w, "operations"); + for (i = 0; i < ACCEL_OPC_LAST; ++i) { + if (stats->operations[i].executed + stats->operations[i].failed == 0) { + continue; + } + _accel_get_opc_name(i, &name); + spdk_json_write_object_begin(w); + spdk_json_write_named_string(w, "opcode", name); + spdk_json_write_named_uint64(w, "executed", stats->operations[i].executed); + spdk_json_write_named_uint64(w, "failed", stats->operations[i].failed); + spdk_json_write_object_end(w); + } + spdk_json_write_array_end(w); + + spdk_json_write_object_end(w); + spdk_jsonrpc_end_result(request, w); +} + +static void +rpc_accel_get_stats(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + int rc; + + rc = accel_get_stats(rpc_accel_get_stats_done, request); + if (rc != 0) { + spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); + } +} +SPDK_RPC_REGISTER("accel_get_stats", rpc_accel_get_stats, SPDK_RPC_RUNTIME) diff --git a/python/spdk/rpc/accel.py b/python/spdk/rpc/accel.py index 7a9690524..98c2152a9 100644 --- a/python/spdk/rpc/accel.py +++ b/python/spdk/rpc/accel.py @@ -100,3 +100,9 @@ def accel_set_options(client, small_cache_size, large_cache_size): params['large_cache_size'] = large_cache_size return client.call('accel_set_options', params) + + +def accel_get_stats(client): + """Get accel framework's statistics""" + + return client.call('accel_get_stats') diff --git a/scripts/rpc.py b/scripts/rpc.py index b077075d0..4cd26c755 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2874,6 +2874,12 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('--large-cache-size', type=int, help='Size of the large iobuf cache') p.set_defaults(func=accel_set_options) + def accel_get_stats(args): + print_dict(rpc.accel.accel_get_stats(args.client)) + + p = subparsers.add_parser('accel_get_stats', help='Display accel framework\'s statistics') + p.set_defaults(func=accel_get_stats) + # ioat def ioat_scan_accel_module(args): rpc.ioat.ioat_scan_accel_module(args.client)