histograms: add rpc calls
This patch adds RPC calls for histograms in bdev layer. Following calls are added: - enable_bdev_histogram - enable/disable histogram structures for specified bdev and each of its channels. - get_bdev_histogram - merges histograms from all channnels and encodes histogram as base64 Signed-off-by: Piotr Pelplinski <piotr.pelplinski@intel.com> Change-Id: Ib423a919dc1cde7dd7d92247db5482cfb9d66956 Reviewed-on: https://review.gerrithub.io/c/433573 Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Maciej Szwed <maciej.szwed@intel.com> Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com> Reviewed-by: wuzhouhui <wuzhouhui@kingsoft.com> Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com> Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
8f0d7e57fa
commit
e5e427c94b
@ -632,6 +632,88 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
## enable_bdev_histogram {#rpc_enable_bdev_histogram}
|
||||
|
||||
Control whether collecting data for histogram is enabled for specified bdev.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | Block device name
|
||||
enable | Required | boolean | Enable or disable histogram on specified device
|
||||
|
||||
### Example
|
||||
|
||||
Example request:
|
||||
~~~
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "enable_bdev_histogram",
|
||||
"params": {
|
||||
"name": "Nvme0n1"
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
~~~
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
## get_bdev_histogram {#rpc_get_bdev_histogram}
|
||||
|
||||
Get latency histogram for specified bdev.
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
name | Required | string | Block device name
|
||||
|
||||
### Result
|
||||
|
||||
Name | Description
|
||||
------------------------| -----------
|
||||
histogram | Base64 encoded histogram
|
||||
bucket_shift | Granularity of the histogram buckets
|
||||
tsc_rate | Ticks per second
|
||||
|
||||
### Example
|
||||
|
||||
Example request:
|
||||
~~~
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "get_bdev_histogram",
|
||||
"params": {
|
||||
"name": "Nvme0n1"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
Note that histogram field is trimmed, actual encoded histogram length is ~80kb.
|
||||
|
||||
~~~
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"histogram": "AAAAAAAAAAAAAA...AAAAAAAAA==",
|
||||
"tsc_rate": 2300000000,
|
||||
"bucket_shift": 7
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
## delete_bdev {#rpc_delete_bdev}
|
||||
|
||||
Unregister a block device.
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include "spdk/rpc.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/util.h"
|
||||
#include "spdk/histogram_data.h"
|
||||
#include "spdk/base64.h"
|
||||
|
||||
#include "spdk/bdev_module.h"
|
||||
|
||||
@ -602,3 +604,179 @@ exit:
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("set_bdev_qos_limit", spdk_rpc_set_bdev_qos_limit, SPDK_RPC_RUNTIME)
|
||||
|
||||
/* SPDK_RPC_ENABLE_BDEV_HISTOGRAM */
|
||||
|
||||
struct rpc_enable_bdev_histogram_request {
|
||||
char *name;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_enable_bdev_histogram_request(struct rpc_enable_bdev_histogram_request *r)
|
||||
{
|
||||
free(r->name);
|
||||
}
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_enable_bdev_histogram_request_decoders[] = {
|
||||
{"name", offsetof(struct rpc_enable_bdev_histogram_request, name), spdk_json_decode_string},
|
||||
{"enable", offsetof(struct rpc_enable_bdev_histogram_request, enable), spdk_json_decode_bool},
|
||||
};
|
||||
|
||||
static void
|
||||
_spdk_bdev_histogram_status_cb(void *cb_arg, int status)
|
||||
{
|
||||
struct spdk_jsonrpc_request *request = cb_arg;
|
||||
struct spdk_json_write_ctx *w;
|
||||
|
||||
w = spdk_jsonrpc_begin_result(request);
|
||||
if (w == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
spdk_json_write_bool(w, status == 0);
|
||||
spdk_jsonrpc_end_result(request, w);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_rpc_enable_bdev_histogram(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_enable_bdev_histogram_request req = {NULL};
|
||||
struct spdk_bdev *bdev;
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_enable_bdev_histogram_request_decoders,
|
||||
SPDK_COUNTOF(rpc_enable_bdev_histogram_request_decoders),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
rc = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_get_by_name(req.name);
|
||||
if (bdev == NULL) {
|
||||
rc = -ENODEV;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
spdk_bdev_histogram_enable(bdev, _spdk_bdev_histogram_status_cb, request, req.enable);
|
||||
|
||||
free_rpc_enable_bdev_histogram_request(&req);
|
||||
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_enable_bdev_histogram_request(&req);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("enable_bdev_histogram", spdk_rpc_enable_bdev_histogram, SPDK_RPC_RUNTIME)
|
||||
|
||||
/* SPDK_RPC_GET_BDEV_HISTOGRAM */
|
||||
|
||||
struct rpc_get_bdev_histogram_request {
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_get_bdev_histogram_request_decoders[] = {
|
||||
{"name", offsetof(struct rpc_get_bdev_histogram_request, name), spdk_json_decode_string}
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_get_bdev_histogram_request(struct rpc_get_bdev_histogram_request *r)
|
||||
{
|
||||
free(r->name);
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_rpc_bdev_histogram_data_cb(void *cb_arg, int status, struct spdk_histogram_data *histogram)
|
||||
{
|
||||
struct spdk_jsonrpc_request *request = cb_arg;
|
||||
struct spdk_json_write_ctx *w;
|
||||
int rc;
|
||||
char *encoded_histogram;
|
||||
size_t src_len, dst_len;
|
||||
|
||||
|
||||
if (status != 0) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
||||
spdk_strerror(-status));
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
src_len = SPDK_HISTOGRAM_NUM_BUCKETS(histogram) * sizeof(uint64_t);
|
||||
dst_len = spdk_base64_get_encoded_strlen(src_len) + 1;
|
||||
|
||||
encoded_histogram = malloc(dst_len);
|
||||
if (encoded_histogram == NULL) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
||||
spdk_strerror(ENOMEM));
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rc = spdk_base64_encode(encoded_histogram, histogram->bucket, src_len);
|
||||
if (rc != 0) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
||||
spdk_strerror(-rc));
|
||||
goto free_encoded_histogram;
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(request);
|
||||
if (w == NULL) {
|
||||
goto free_encoded_histogram;
|
||||
}
|
||||
|
||||
spdk_json_write_object_begin(w);
|
||||
spdk_json_write_named_string(w, "histogram", encoded_histogram);
|
||||
spdk_json_write_named_int64(w, "bucket_shift", histogram->bucket_shift);
|
||||
spdk_json_write_named_int64(w, "tsc_rate", spdk_get_ticks_hz());
|
||||
spdk_json_write_object_end(w);
|
||||
spdk_jsonrpc_end_result(request, w);
|
||||
|
||||
free_encoded_histogram:
|
||||
free(encoded_histogram);
|
||||
invalid:
|
||||
spdk_histogram_data_free(histogram);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_rpc_get_bdev_histogram(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_get_bdev_histogram_request req = {NULL};
|
||||
struct spdk_histogram_data *histogram;
|
||||
struct spdk_bdev *bdev;
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_get_bdev_histogram_request_decoders,
|
||||
SPDK_COUNTOF(rpc_get_bdev_histogram_request_decoders),
|
||||
&req)) {
|
||||
SPDK_ERRLOG("spdk_json_decode_object failed\n");
|
||||
rc = -EINVAL;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_get_by_name(req.name);
|
||||
if (bdev == NULL) {
|
||||
rc = -ENODEV;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
histogram = spdk_histogram_data_alloc();
|
||||
if (histogram == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
spdk_bdev_histogram_get(bdev, histogram, _spdk_rpc_bdev_histogram_data_cb, request);
|
||||
|
||||
free_rpc_get_bdev_histogram_request(&req);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
free_rpc_get_bdev_histogram_request(&req);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("get_bdev_histogram", spdk_rpc_get_bdev_histogram, SPDK_RPC_RUNTIME)
|
||||
|
@ -431,6 +431,22 @@ if __name__ == "__main__":
|
||||
'bdev_name', help='Blockdev name to be deleted. Example: Malloc0.')
|
||||
p.set_defaults(func=delete_bdev)
|
||||
|
||||
def enable_bdev_histogram(args):
|
||||
rpc.bdev.enable_bdev_histogram(args.client, name=args.name, enable=args.enable)
|
||||
|
||||
p = subparsers.add_parser('enable_bdev_histogram', help='Enable or disable histogram for specified bdev')
|
||||
p.add_argument('-e', '--enable', default=True, dest='enable', action='store_true', help='Enable histograms on specified device')
|
||||
p.add_argument('-d', '--disable', dest='enable', action='store_false', help='Disable histograms on specified device')
|
||||
p.add_argument('name', help='bdev name')
|
||||
p.set_defaults(func=enable_bdev_histogram)
|
||||
|
||||
def get_bdev_histogram(args):
|
||||
print_dict(rpc.bdev.get_bdev_histogram(args.client, name=args.name))
|
||||
|
||||
p = subparsers.add_parser('get_bdev_histogram', help='Get histogram for specified bdev')
|
||||
p.add_argument('name', help='bdev name')
|
||||
p.set_defaults(func=get_bdev_histogram)
|
||||
|
||||
def set_bdev_qd_sampling_period(args):
|
||||
rpc.bdev.set_bdev_qd_sampling_period(args.client,
|
||||
name=args.name,
|
||||
|
@ -485,6 +485,26 @@ def delete_bdev(client, bdev_name):
|
||||
return client.call('delete_bdev', params)
|
||||
|
||||
|
||||
def enable_bdev_histogram(client, name, enable):
|
||||
"""Control whether histogram is enabled for specified bdev.
|
||||
|
||||
Args:
|
||||
bdev_name: name of bdev
|
||||
"""
|
||||
params = {'name': name, "enable": enable}
|
||||
return client.call('enable_bdev_histogram', params)
|
||||
|
||||
|
||||
def get_bdev_histogram(client, name):
|
||||
"""Get histogram for specified bdev.
|
||||
|
||||
Args:
|
||||
bdev_name: name of bdev
|
||||
"""
|
||||
params = {'name': name}
|
||||
return client.call('get_bdev_histogram', params)
|
||||
|
||||
|
||||
def bdev_inject_error(client, name, io_type, error_type, num=1):
|
||||
"""Inject an error via an error bdev.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user