ocf/src/ocf_stats_builder.c
Adam Rutkowski 9a1f9d41b8 Return error from stats API functions in standby
Signed-off-by: Adam Rutkowski <adam.j.rutkowski@intel.com>
2022-03-29 22:20:04 +02:00

459 lines
12 KiB
C

/*
* Copyright(c) 2012-2021 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "ocf/ocf.h"
#include "ocf_priv.h"
#include "metadata/metadata.h"
#include "engine/cache_engine.h"
#include "utils/utils_user_part.h"
#include "utils/utils_cache_line.h"
#include "utils/utils_stats.h"
static void _fill_req(struct ocf_stats_requests *req, struct ocf_stats_core *s)
{
uint64_t serviced = s->read_reqs.total + s->write_reqs.total;
uint64_t total = serviced + s->read_reqs.pass_through +
s->write_reqs.pass_through;
uint64_t hit;
/* Reads Section */
hit = s->read_reqs.total - (s->read_reqs.full_miss +
s->read_reqs.partial_miss);
_set(&req->rd_hits, hit, total);
_set(&req->rd_partial_misses, s->read_reqs.partial_miss, total);
_set(&req->rd_full_misses, s->read_reqs.full_miss, total);
_set(&req->rd_total, s->read_reqs.total, total);
/* Write Section */
hit = s->write_reqs.total - (s->write_reqs.full_miss +
s->write_reqs.partial_miss);
_set(&req->wr_hits, hit, total);
_set(&req->wr_partial_misses, s->write_reqs.partial_miss, total);
_set(&req->wr_full_misses, s->write_reqs.full_miss, total);
_set(&req->wr_total, s->write_reqs.total, total);
/* Pass-Through section */
_set(&req->rd_pt, s->read_reqs.pass_through, total);
_set(&req->wr_pt, s->write_reqs.pass_through, total);
/* Summary */
_set(&req->serviced, serviced, total);
_set(&req->total, total, total);
}
static void _fill_req_part(struct ocf_stats_requests *req,
struct ocf_stats_io_class *s)
{
uint64_t serviced = s->read_reqs.total + s->write_reqs.total;
uint64_t total = serviced + s->read_reqs.pass_through +
s->write_reqs.pass_through;
uint64_t hit;
/* Reads Section */
hit = s->read_reqs.total - (s->read_reqs.full_miss +
s->read_reqs.partial_miss);
_set(&req->rd_hits, hit, total);
_set(&req->rd_partial_misses, s->read_reqs.partial_miss, total);
_set(&req->rd_full_misses, s->read_reqs.full_miss, total);
_set(&req->rd_total, s->read_reqs.total, total);
/* Write Section */
hit = s->write_reqs.total - (s->write_reqs.full_miss +
s->write_reqs.partial_miss);
_set(&req->wr_hits, hit, total);
_set(&req->wr_partial_misses, s->write_reqs.partial_miss, total);
_set(&req->wr_full_misses, s->write_reqs.full_miss, total);
_set(&req->wr_total, s->write_reqs.total, total);
/* Pass-Through section */
_set(&req->rd_pt, s->read_reqs.pass_through, total);
_set(&req->wr_pt, s->write_reqs.pass_through, total);
/* Summary */
_set(&req->serviced, serviced, total);
_set(&req->total, total, total);
}
static void _fill_blocks(struct ocf_stats_blocks *blocks,
struct ocf_stats_core *s)
{
uint64_t rd, wr, total;
/* Core volume */
rd = _bytes4k(s->core_volume.read);
wr = _bytes4k(s->core_volume.write);
total = rd + wr;
_set(&blocks->core_volume_rd, rd, total);
_set(&blocks->core_volume_wr, wr, total);
_set(&blocks->core_volume_total, total, total);
/* Cache volume */
rd = _bytes4k(s->cache_volume.read);
wr = _bytes4k(s->cache_volume.write);
total = rd + wr;
_set(&blocks->cache_volume_rd, rd, total);
_set(&blocks->cache_volume_wr, wr, total);
_set(&blocks->cache_volume_total, total, total);
/* Core (cache volume) */
rd = _bytes4k(s->core.read);
wr = _bytes4k(s->core.write);
total = rd + wr;
_set(&blocks->volume_rd, rd, total);
_set(&blocks->volume_wr, wr, total);
_set(&blocks->volume_total, total, total);
}
static void _fill_blocks_part(struct ocf_stats_blocks *blocks,
struct ocf_stats_io_class *s)
{
uint64_t rd, wr, total;
/* Core volume */
rd = _bytes4k(s->core_blocks.read);
wr = _bytes4k(s->core_blocks.write);
total = rd + wr;
_set(&blocks->core_volume_rd, rd, total);
_set(&blocks->core_volume_wr, wr, total);
_set(&blocks->core_volume_total, total, total);
/* Cache volume */
rd = _bytes4k(s->cache_blocks.read);
wr = _bytes4k(s->cache_blocks.write);
total = rd + wr;
_set(&blocks->cache_volume_rd, rd, total);
_set(&blocks->cache_volume_wr, wr, total);
_set(&blocks->cache_volume_total, total, total);
/* Core (cache volume) */
rd = _bytes4k(s->blocks.read);
wr = _bytes4k(s->blocks.write);
total = rd + wr;
_set(&blocks->volume_rd, rd, total);
_set(&blocks->volume_wr, wr, total);
_set(&blocks->volume_total, total, total);
}
static void _fill_errors(struct ocf_stats_errors *errors,
struct ocf_stats_core *s)
{
uint64_t rd, wr, total;
rd = s->core_errors.read;
wr = s->core_errors.write;
total = rd + wr;
_set(&errors->core_volume_rd, rd, total);
_set(&errors->core_volume_wr, wr, total);
_set(&errors->core_volume_total, total, total);
rd = s->cache_errors.read;
wr = s->cache_errors.write;
total = rd + wr;
_set(&errors->cache_volume_rd, rd, total);
_set(&errors->cache_volume_wr, wr, total);
_set(&errors->cache_volume_total, total, total);
total = s->core_errors.read + s->core_errors.write +
s->cache_errors.read + s->cache_errors.write;
_set(&errors->total, total, total);
}
static void _accumulate_block(struct ocf_stats_block *to,
const struct ocf_stats_block *from)
{
to->read += from->read;
to->write += from->write;
}
static void _accumulate_reqs(struct ocf_stats_req *to,
const struct ocf_stats_req *from)
{
to->full_miss += from->full_miss;
to->partial_miss += from->partial_miss;
to->total += from->total;
to->pass_through += from->pass_through;
}
static void _accumulate_errors(struct ocf_stats_error *to,
const struct ocf_stats_error *from)
{
to->read += from->read;
to->write += from->write;
}
struct io_class_stats_context {
struct ocf_stats_io_class *stats;
ocf_part_id_t part_id;
};
static int _accumulate_io_class_stats(ocf_core_t core, void *cntx)
{
int result;
struct ocf_stats_io_class stats;
struct ocf_stats_io_class *total =
((struct io_class_stats_context*)cntx)->stats;
ocf_part_id_t part_id = ((struct io_class_stats_context*)cntx)->part_id;
result = ocf_core_io_class_get_stats(core, part_id, &stats);
if (result)
return result;
total->occupancy_clines += stats.occupancy_clines;
total->dirty_clines += stats.dirty_clines;
total->free_clines = stats.free_clines;
_accumulate_block(&total->cache_blocks, &stats.cache_blocks);
_accumulate_block(&total->core_blocks, &stats.core_blocks);
_accumulate_block(&total->blocks, &stats.blocks);
_accumulate_reqs(&total->read_reqs, &stats.read_reqs);
_accumulate_reqs(&total->write_reqs, &stats.write_reqs);
return 0;
}
static void _ocf_stats_part_fill(ocf_cache_t cache, ocf_part_id_t part_id,
struct ocf_stats_io_class *stats , struct ocf_stats_usage *usage,
struct ocf_stats_requests *req, struct ocf_stats_blocks *blocks)
{
uint64_t cache_size, cache_line_size;
cache_line_size = ocf_cache_get_line_size(cache);
cache_size = cache->conf_meta->cachelines;
if (usage) {
_set(&usage->occupancy,
_lines4k(stats->occupancy_clines, cache_line_size),
_lines4k(cache_size, cache_line_size));
_set(&usage->free,
_lines4k(stats->free_clines, cache_line_size),
_lines4k(cache_size, cache_line_size));
_set(&usage->clean,
_lines4k(stats->occupancy_clines - stats->dirty_clines,
cache_line_size),
_lines4k(stats->occupancy_clines, cache_line_size));
_set(&usage->dirty,
_lines4k(stats->dirty_clines, cache_line_size),
_lines4k(stats->occupancy_clines, cache_line_size));
}
if (req)
_fill_req_part(req, stats);
if (blocks)
_fill_blocks_part(blocks, stats);
}
int ocf_stats_collect_part_core(ocf_core_t core, ocf_part_id_t part_id,
struct ocf_stats_usage *usage, struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks)
{
struct ocf_stats_io_class s;
ocf_cache_t cache;
int result = 0;
OCF_CHECK_NULL(core);
cache = ocf_core_get_cache(core);
if (ocf_cache_is_standby(cache))
return -OCF_ERR_CACHE_STANDBY;
if (part_id > OCF_IO_CLASS_ID_MAX)
return -OCF_ERR_INVAL;
_ocf_stats_zero(usage);
_ocf_stats_zero(req);
_ocf_stats_zero(blocks);
result = ocf_core_io_class_get_stats(core, part_id, &s);
if (result)
return result;
_ocf_stats_part_fill(cache, part_id, &s, usage, req, blocks);
return result;
}
int ocf_stats_collect_part_cache(ocf_cache_t cache, ocf_part_id_t part_id,
struct ocf_stats_usage *usage, struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks)
{
struct io_class_stats_context ctx;
struct ocf_stats_io_class s = {};
int result = 0;
OCF_CHECK_NULL(cache);
if (ocf_cache_is_standby(cache))
return -OCF_ERR_CACHE_STANDBY;
if (part_id > OCF_IO_CLASS_ID_MAX)
return -OCF_ERR_INVAL;
_ocf_stats_zero(usage);
_ocf_stats_zero(req);
_ocf_stats_zero(blocks);
ctx.part_id = part_id;
ctx.stats = &s;
result = ocf_core_visit(cache, _accumulate_io_class_stats, &ctx, true);
if (result)
return result;
_ocf_stats_part_fill(cache, part_id, &s, usage, req, blocks);
return result;
}
int ocf_stats_collect_core(ocf_core_t core,
struct ocf_stats_usage *usage,
struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks,
struct ocf_stats_errors *errors)
{
ocf_cache_t cache;
uint64_t cache_occupancy, cache_size, cache_line_size;
struct ocf_stats_core s;
int result;
OCF_CHECK_NULL(core);
cache = ocf_core_get_cache(core);
if (ocf_cache_is_standby(cache))
return -OCF_ERR_CACHE_STANDBY;
result = ocf_core_get_stats(core, &s);
if (result)
return result;
cache_line_size = ocf_cache_get_line_size(cache);
cache_size = cache->conf_meta->cachelines;
cache_occupancy = ocf_get_cache_occupancy(cache);
_ocf_stats_zero(usage);
_ocf_stats_zero(req);
_ocf_stats_zero(blocks);
_ocf_stats_zero(errors);
if (usage) {
_set(&usage->occupancy,
_lines4k(s.cache_occupancy, cache_line_size),
_lines4k(cache_size, cache_line_size));
_set(&usage->free,
_lines4k(cache_size - cache_occupancy, cache_line_size),
_lines4k(cache_size, cache_line_size));
_set(&usage->clean,
_lines4k(s.cache_occupancy - s.dirty, cache_line_size),
_lines4k(s.cache_occupancy, cache_line_size));
_set(&usage->dirty,
_lines4k(s.dirty, cache_line_size),
_lines4k(s.cache_occupancy, cache_line_size));
}
if (req)
_fill_req(req, &s);
if (blocks)
_fill_blocks(blocks, &s);
if (errors)
_fill_errors(errors, &s);
return 0;
}
static int _accumulate_stats(ocf_core_t core, void *cntx)
{
struct ocf_stats_core stats, *total = cntx;
int result;
result = ocf_core_get_stats(core, &stats);
if (result)
return result;
_accumulate_block(&total->cache_volume, &stats.cache_volume);
_accumulate_block(&total->core_volume, &stats.core_volume);
_accumulate_block(&total->core, &stats.core);
_accumulate_reqs(&total->read_reqs, &stats.read_reqs);
_accumulate_reqs(&total->write_reqs, &stats.write_reqs);
_accumulate_errors(&total->cache_errors, &stats.cache_errors);
_accumulate_errors(&total->core_errors, &stats.core_errors);
return 0;
}
int ocf_stats_collect_cache(ocf_cache_t cache,
struct ocf_stats_usage *usage,
struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks,
struct ocf_stats_errors *errors)
{
uint64_t cache_line_size;
struct ocf_cache_info info;
struct ocf_stats_core s = { 0 };
int result;
OCF_CHECK_NULL(cache);
if (ocf_cache_is_standby(cache))
return -OCF_ERR_CACHE_STANDBY;
result = ocf_cache_get_info(cache, &info);
if (result)
return result;
cache_line_size = ocf_cache_get_line_size(cache);
_ocf_stats_zero(usage);
_ocf_stats_zero(req);
_ocf_stats_zero(blocks);
_ocf_stats_zero(errors);
result = ocf_core_visit(cache, _accumulate_stats, &s, true);
if (result)
return result;
if (usage) {
_set(&usage->occupancy,
_lines4k(info.occupancy, cache_line_size),
_lines4k(info.size, cache_line_size));
_set(&usage->free,
_lines4k(info.size - info.occupancy, cache_line_size),
_lines4k(info.size, cache_line_size));
_set(&usage->clean,
_lines4k(info.occupancy - info.dirty, cache_line_size),
_lines4k(info.size, cache_line_size));
_set(&usage->dirty,
_lines4k(info.dirty, cache_line_size),
_lines4k(info.size, cache_line_size));
}
if (req)
_fill_req(req, &s);
if (blocks)
_fill_blocks(blocks, &s);
if (errors)
_fill_errors(errors, &s);
return 0;
}