OCF: rpc: add stats method

Add get_ocf_stats rpc method that
  returns available OCF statistics for specific OCF bdev

Change-Id: If043a18c847fbeeddd8fdde1af9397e24bd90718
Signed-off-by: Vitaliy Mysak <vitaliy.mysak@intel.com>
Reviewed-on: https://review.gerrithub.io/c/438411
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
This commit is contained in:
Vitaliy Mysak 2018-12-28 18:59:40 +00:00 committed by Jim Harris
parent 9f792ca0dc
commit 27e0190b84
7 changed files with 471 additions and 0 deletions

View File

@ -872,6 +872,210 @@ Example response:
}
~~~
## get_ocf_stats {#rpc_get_ocf_stats}
Get statistics of chosen OCF block device.
### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
name | Required | string | Block device name
### Response
Statistics as json object.
### Example
Example request:
~~~
{
"jsonrpc": "2.0",
"method": "get_ocf_stats",
"id": 1
}
~~~
Example response:
~~~
{
"jsonrpc": "2.0",
"id": 1,
"result": [
"usage": {
"clean": {
"count": 76033,
"units": "4KiB blocks",
"percentage": "100.0"
},
"free": {
"count": 767,
"units": "4KiB blocks",
"percentage": "0.9"
},
"occupancy": {
"count": 76033,
"units": "4KiB blocks",
"percentage": "99.0"
},
"dirty": {
"count": 0,
"units": "4KiB blocks",
"percentage": "0.0"
}
},
"requests": {
"rd_total": {
"count": 2,
"units": "Requests",
"percentage": "0.0"
},
"wr_full_misses": {
"count": 76280,
"units": "Requests",
"percentage": "35.6"
},
"rd_full_misses": {
"count": 1,
"units": "Requests",
"percentage": "0.0"
},
"rd_partial_misses": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"wr_total": {
"count": 212416,
"units": "Requests",
"percentage": "99.2"
},
"wr_pt": {
"count": 1535,
"units": "Requests",
"percentage": "0.7"
},
"wr_partial_misses": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"serviced": {
"count": 212418,
"units": "Requests",
"percentage": "99.2"
},
"rd_pt": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"total": {
"count": 213953,
"units": "Requests",
"percentage": "100.0"
},
"rd_hits": {
"count": 1,
"units": "Requests",
"percentage": "0.0"
},
"wr_hits": {
"count": 136136,
"units": "Requests",
"percentage": "63.6"
}
},
"errors": {
"total": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"cache_obj_total": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"core_obj_total": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"cache_obj_rd": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"core_obj_wr": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"core_obj_rd": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
},
"cache_obj_wr": {
"count": 0,
"units": "Requests",
"percentage": "0.0"
}
},
"blocks": {
"volume_rd": {
"count": 9,
"units": "4KiB blocks",
"percentage": "0.0"
},
"volume_wr": {
"count": 213951,
"units": "4KiB blocks",
"percentage": "99.9"
},
"cache_obj_total": {
"count": 212425,
"units": "4KiB blocks",
"percentage": "100.0"
},
"core_obj_total": {
"count": 213959,
"units": "4KiB blocks",
"percentage": "100.0"
},
"cache_obj_rd": {
"count": 1,
"units": "4KiB blocks",
"percentage": "0.0"
},
"core_obj_wr": {
"count": 213951,
"units": "4KiB blocks",
"percentage": "99.9"
},
"volume_total": {
"count": 213960,
"units": "4KiB blocks",
"percentage": "100.0"
},
"core_obj_rd": {
"count": 8,
"units": "4KiB blocks",
"percentage": "0.0"
},
"cache_obj_wr": {
"count": 212424,
"units": "4KiB blocks",
"percentage": "99.9"
}
]
}
~~~
## construct_malloc_bdev {#rpc_construct_malloc_bdev}
Construct @ref bdev_config_malloc

126
lib/bdev/ocf/stats.c Normal file
View File

@ -0,0 +1,126 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ctx.h"
#include "stats.h"
int
vbdev_ocf_stats_get(int cache_id, int core_id, struct vbdev_ocf_stats *stats)
{
int status;
struct ocf_stats_core core_stats;
ocf_cache_t cache;
ocf_core_t core;
status = ocf_mngt_cache_get(vbdev_ocf_ctx, cache_id, &cache);
if (status) {
return status;
}
status = ocf_core_get(cache, 0, &core);
if (status) {
return status;
}
status = ocf_core_get_stats(core, &core_stats);
if (status) {
return status;
}
status = ocf_stats_collect_core(core, &stats->usage, &stats->reqs, &stats->blocks, &stats->errors);
if (status) {
return status;
}
return 0;
}
#define WJSON_STAT(w, stats, group, field, units) \
spdk_json_write_named_object_begin(w, #field); \
spdk_json_write_named_uint64(w, "count", stats->group.field.value); \
spdk_json_write_named_string_fmt(w, "percentage", "%lu.%lu", \
stats->group.field.percent / 10, stats->group.field.percent % 10); \
spdk_json_write_named_string(w, "units", units); \
spdk_json_write_object_end(w);
void
vbdev_ocf_stats_write_json(struct spdk_json_write_ctx *w, struct vbdev_ocf_stats *stats)
{
spdk_json_write_object_begin(w);
spdk_json_write_named_object_begin(w, "usage");
WJSON_STAT(w, stats, usage, occupancy, "4KiB blocks");
WJSON_STAT(w, stats, usage, free, "4KiB blocks");
WJSON_STAT(w, stats, usage, clean, "4KiB blocks");
WJSON_STAT(w, stats, usage, dirty, "4KiB blocks");
spdk_json_write_object_end(w);
spdk_json_write_named_object_begin(w, "requests");
WJSON_STAT(w, stats, reqs, rd_hits, "Requests");
WJSON_STAT(w, stats, reqs, rd_partial_misses, "Requests");
WJSON_STAT(w, stats, reqs, rd_full_misses, "Requests");
WJSON_STAT(w, stats, reqs, rd_total, "Requests");
WJSON_STAT(w, stats, reqs, wr_hits, "Requests");
WJSON_STAT(w, stats, reqs, wr_partial_misses, "Requests");
WJSON_STAT(w, stats, reqs, wr_full_misses, "Requests");
WJSON_STAT(w, stats, reqs, wr_total, "Requests");
WJSON_STAT(w, stats, reqs, rd_pt, "Requests");
WJSON_STAT(w, stats, reqs, wr_pt, "Requests");
WJSON_STAT(w, stats, reqs, serviced, "Requests");
WJSON_STAT(w, stats, reqs, total, "Requests");
spdk_json_write_object_end(w);
spdk_json_write_named_object_begin(w, "blocks");
WJSON_STAT(w, stats, blocks, core_obj_rd, "4KiB blocks");
WJSON_STAT(w, stats, blocks, core_obj_wr, "4KiB blocks");
WJSON_STAT(w, stats, blocks, core_obj_total, "4KiB blocks");
WJSON_STAT(w, stats, blocks, cache_obj_rd, "4KiB blocks");
WJSON_STAT(w, stats, blocks, cache_obj_wr, "4KiB blocks");
WJSON_STAT(w, stats, blocks, cache_obj_total, "4KiB blocks");
WJSON_STAT(w, stats, blocks, volume_rd, "4KiB blocks");
WJSON_STAT(w, stats, blocks, volume_wr, "4KiB blocks");
WJSON_STAT(w, stats, blocks, volume_total, "4KiB blocks");
spdk_json_write_object_end(w);
spdk_json_write_named_object_begin(w, "errors");
WJSON_STAT(w, stats, errors, core_obj_rd, "Requests");
WJSON_STAT(w, stats, errors, core_obj_wr, "Requests");
WJSON_STAT(w, stats, errors, core_obj_total, "Requests");
WJSON_STAT(w, stats, errors, cache_obj_rd, "Requests");
WJSON_STAT(w, stats, errors, cache_obj_wr, "Requests");
WJSON_STAT(w, stats, errors, cache_obj_total, "Requests");
WJSON_STAT(w, stats, errors, total, "Requests");
spdk_json_write_object_end(w);
spdk_json_write_object_end(w);
}

51
lib/bdev/ocf/stats.h Normal file
View File

@ -0,0 +1,51 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VBDEV_OCF_STATS_H
#define VBDEV_OCF_STATS_H
#include "spdk/json.h"
#include <ocf/ocf.h>
struct vbdev_ocf_stats {
struct ocf_stats_usage usage;
struct ocf_stats_requests reqs;
struct ocf_stats_blocks blocks;
struct ocf_stats_errors errors;
};
int vbdev_ocf_stats_get(int cache_id, int core_id, struct vbdev_ocf_stats *stats);
void vbdev_ocf_stats_write_json(struct spdk_json_write_ctx *w, struct vbdev_ocf_stats *stats);
#endif

View File

@ -32,6 +32,7 @@
*/
#include "vbdev_ocf.h"
#include "stats.h"
#include "spdk/log.h"
#include "spdk/rpc.h"
#include "spdk/string.h"
@ -158,3 +159,62 @@ end:
free_rpc_delete_ocf_bdev(&req);
}
SPDK_RPC_REGISTER("delete_ocf_bdev", spdk_rpc_delete_ocf_bdev, SPDK_RPC_RUNTIME)
/* Structure to hold the parameters for this RPC method. */
struct rpc_get_ocf_stats {
char *name; /* master vbdev name */
};
static void
free_rpc_get_ocf_stats(struct rpc_get_ocf_stats *r)
{
free(r->name);
}
/* Structure to decode the input parameters for this RPC method. */
static const struct spdk_json_object_decoder rpc_get_ocf_stats_decoders[] = {
{"name", offsetof(struct rpc_get_ocf_stats, name), spdk_json_decode_string},
};
static void
spdk_rpc_get_ocf_stats(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
{
struct rpc_get_ocf_stats req = {NULL};
struct spdk_json_write_ctx *w;
struct vbdev_ocf *vbdev;
struct vbdev_ocf_stats stats;
int status;
if (spdk_json_decode_object(params, rpc_get_ocf_stats_decoders,
SPDK_COUNTOF(rpc_get_ocf_stats_decoders),
&req)) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
"Invalid parameters");
goto end;
}
vbdev = vbdev_ocf_get_by_name(req.name);
if (vbdev == NULL) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
spdk_strerror(ENODEV));
goto end;
}
status = vbdev_ocf_stats_get(vbdev->cache.id, vbdev->core.id, &stats);
if (status) {
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
"Could not get stats: %s",
spdk_strerror(-status));
goto end;
}
w = spdk_jsonrpc_begin_result(request);
if (w) {
vbdev_ocf_stats_write_json(w, &stats);
spdk_jsonrpc_end_result(request, w);
}
end:
free_rpc_get_ocf_stats(&req);
}
SPDK_RPC_REGISTER("get_ocf_stats", spdk_rpc_get_ocf_stats, SPDK_RPC_RUNTIME)

View File

@ -167,6 +167,14 @@ if __name__ == "__main__":
p.add_argument('name', help='Name of OCF bdev')
p.set_defaults(func=delete_ocf_bdev)
def get_ocf_stats(args):
print_dict(rpc.bdev.get_ocf_stats(args.client,
name=args.name))
p = subparsers.add_parser('get_ocf_stats',
help='Get statistics of chosen OCF block device')
p.add_argument('name', help='Name of OCF bdev')
p.set_defaults(func=get_ocf_stats)
def construct_malloc_bdev(args):
num_blocks = (args.total_size * 1024 * 1024) // args.block_size
print(rpc.bdev.construct_malloc_bdev(args.client,

View File

@ -71,6 +71,20 @@ def delete_ocf_bdev(client, name):
return client.call('delete_ocf_bdev', params)
def get_ocf_stats(client, name):
"""Get statistics of chosen OCF block device
Args:
name: name of OCF bdev
Returns:
Statistics as json object
"""
params = {'name': name}
return client.call('get_ocf_stats', params)
def construct_malloc_bdev(client, num_blocks, block_size, name=None, uuid=None):
"""Construct a malloc block device.

View File

@ -5,6 +5,14 @@ rootdir=$(readlink -f $curdir/../../..)
source $rootdir/test/common/autotest_common.sh
bdevperf=$rootdir/test/bdev/bdevperf/bdevperf
rpc_py="python $rootdir/scripts/rpc.py"
$bdevperf -c $curdir/mallocs.conf -q 128 -o 4096 -t 4 -w flush
$bdevperf -c $curdir/mallocs.conf -q 128 -o 4096 -t 4 -w unmap
$bdevperf -c $curdir/mallocs.conf -q 128 -o 4096 -t 4 -w write -r /var/tmp/spdk.sock &
bdev_perf_pid=$!
waitforlisten $bdev_perf_pid
sleep 1
$rpc_py get_ocf_stats MalCache1
wait $bdev_perf_pid