Merge pull request #253 from mmichal10/stats-refactor

Stats builder for ioclasses
This commit is contained in:
Michal Rakowski 2019-09-10 14:56:26 +02:00 committed by GitHub
commit 29c1c7f9e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 832 additions and 534 deletions

View File

@ -29,7 +29,6 @@
#include "ocf_metadata_updater.h" #include "ocf_metadata_updater.h"
#include "ocf_io_class.h" #include "ocf_io_class.h"
#include "ocf_stats.h" #include "ocf_stats.h"
#include "ocf_stats_builder.h"
#include "ocf_mngt.h" #include "ocf_mngt.h"
#include "ocf_ctx.h" #include "ocf_ctx.h"
#include "ocf_err.h" #include "ocf_err.h"

View File

@ -16,6 +16,32 @@
#include "ocf_io.h" #include "ocf_io.h"
#include "ocf_mngt.h" #include "ocf_mngt.h"
struct ocf_core_info {
/** Core size in cache line size unit */
uint64_t core_size;
/** Core size in bytes unit */
uint64_t core_size_bytes;
/** Fields refers ongoing flush operation */
struct {
/** Number of blocks flushed in ongoing flush operation */
uint32_t flushed;
/** Number of blocks left to flush in ongoing flush operation */
uint32_t dirty;
};
/** How long core is dirty in seconds unit */
uint32_t dirty_for;
/** Sequential cutoff threshold (in bytes) */
uint32_t seq_cutoff_threshold;
/** Sequential cutoff policy */
ocf_seq_cutoff_policy seq_cutoff_policy;
};
/** /**
* @brief Get OCF core by name * @brief Get OCF core by name
* *
@ -202,4 +228,15 @@ typedef int (*ocf_core_visitor_t)(ocf_core_t core, void *cntx);
int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx, int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx,
bool only_opened); bool only_opened);
/**
* @brief Get info of given core object
*
* @param[in] core Core object
* @param[out] info Core info structure
*
* @retval 0 Success
* @retval Non-zero Fail
*/
int ocf_core_get_info(ocf_core_t core, struct ocf_core_info *info);
#endif /* __OCF_CORE_H__ */ #endif /* __OCF_CORE_H__ */

View File

@ -5,154 +5,218 @@
/** /**
* @file * @file
* @brief OCF API for getting and reseting statistics * @brief OCF API for updating and reseting statistics
* *
* This file contains routines pertaining to retrieval and * This file contains routines pertaining to manipulation of OCF IO statistics.
* manipulation of OCF IO statistics.
*/ */
#ifndef __OCF_STATS_H__ #ifndef __OCF_STATS_H__
#define __OCF_STATS_H__ #define __OCF_STATS_H__
struct ocf_io; /**
* Entire row of statistcs
*/
struct ocf_stat {
/** Value */
uint64_t value;
/** percent x100 */
uint64_t fraction;
};
/** /**
* @brief OCF requests statistics like hit, miss, etc... * @brief Usage statistics in 4 KiB unit
* *
* @note To calculate number of hits request do: * An example of presenting statistics:
* total - (partial_miss + full_miss) * <pre>
*
* Usage statistics Count % Units
*
* Occupancy 20 50.0 4KiB blocks
* Free 20 50.0 4KiB blocks
* Clean 15 75.0 4KiB blocks
* Dirty 5 25.0 4KiB blocks
*
* </pre>
*/ */
struct ocf_stats_req { struct ocf_stats_usage {
/** Number of partial misses */ struct ocf_stat occupancy;
uint64_t partial_miss; struct ocf_stat free;
struct ocf_stat clean;
/** Number of full misses */ struct ocf_stat dirty;
uint64_t full_miss;
/** Total of requests */
uint64_t total;
/** Pass-through requests */
uint64_t pass_through;
}; };
/** /**
* @brief OCF error statistics * @brief Requests statistcs
*
* An example of presenting statistics:
* <pre>
*
* Request statistics Count % Units
*
* Read hits 10 4.5 Requests
* Read partial misses 1 0.5 Requests
* Read full misses 211 95.0 Requests
* Read total 222 100.0 Requests
*
* Write hits 0 0.0 Requests
* Write partial misses 0 0.0 Requests
* Write full misses 0 0.0 Requests
* Write total 0 0.0 Requests
*
* Pass-Through reads 0 0.0 Requests
* Pass-Through writes 0 0.0 Requests
* Serviced requests 222 100.0 Requests
*
* Total requests 222 100.0 Requests
*
* </pre>
*/ */
struct ocf_stats_error { struct ocf_stats_requests {
/** Read errors */ struct ocf_stat rd_hits;
uint32_t read; struct ocf_stat rd_partial_misses;
struct ocf_stat rd_full_misses;
/** Write errors */ struct ocf_stat rd_total;
uint32_t write; struct ocf_stat wr_hits;
struct ocf_stat wr_partial_misses;
struct ocf_stat wr_full_misses;
struct ocf_stat wr_total;
struct ocf_stat rd_pt;
struct ocf_stat wr_pt;
struct ocf_stat serviced;
struct ocf_stat total;
}; };
/** /**
* @brief OCF block statistics in bytes * @brief Block statistics
*
* An example of presenting statistics:
* <pre>
*
* Block statistics Count % Units
*
* Reads from core volume(s) 426 100.0 4KiB blocks
* Writes to core volume(s) 0 0.0 4KiB blocks
* Total to/from core volume (s) 426 100.0 4KiB blocks
*
* Reads from cache volume 13 3.0 4KiB blocks
* Writes to cache volume 426 97.0 4KiB blocks
* Total to/from cache volume 439 100.0 4KiB blocks
*
* Reads from core(s) 439 100.0 4KiB blocks
* Writes to core(s) 0 0.0 4KiB blocks
* Total to/from core(s) 439 100.0 4KiB blocks
*
* </pre>
*/ */
struct ocf_stats_block { struct ocf_stats_blocks {
/** Number of blocks read */ struct ocf_stat core_volume_rd;
uint64_t read; struct ocf_stat core_volume_wr;
struct ocf_stat core_volume_total;
/** Number of blocks written */ struct ocf_stat cache_volume_rd;
uint64_t write; struct ocf_stat cache_volume_wr;
struct ocf_stat cache_volume_total;
struct ocf_stat volume_rd;
struct ocf_stat volume_wr;
struct ocf_stat volume_total;
}; };
/** /**
* Statistics appropriate for given IO class * @brief Errors statistics
*
* An example of presenting statistics:
* <pre>
*
* Error statistics Count % Units
*
* Cache read errors 0 0.0 Requests
* Cache write errors 0 0.0 Requests
* Cache total errors 0 0.0 Requests
*
* Core read errors 0 0.0 Requests
* Core write errors 0 0.0 Requests
* Core total errors 0 0.0 Requests
*
* Total errors 0 0.0 Requests
*
* </pre>
*/ */
struct ocf_stats_io_class { struct ocf_stats_errors {
/** Read requests statistics */ struct ocf_stat core_volume_rd;
struct ocf_stats_req read_reqs; struct ocf_stat core_volume_wr;
struct ocf_stat core_volume_total;
/** Writes requests statistics */ struct ocf_stat cache_volume_rd;
struct ocf_stats_req write_reqs; struct ocf_stat cache_volume_wr;
struct ocf_stat cache_volume_total;
/** Block requests statistics */ struct ocf_stat total;
struct ocf_stats_block blocks;
/** Number of cache lines available for given partition */
uint64_t free_clines;
/** Number of cache lines within lru list */
uint64_t occupancy_clines;
/** Number of dirty cache lines assigned to specific partition */
uint64_t dirty_clines;
};
#define IO_PACKET_NO 12
#define IO_ALIGN_NO 4
/**
* @brief Core debug statistics
*/
struct ocf_stats_core_debug {
/** I/O sizes being read (grouped by packets) */
uint64_t read_size[IO_PACKET_NO];
/** I/O sizes being written (grouped by packets) */
uint64_t write_size[IO_PACKET_NO];
/** I/O alignment for reads */
uint64_t read_align[IO_ALIGN_NO];
/** I/O alignment for writes */
uint64_t write_align[IO_ALIGN_NO];
}; };
/** /**
* @brief OCF core statistics * @param Collect statistics for given cache
*
* @param cache Cache instance for which statistics will be collected
* @param usage Usage statistics
* @param req Request statistics
* @param blocks Blocks statistics
* @param errors Errors statistics
*
* @retval 0 Success
* @retval Non-zero Error
*/ */
struct ocf_stats_core { int ocf_stats_collect_cache(ocf_cache_t cache,
/** Core size in cache line size unit */ struct ocf_stats_usage *usage,
uint64_t core_size; struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks,
struct ocf_stats_errors *errors);
/** Core size in bytes unit */ /**
uint64_t core_size_bytes; * @param Collect statistics for given core
*
* @param core Core for which statistics will be collected
* @param usage Usage statistics
* @param req Request statistics
* @param blocks Blocks statistics
* @param errors Errors statistics
*
* @retval 0 Success
* @retval Non-zero Error
*/
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);
/** Number of cache lines allocated in the cache for this core */ /**
uint32_t cache_occupancy; * @param Collect statistics for given ioclass
*
* @param core Core handle for which statistics will be collected
* @param part_id Ioclass id for which statistics will be collected
* @param usage Usage statistics
* @param req Request statistics
* @param blocks Blocks statistics
*
* @retval 0 Success
* @retval Non-zero Error
*/
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);
/** Number of dirty cache lines allocated in the cache for this core */ /**
uint32_t dirty; * @param Collect statistics for given ioclass
*
/** Number of block flushed in ongoing flush operation */ * @param cache Cache instance for which statistics will be collected
uint32_t flushed; * @param part_id Ioclass id for which statistics will be collected
* @param usage Usage statistics
/** How long core is dirty in seconds unit */ * @param req Request statistics
uint32_t dirty_for; * @param blocks Blocks statistics
*
/** Read requests statistics */ * @retval 0 Success
struct ocf_stats_req read_reqs; * @retval Non-zero Error
*/
/** Write requests statistics */ int ocf_stats_collect_part_cache(ocf_cache_t cache, ocf_part_id_t part_id,
struct ocf_stats_req write_reqs; struct ocf_stats_usage *usage, struct ocf_stats_requests *req,
struct ocf_stats_blocks *blocks);
/** Block requests for cache volume statistics */
struct ocf_stats_block cache_volume;
/** Block requests for core volume statistics */
struct ocf_stats_block core_volume;
/** Block requests submitted by user to this core */
struct ocf_stats_block core;
/** Cache volume error statistics */
struct ocf_stats_error cache_errors;
/** Core volume error statistics */
struct ocf_stats_error core_errors;
/** Debug statistics */
struct ocf_stats_core_debug debug_stat;
/** Sequential cutoff threshold (in bytes) */
uint32_t seq_cutoff_threshold;
/** Sequential cutoff policy */
ocf_seq_cutoff_policy seq_cutoff_policy;
};
/** /**
* @brief Initialize or reset core statistics * @brief Initialize or reset core statistics
@ -172,45 +236,4 @@ void ocf_core_stats_initialize(ocf_core_t core);
*/ */
void ocf_core_stats_initialize_all(ocf_cache_t cache); void ocf_core_stats_initialize_all(ocf_cache_t cache);
/**
* @brief ocf_core_io_class_get_stats retrieve io class statistics
* for given core
*
* Retrieve buffer of cache statistics for given cache instance.
*
* @param[in] core core handle to which request pertains
* @param[in] part_id IO class, stats of which are requested
* @param[out] stats statistic structure that shall be filled as
* a result of this function invocation.
*
* @result zero upon successful completion; error code otherwise
*/
int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
struct ocf_stats_io_class *stats);
/**
* @brief retrieve core stats
*
* Retrieve ocf per core stats (for all IO classes together)
*
* @param[in] core core ID to which request pertains
* @param[out] stats statistics structure that shall be filled as
* a result of this function invocation.
*
* @result zero upon successful completion; error code otherwise
*/
int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats);
/**
* @brief update stats given IO request
*
* Function meant to update stats for IO request.
*
* @note This function shall be invoked for eac IO request processed
*
* @param[in] core to which request pertains
* @param[in] io request for which stats are being updated
*/
void ocf_core_update_stats(ocf_core_t core, struct ocf_io *io);
#endif /* __OCF_STATS_H__ */ #endif /* __OCF_STATS_H__ */

View File

@ -1,190 +0,0 @@
/*
* Copyright(c) 2012-2018 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
/**
* @file
* @brief OCF API for collecting statistics
*
* This file contains routines pertaining to retrieval and
* manipulation of OCF IO statistics.
*/
#ifndef __OCF_STATS_BUILDER_H__
#define __OCF_STATS_BUILDER_H__
/**
* Entire row of statistcs
*/
struct ocf_stat {
/** Value */
uint64_t value;
/** percent x10 */
uint64_t percent;
};
/**
* @brief Usage statistics in 4 KiB unit
*
* An example of presenting statistics:
* <pre>
*
* Usage statistics Count % Units
*
* Occupancy 20 50.0 4KiB blocks
* Free 20 50.0 4KiB blocks
* Clean 15 75.0 4KiB blocks
* Dirty 5 25.0 4KiB blocks
*
* </pre>
*/
struct ocf_stats_usage {
struct ocf_stat occupancy;
struct ocf_stat free;
struct ocf_stat clean;
struct ocf_stat dirty;
};
/**
* @brief Requests statistcs
*
* An example of presenting statistics:
* <pre>
*
* Request statistics Count % Units
*
* Read hits 10 4.5 Requests
* Read partial misses 1 0.5 Requests
* Read full misses 211 95.0 Requests
* Read total 222 100.0 Requests
*
* Write hits 0 0.0 Requests
* Write partial misses 0 0.0 Requests
* Write full misses 0 0.0 Requests
* Write total 0 0.0 Requests
*
* Pass-Through reads 0 0.0 Requests
* Pass-Through writes 0 0.0 Requests
* Serviced requests 222 100.0 Requests
*
* Total requests 222 100.0 Requests
*
* </pre>
*/
struct ocf_stats_requests {
struct ocf_stat rd_hits;
struct ocf_stat rd_partial_misses;
struct ocf_stat rd_full_misses;
struct ocf_stat rd_total;
struct ocf_stat wr_hits;
struct ocf_stat wr_partial_misses;
struct ocf_stat wr_full_misses;
struct ocf_stat wr_total;
struct ocf_stat rd_pt;
struct ocf_stat wr_pt;
struct ocf_stat serviced;
struct ocf_stat total;
};
/**
* @brief Block statistics
*
* An example of presenting statistics:
* <pre>
*
* Block statistics Count % Units
*
* Reads from core volume(s) 426 100.0 4KiB blocks
* Writes to core volume(s) 0 0.0 4KiB blocks
* Total to/from core volume (s) 426 100.0 4KiB blocks
*
* Reads from cache volume 13 3.0 4KiB blocks
* Writes to cache volume 426 97.0 4KiB blocks
* Total to/from cache volume 439 100.0 4KiB blocks
*
* Reads from core(s) 439 100.0 4KiB blocks
* Writes to core(s) 0 0.0 4KiB blocks
* Total to/from core(s) 439 100.0 4KiB blocks
*
* </pre>
*/
struct ocf_stats_blocks {
struct ocf_stat core_volume_rd;
struct ocf_stat core_volume_wr;
struct ocf_stat core_volume_total;
struct ocf_stat cache_volume_rd;
struct ocf_stat cache_volume_wr;
struct ocf_stat cache_volume_total;
struct ocf_stat volume_rd;
struct ocf_stat volume_wr;
struct ocf_stat volume_total;
};
/**
* @brief Errors statistics
*
* An example of presenting statistics:
* <pre>
*
* Error statistics Count % Units
*
* Cache read errors 0 0.0 Requests
* Cache write errors 0 0.0 Requests
* Cache total errors 0 0.0 Requests
*
* Core read errors 0 0.0 Requests
* Core write errors 0 0.0 Requests
* Core total errors 0 0.0 Requests
*
* Total errors 0 0.0 Requests
*
* </pre>
*/
struct ocf_stats_errors {
struct ocf_stat core_volume_rd;
struct ocf_stat core_volume_wr;
struct ocf_stat core_volume_total;
struct ocf_stat cache_volume_rd;
struct ocf_stat cache_volume_wr;
struct ocf_stat cache_volume_total;
struct ocf_stat total;
};
/**
* @param Collect statistics for given cache
*
* @param cache Cache instance for each statistics will be collected
* @param usage Usage statistics
* @param req Request statistics
* @param blocks Blocks statistics
* @param errors Errors statistics
*
* @retval 0 Success
* @retval Non-zero Error
*/
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);
/**
* @param Collect statistics for given core
*
* @param cache Core for each statistics will be collected
* @param usage Usage statistics
* @param req Request statistics
* @param blocks Blocks statistics
* @param errors Errors statistics
*
* @retval 0 Success
* @retval Non-zero Error
*/
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);
#endif /* __OCF_STATS_BUILDER_H__ */

View File

@ -61,7 +61,7 @@ static void _ocf_backfill_complete(struct ocf_request *req, int error)
req->data = NULL; req->data = NULL;
if (req->error) { if (req->error) {
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
ocf_engine_invalidate(req); ocf_engine_invalidate(req);
} else { } else {
ocf_req_unlock(req); ocf_req_unlock(req);

View File

@ -446,42 +446,14 @@ void ocf_engine_clean(struct ocf_request *req)
void ocf_engine_update_block_stats(struct ocf_request *req) void ocf_engine_update_block_stats(struct ocf_request *req)
{ {
ocf_part_id_t part_id = req->part_id; ocf_core_stats_vol_block_update(req->core, req->part_id, req->rw,
struct ocf_counters_block *blocks; req->byte_length);
blocks = &req->core->counters->
part_counters[part_id].blocks;
if (req->rw == OCF_READ)
env_atomic64_add(req->byte_length, &blocks->read_bytes);
else if (req->rw == OCF_WRITE)
env_atomic64_add(req->byte_length, &blocks->write_bytes);
else
ENV_BUG();
} }
void ocf_engine_update_request_stats(struct ocf_request *req) void ocf_engine_update_request_stats(struct ocf_request *req)
{ {
ocf_part_id_t part_id = req->part_id; ocf_core_stats_request_update(req->core, req->part_id, req->rw,
struct ocf_counters_req *reqs; req->info.hit_no, req->core_line_count);
switch (req->rw) {
case OCF_READ:
reqs = &req->core->counters->part_counters[part_id].read_reqs;
break;
case OCF_WRITE:
reqs = &req->core->counters->part_counters[part_id].write_reqs;
break;
default:
ENV_BUG();
}
env_atomic64_inc(&reqs->total);
if (req->info.hit_no == 0)
env_atomic64_inc(&reqs->full_miss);
else if (req->info.hit_no < req->core_line_count)
env_atomic64_inc(&reqs->partial_miss);
} }
void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync) void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync)

View File

@ -16,17 +16,13 @@
static void _ocf_d2c_completion(struct ocf_request *req, int error) static void _ocf_d2c_completion(struct ocf_request *req, int error)
{ {
ocf_core_t core = req->core;
req->error = error; req->error = error;
OCF_DEBUG_RQ(req, "Completion"); OCF_DEBUG_RQ(req, "Completion");
if (req->error) { if (req->error) {
req->info.core_error = 1; req->info.core_error = 1;
if (req->rw == OCF_READ) ocf_core_stats_core_error_update(req->core, req->rw);
env_atomic_inc(&core->counters->core_errors.read);
else
env_atomic_inc(&core->counters->core_errors.write);
} }
/* Complete request */ /* Complete request */
@ -51,13 +47,8 @@ int ocf_io_d2c(struct ocf_request *req)
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);
if (req->rw == OCF_READ) { ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw,
env_atomic64_inc(&core->counters-> req->info.hit_no, req->core_line_count);
part_counters[req->part_id].read_reqs.pass_through);
} else {
env_atomic64_inc(&core->counters->
part_counters[req->part_id].write_reqs.pass_through);
}
/* Put OCF request - decrease reference counter */ /* Put OCF request - decrease reference counter */
ocf_req_put(req); ocf_req_put(req);

View File

@ -43,7 +43,7 @@ static void _ocf_read_fast_complete(struct ocf_request *req, int error)
if (req->error) { if (req->error) {
OCF_DEBUG_RQ(req, "ERROR"); OCF_DEBUG_RQ(req, "ERROR");
env_atomic_inc(&req->core->counters->cache_errors.read); ocf_core_stats_cache_error_update(req->core, OCF_READ);
ocf_engine_push_req_front_pt(req); ocf_engine_push_req_front_pt(req);
} else { } else {
ocf_req_unlock(req); ocf_req_unlock(req);
@ -91,7 +91,7 @@ static int _ocf_read_fast_do(struct ocf_request *req)
ocf_engine_io_count(req), _ocf_read_fast_complete); ocf_engine_io_count(req), _ocf_read_fast_complete);
/* Updata statistics */ /* Update statistics */
ocf_engine_update_request_stats(req); ocf_engine_update_request_stats(req);
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);

View File

@ -20,7 +20,7 @@ static void _ocf_invalidate_req(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
req->error = error; req->error = error;
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
} }
if (env_atomic_dec_return(&req->req_remaining)) if (env_atomic_dec_return(&req->req_remaining))

View File

@ -28,7 +28,7 @@ static void _ocf_read_pt_complete(struct ocf_request *req, int error)
if (req->error) { if (req->error) {
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.read); ocf_core_stats_core_error_update(req->core, OCF_READ);
} }
/* Complete request */ /* Complete request */
@ -87,8 +87,8 @@ int ocf_read_pt_do(struct ocf_request *req)
/* Update statistics */ /* Update statistics */
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);
env_atomic64_inc(&req->core->counters-> ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw,
part_counters[req->part_id].read_reqs.pass_through); req->info.hit_no, req->core_line_count);
/* Put OCF request - decrease reference counter */ /* Put OCF request - decrease reference counter */
ocf_req_put(req); ocf_req_put(req);

View File

@ -38,7 +38,7 @@ static void _ocf_read_generic_hit_complete(struct ocf_request *req, int error)
OCF_DEBUG_RQ(req, "HIT completion"); OCF_DEBUG_RQ(req, "HIT completion");
if (req->error) { if (req->error) {
env_atomic_inc(&req->core->counters->cache_errors.read); ocf_core_stats_cache_error_update(req->core, OCF_READ);
ocf_engine_push_req_front_pt(req); ocf_engine_push_req_front_pt(req);
} else { } else {
@ -77,7 +77,7 @@ static void _ocf_read_generic_miss_complete(struct ocf_request *req, int error)
req->complete(req, req->error); req->complete(req, req->error);
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.read); ocf_core_stats_core_error_update(req->core, OCF_READ);
ctx_data_free(cache->owner, req->cp_data); ctx_data_free(cache->owner, req->cp_data);
req->cp_data = NULL; req->cp_data = NULL;

View File

@ -24,7 +24,7 @@ static void _ocf_read_wa_complete(struct ocf_request *req, int error)
if (req->error) { if (req->error) {
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.write); ocf_core_stats_core_error_update(req->core, OCF_WRITE);
} }
/* Complete request */ /* Complete request */
@ -76,8 +76,8 @@ int ocf_write_wa(struct ocf_request *req)
/* Update statistics */ /* Update statistics */
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);
env_atomic64_inc(&req->core->counters-> ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw,
part_counters[req->part_id].write_reqs.pass_through); req->info.hit_no, req->core_line_count);
} }
/* Put OCF request - decrease reference counter */ /* Put OCF request - decrease reference counter */

View File

@ -89,7 +89,7 @@ static const struct ocf_io_if _io_if_wb_flush_metadata = {
static void _ocf_write_wb_complete(struct ocf_request *req, int error) static void _ocf_write_wb_complete(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
req->error |= error; req->error |= error;
} }
@ -150,13 +150,13 @@ int ocf_write_wb_do(struct ocf_request *req)
/* Get OCF request - increase reference counter */ /* Get OCF request - increase reference counter */
ocf_req_get(req); ocf_req_get(req);
/* Updata status bits */ /* Update status bits */
_ocf_write_wb_update_bits(req); _ocf_write_wb_update_bits(req);
/* Submit IO */ /* Submit IO */
_ocf_write_wb_submit(req); _ocf_write_wb_submit(req);
/* Updata statistics */ /* Update statistics */
ocf_engine_update_request_stats(req); ocf_engine_update_request_stats(req);
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);

View File

@ -26,7 +26,7 @@ static const struct ocf_io_if _io_if_wi_flush_metadata = {
static void _ocf_write_wi_io_flush_metadata(struct ocf_request *req, int error) static void _ocf_write_wi_io_flush_metadata(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
req->error |= error; req->error |= error;
} }
@ -77,7 +77,7 @@ static void _ocf_write_wi_core_complete(struct ocf_request *req, int error)
if (error) { if (error) {
req->error = error; req->error = error;
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.write); ocf_core_stats_core_error_update(req->core, OCF_WRITE);
} }
if (env_atomic_dec_return(&req->req_remaining)) if (env_atomic_dec_return(&req->req_remaining))
@ -112,8 +112,8 @@ static int _ocf_write_wi_do(struct ocf_request *req)
/* Update statistics */ /* Update statistics */
ocf_engine_update_block_stats(req); ocf_engine_update_block_stats(req);
env_atomic64_inc(&req->core->counters-> ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw,
part_counters[req->part_id].write_reqs.pass_through); req->info.hit_no, req->core_line_count);
/* Put OCF request - decrease reference counter */ /* Put OCF request - decrease reference counter */
ocf_req_put(req); ocf_req_put(req);

View File

@ -21,7 +21,7 @@
static void ocf_read_wo_cache_complete(struct ocf_request *req, int error) static void ocf_read_wo_cache_complete(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
env_atomic_inc(&req->core->counters->cache_errors.read); ocf_core_stats_cache_error_update(req->core, OCF_READ);
req->error |= error; req->error |= error;
} }
@ -148,7 +148,7 @@ static void _ocf_read_wo_core_complete(struct ocf_request *req, int error)
if (error) { if (error) {
req->error |= error; req->error |= error;
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.read); ocf_core_stats_core_error_update(req->core, OCF_READ);
} }
/* if all mapped cachelines are clean, the data we've read from core /* if all mapped cachelines are clean, the data we've read from core

View File

@ -48,7 +48,7 @@ static void _ocf_write_wt_cache_complete(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
req->error = req->error ?: error; req->error = req->error ?: error;
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
if (req->error) if (req->error)
inc_fallback_pt_error_counter(req->cache); inc_fallback_pt_error_counter(req->cache);
@ -62,7 +62,7 @@ static void _ocf_write_wt_core_complete(struct ocf_request *req, int error)
if (error) { if (error) {
req->error = error; req->error = error;
req->info.core_error = 1; req->info.core_error = 1;
env_atomic_inc(&req->core->counters->core_errors.write); ocf_core_stats_core_error_update(req->core, OCF_WRITE);
} }
_ocf_write_wt_req_complete(req); _ocf_write_wt_req_complete(req);

View File

@ -50,7 +50,7 @@ static const struct ocf_io_if _io_if_zero_purge = {
static void _ocf_zero_io_flush_metadata(struct ocf_request *req, int error) static void _ocf_zero_io_flush_metadata(struct ocf_request *req, int error)
{ {
if (error) { if (error) {
env_atomic_inc(&req->core->counters->cache_errors.write); ocf_core_stats_cache_error_update(req->core, OCF_WRITE);
req->error = error; req->error = error;
} }

View File

@ -143,6 +143,13 @@ int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx,
/* *** HELPER FUNCTIONS *** */ /* *** HELPER FUNCTIONS *** */
static uint32_t _calc_dirty_for(uint64_t dirty_since)
{
return dirty_since ?
(env_ticks_to_msecs(env_get_tick_count() - dirty_since) / 1000)
: 0;
}
static inline struct ocf_request *ocf_io_to_req(struct ocf_io *io) static inline struct ocf_request *ocf_io_to_req(struct ocf_io *io)
{ {
struct ocf_io_internal *ioi; struct ocf_io_internal *ioi;
@ -585,3 +592,31 @@ int ocf_core_volume_type_init(ocf_ctx_t ctx)
&ocf_core_volume_properties, &ocf_core_volume_properties,
&ocf_core_volume_extended); &ocf_core_volume_extended);
} }
int ocf_core_get_info(ocf_core_t core, struct ocf_core_info *info)
{
ocf_cache_t cache;
OCF_CHECK_NULL(core);
cache = ocf_core_get_cache(core);
if (!info)
return -OCF_ERR_INVAL;
ENV_BUG_ON(env_memset(info, sizeof(*info), 0));
info->core_size_bytes = ocf_volume_get_length(&core->volume);
info->core_size = ocf_bytes_2_lines_round_up(cache,
info->core_size_bytes);
info->seq_cutoff_threshold = ocf_core_get_seq_cutoff_threshold(core);
info->seq_cutoff_policy = ocf_core_get_seq_cutoff_policy(core);
info->flushed = env_atomic_read(&core->flushed);
info->dirty = env_atomic_read(&core->runtime_meta->dirty_clines);
info->dirty_for = _calc_dirty_for(
env_atomic64_read(&core->runtime_meta->dirty_since));
return 0;
}

View File

@ -47,6 +47,8 @@ static void ocf_stats_part_init(struct ocf_counters_part *stats)
ocf_stats_req_init(&stats->write_reqs); ocf_stats_req_init(&stats->write_reqs);
ocf_stats_block_init(&stats->blocks); ocf_stats_block_init(&stats->blocks);
ocf_stats_block_init(&stats->core_blocks);
ocf_stats_block_init(&stats->cache_blocks);
} }
static void ocf_stats_error_init(struct ocf_counters_error *stats) static void ocf_stats_error_init(struct ocf_counters_error *stats)
@ -55,6 +57,119 @@ static void ocf_stats_error_init(struct ocf_counters_error *stats)
env_atomic_set(&stats->write, 0); env_atomic_set(&stats->write, 0);
} }
static void _ocf_stats_block_update(struct ocf_counters_block *counters, int dir,
uint64_t bytes)
{
switch (dir) {
case OCF_READ:
env_atomic64_add(bytes, &counters->read_bytes);
break;
case OCF_WRITE:
env_atomic64_add(bytes, &counters->write_bytes);
break;
default:
ENV_BUG();
}
}
void ocf_core_stats_vol_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes)
{
struct ocf_counters_block *counters =
&core->counters->part_counters[part_id].blocks;
_ocf_stats_block_update(counters, dir, bytes);
}
void ocf_core_stats_cache_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes)
{
struct ocf_counters_block *counters =
&core->counters->part_counters[part_id].cache_blocks;
_ocf_stats_block_update(counters, dir, bytes);
}
void ocf_core_stats_core_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes)
{
struct ocf_counters_block *counters =
&core->counters->part_counters[part_id].core_blocks;
_ocf_stats_block_update(counters, dir, bytes);
}
void ocf_core_stats_request_update(ocf_core_t core, ocf_part_id_t part_id,
uint8_t dir, uint64_t hit_no, uint64_t core_line_count)
{
struct ocf_counters_req *counters;
switch (dir) {
case OCF_READ:
counters = &core->counters->part_counters[part_id].read_reqs;
break;
case OCF_WRITE:
counters = &core->counters->part_counters[part_id].write_reqs;
break;
default:
ENV_BUG();
}
env_atomic64_inc(&counters->total);
if (hit_no == 0)
env_atomic64_inc(&counters->full_miss);
else if (hit_no < core_line_count)
env_atomic64_inc(&counters->partial_miss);
}
void ocf_core_stats_request_pt_update(ocf_core_t core, ocf_part_id_t part_id,
uint8_t dir, uint64_t hit_no, uint64_t core_line_count)
{
struct ocf_counters_req *counters;
switch (dir) {
case OCF_READ:
counters = &core->counters->part_counters[part_id].read_reqs;
break;
case OCF_WRITE:
counters = &core->counters->part_counters[part_id].write_reqs;
break;
default:
ENV_BUG();
}
env_atomic64_inc(&counters->pass_through);
}
static void _ocf_core_stats_error_update(struct ocf_counters_error *counters,
uint8_t dir)
{
switch (dir) {
case OCF_READ:
env_atomic_inc(&counters->read);
break;
case OCF_WRITE:
env_atomic_inc(&counters->write);
break;
default:
ENV_BUG();
}
}
void ocf_core_stats_core_error_update(ocf_core_t core, uint8_t dir)
{
struct ocf_counters_error *counters = &core->counters->core_errors;
_ocf_core_stats_error_update(counters, dir);
}
void ocf_core_stats_cache_error_update(ocf_core_t core, uint8_t dir)
{
struct ocf_counters_error *counters = &core->counters->cache_errors;
_ocf_core_stats_error_update(counters, dir);
}
/******************************************************************** /********************************************************************
* Function that resets stats, debug and breakdown counters. * Function that resets stats, debug and breakdown counters.
@ -77,9 +192,6 @@ void ocf_core_stats_initialize(ocf_core_t core)
exp_obj_stats = core->counters; exp_obj_stats = core->counters;
ocf_stats_block_init(&exp_obj_stats->core_blocks);
ocf_stats_block_init(&exp_obj_stats->cache_blocks);
ocf_stats_error_init(&exp_obj_stats->cache_errors); ocf_stats_error_init(&exp_obj_stats->cache_errors);
ocf_stats_error_init(&exp_obj_stats->core_errors); ocf_stats_error_init(&exp_obj_stats->core_errors);
@ -199,30 +311,20 @@ int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
copy_req_stats(&stats->write_reqs, &part_stat->write_reqs); copy_req_stats(&stats->write_reqs, &part_stat->write_reqs);
copy_block_stats(&stats->blocks, &part_stat->blocks); copy_block_stats(&stats->blocks, &part_stat->blocks);
copy_block_stats(&stats->cache_blocks, &part_stat->cache_blocks);
copy_block_stats(&stats->core_blocks, &part_stat->core_blocks);
return 0; return 0;
} }
static uint32_t _calc_dirty_for(uint64_t dirty_since)
{
return dirty_since ?
(env_ticks_to_msecs(env_get_tick_count() - dirty_since) / 1000)
: 0;
}
int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats) int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats)
{ {
uint32_t i; uint32_t i;
ocf_core_id_t core_id;
ocf_cache_t cache;
struct ocf_counters_core *core_stats = NULL; struct ocf_counters_core *core_stats = NULL;
struct ocf_counters_part *curr = NULL; struct ocf_counters_part *curr = NULL;
OCF_CHECK_NULL(core); OCF_CHECK_NULL(core);
core_id = ocf_core_get_id(core);
cache = ocf_core_get_cache(core);
if (!stats) if (!stats)
return -OCF_ERR_INVAL; return -OCF_ERR_INVAL;
@ -230,19 +332,6 @@ int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats)
ENV_BUG_ON(env_memset(stats, sizeof(*stats), 0)); ENV_BUG_ON(env_memset(stats, sizeof(*stats), 0));
stats->core_size_bytes = ocf_volume_get_length(
&cache->core[core_id].volume);
stats->core_size = ocf_bytes_2_lines_round_up(cache,
stats->core_size_bytes);
stats->seq_cutoff_threshold = ocf_core_get_seq_cutoff_threshold(core);
stats->seq_cutoff_policy = ocf_core_get_seq_cutoff_policy(core);
env_atomic_read(&core->runtime_meta->cached_clines);
copy_block_stats(&stats->core_volume, &core_stats->core_blocks);
copy_block_stats(&stats->cache_volume, &core_stats->cache_blocks);
copy_error_stats(&stats->core_errors, copy_error_stats(&stats->core_errors,
&core_stats->core_errors); &core_stats->core_errors);
copy_error_stats(&stats->cache_errors, copy_error_stats(&stats->cache_errors,
@ -262,6 +351,8 @@ int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats)
&curr->write_reqs); &curr->write_reqs);
accum_block_stats(&stats->core, &curr->blocks); accum_block_stats(&stats->core, &curr->blocks);
accum_block_stats(&stats->core_volume, &curr->core_blocks);
accum_block_stats(&stats->cache_volume, &curr->cache_blocks);
stats->cache_occupancy += env_atomic_read(&core->runtime_meta-> stats->cache_occupancy += env_atomic_read(&core->runtime_meta->
part_counters[i].cached_clines); part_counters[i].cached_clines);
@ -269,11 +360,6 @@ int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats)
part_counters[i].dirty_clines); part_counters[i].dirty_clines);
} }
stats->flushed = env_atomic_read(&core->flushed);
stats->dirty_for = _calc_dirty_for(
env_atomic64_read(&core->runtime_meta->dirty_since));
return 0; return 0;
} }

View File

@ -18,11 +18,11 @@
} \ } \
} while (0) } while (0)
static uint64_t _percentage(uint64_t numerator, uint64_t denominator) static uint64_t _fraction(uint64_t numerator, uint64_t denominator)
{ {
uint64_t result; uint64_t result;
if (denominator) { if (denominator) {
result = 1000 * numerator / denominator; result = 10000 * numerator / denominator;
} else { } else {
result = 0; result = 0;
} }
@ -47,7 +47,7 @@ static uint64_t _bytes4k(uint64_t bytes)
static void _set(struct ocf_stat *stat, uint64_t value, uint64_t denominator) static void _set(struct ocf_stat *stat, uint64_t value, uint64_t denominator)
{ {
stat->value = value; stat->value = value;
stat->percent = _percentage(value, denominator); stat->fraction = _fraction(value, denominator);
} }
static void _fill_req(struct ocf_stats_requests *req, struct ocf_stats_core *s) static void _fill_req(struct ocf_stats_requests *req, struct ocf_stats_core *s)
@ -82,6 +82,39 @@ static void _fill_req(struct ocf_stats_requests *req, struct ocf_stats_core *s)
_set(&req->total, total, 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, static void _fill_blocks(struct ocf_stats_blocks *blocks,
struct ocf_stats_core *s) struct ocf_stats_core *s)
{ {
@ -112,6 +145,36 @@ static void _fill_blocks(struct ocf_stats_blocks *blocks,
_set(&blocks->volume_total, total, 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, static void _fill_errors(struct ocf_stats_errors *errors,
struct ocf_stats_core *s) struct ocf_stats_core *s)
{ {
@ -137,6 +200,152 @@ static void _fill_errors(struct ocf_stats_errors *errors,
_set(&errors->total, total, total); _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));
if (part_id == PARTITION_DEFAULT) {
_set(&usage->free,
_lines4k(stats->free_clines, cache_line_size),
_lines4k(cache_size, cache_line_size));
} else {
_set(&usage->free,
_lines4k(0, cache_line_size),
_lines4k(0, 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);
_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);
_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, int ocf_stats_collect_core(ocf_core_t core,
struct ocf_stats_usage *usage, struct ocf_stats_usage *usage,
struct ocf_stats_requests *req, struct ocf_stats_requests *req,
@ -194,29 +403,6 @@ int ocf_stats_collect_core(ocf_core_t core,
return 0; return 0;
} }
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;
}
static int _accumulate_stats(ocf_core_t core, void *cntx) static int _accumulate_stats(ocf_core_t core, void *cntx)
{ {
struct ocf_stats_core stats, *total = cntx; struct ocf_stats_core stats, *total = cntx;

View File

@ -23,6 +23,132 @@ struct ocf_counters_req {
env_atomic64 pass_through; env_atomic64 pass_through;
}; };
/**
* @brief OCF requests statistics like hit, miss, etc...
*
* @note To calculate number of hits request do:
* total - (partial_miss + full_miss)
*/
struct ocf_stats_req {
/** Number of partial misses */
uint64_t partial_miss;
/** Number of full misses */
uint64_t full_miss;
/** Total of requests */
uint64_t total;
/** Pass-through requests */
uint64_t pass_through;
};
/**
* @brief OCF error statistics
*/
struct ocf_stats_error {
/** Read errors */
uint32_t read;
/** Write errors */
uint32_t write;
};
/**
* @brief OCF block statistics in bytes
*/
struct ocf_stats_block {
/** Number of blocks read */
uint64_t read;
/** Number of blocks written */
uint64_t write;
};
/**
* Statistics appropriate for given IO class
*/
struct ocf_stats_io_class {
/** Number of cache lines available for given partition */
uint64_t free_clines;
/** Number of cache lines within lru list */
uint64_t occupancy_clines;
/** Number of dirty cache lines assigned to specific partition */
uint64_t dirty_clines;
/** Read requests statistics */
struct ocf_stats_req read_reqs;
/** Writes requests statistics */
struct ocf_stats_req write_reqs;
/** Block requests for ocf volume statistics */
struct ocf_stats_block blocks;
/** Block requests for cache volume statistics */
struct ocf_stats_block cache_blocks;
/** Block requests for core volume statistics */
struct ocf_stats_block core_blocks;
};
#define IO_PACKET_NO 12
#define IO_ALIGN_NO 4
/**
* @brief Core debug statistics
*/
struct ocf_stats_core_debug {
/** I/O sizes being read (grouped by packets) */
uint64_t read_size[IO_PACKET_NO];
/** I/O sizes being written (grouped by packets) */
uint64_t write_size[IO_PACKET_NO];
/** I/O alignment for reads */
uint64_t read_align[IO_ALIGN_NO];
/** I/O alignment for writes */
uint64_t write_align[IO_ALIGN_NO];
};
/**
* @brief OCF core statistics
*/
struct ocf_stats_core {
/** Number of cache lines allocated in the cache for this core */
uint32_t cache_occupancy;
/** Number of dirty cache lines allocated in the cache for this core */
uint32_t dirty;
/** Read requests statistics */
struct ocf_stats_req read_reqs;
/** Write requests statistics */
struct ocf_stats_req write_reqs;
/** Block requests for cache volume statistics */
struct ocf_stats_block cache_volume;
/** Block requests for core volume statistics */
struct ocf_stats_block core_volume;
/** Block requests submitted by user to this core */
struct ocf_stats_block core;
/** Cache volume error statistics */
struct ocf_stats_error cache_errors;
/** Core volume error statistics */
struct ocf_stats_error core_errors;
/** Debug statistics */
struct ocf_stats_core_debug debug_stat;
};
/** /**
* statistics appropriate for given io class. * statistics appropriate for given io class.
*/ */
@ -31,6 +157,9 @@ struct ocf_counters_part {
struct ocf_counters_req write_reqs; struct ocf_counters_req write_reqs;
struct ocf_counters_block blocks; struct ocf_counters_block blocks;
struct ocf_counters_block core_blocks;
struct ocf_counters_block cache_blocks;
}; };
#ifdef OCF_DEBUG_STATS #ifdef OCF_DEBUG_STATS
@ -44,9 +173,6 @@ struct ocf_counters_debug {
#endif #endif
struct ocf_counters_core { struct ocf_counters_core {
struct ocf_counters_block core_blocks;
struct ocf_counters_block cache_blocks;
struct ocf_counters_error core_errors; struct ocf_counters_error core_errors;
struct ocf_counters_error cache_errors; struct ocf_counters_error cache_errors;
@ -56,4 +182,60 @@ struct ocf_counters_core {
#endif #endif
}; };
void ocf_core_stats_core_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes);
void ocf_core_stats_cache_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes);
void ocf_core_stats_vol_block_update(ocf_core_t core, ocf_part_id_t part_id,
int dir, uint64_t bytes);
void ocf_core_stats_request_update(ocf_core_t core, ocf_part_id_t part_id,
uint8_t dir, uint64_t hit_no, uint64_t core_line_count);
void ocf_core_stats_request_pt_update(ocf_core_t core, ocf_part_id_t part_id,
uint8_t dir, uint64_t hit_no, uint64_t core_line_count);
void ocf_core_stats_core_error_update(ocf_core_t core, uint8_t dir);
void ocf_core_stats_cache_error_update(ocf_core_t core, uint8_t dir);
/**
* @brief ocf_core_io_class_get_stats retrieve io class statistics
* for given core
*
* Retrieve buffer of cache statistics for given cache instance.
*
* @param[in] core core handle to which request pertains
* @param[in] part_id IO class, stats of which are requested
* @param[out] stats statistic structure that shall be filled as
* a result of this function invocation.
*
* @result zero upon successful completion; error code otherwise
*/
int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
struct ocf_stats_io_class *stats);
/**
* @brief retrieve core stats
*
* Retrieve ocf per core stats (for all IO classes together)
*
* @param[in] core core ID to which request pertains
* @param[out] stats statistics structure that shall be filled as
* a result of this function invocation.
*
* @result zero upon successful completion; error code otherwise
*/
int ocf_core_get_stats(ocf_core_t core, struct ocf_stats_core *stats);
/**
* @brief update DEBUG stats given IO request
*
* Function meant to update DEBUG stats for IO request.
*
* @note This function shall be invoked for each IO request processed
*
* @param[in] core to which request pertains
* @param[in] io request for which stats are being updated
*/
void ocf_core_update_stats(ocf_core_t core, struct ocf_io *io);
#endif #endif

View File

@ -465,8 +465,7 @@ static void _ocf_cleaner_core_io_cmpl(struct ocf_io *io, int error)
if (error) { if (error) {
map->invalid |= 1; map->invalid |= 1;
_ocf_cleaner_set_error(req); _ocf_cleaner_set_error(req);
env_atomic_inc(&req->cache->core[map->core_id].counters-> ocf_core_stats_core_error_update(req->core, OCF_WRITE);
core_errors.write);
} }
_ocf_cleaner_core_io_end(req); _ocf_cleaner_core_io_end(req);
@ -480,10 +479,8 @@ static void _ocf_cleaner_core_io_for_dirty_range(struct ocf_request *req,
uint64_t addr, offset; uint64_t addr, offset;
int err; int err;
ocf_cache_t cache = req->cache; ocf_cache_t cache = req->cache;
ocf_core_t core = ocf_cache_get_core(cache, iter->core_id);
struct ocf_io *io; struct ocf_io *io;
struct ocf_counters_block *core_stats = ocf_core_t core = ocf_cache_get_core(cache, iter->core_id);
&cache->core[iter->core_id].counters->core_blocks;
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache,
iter->coll_idx); iter->coll_idx);
@ -505,7 +502,8 @@ static void _ocf_cleaner_core_io_for_dirty_range(struct ocf_request *req,
ocf_io_set_cmpl(io, iter, req, _ocf_cleaner_core_io_cmpl); ocf_io_set_cmpl(io, iter, req, _ocf_cleaner_core_io_cmpl);
env_atomic64_add(SECTORS_TO_BYTES(end - begin), &core_stats->write_bytes); ocf_core_stats_core_block_update(core, part_id, OCF_WRITE,
SECTORS_TO_BYTES(end - begin));
OCF_DEBUG_PARAM(req->cache, "Core write, line = %llu, " OCF_DEBUG_PARAM(req->cache, "Core write, line = %llu, "
"sector = %llu, count = %llu", iter->core_line, begin, "sector = %llu, count = %llu", iter->core_line, begin,
@ -622,8 +620,7 @@ static void _ocf_cleaner_cache_io_cmpl(struct ocf_io *io, int error)
if (error) { if (error) {
map->invalid |= 1; map->invalid |= 1;
_ocf_cleaner_set_error(req); _ocf_cleaner_set_error(req);
env_atomic_inc(&req->cache->core[map->core_id].counters-> ocf_core_stats_cache_error_update(req->core, OCF_READ);
cache_errors.read);
} }
_ocf_cleaner_cache_io_end(req); _ocf_cleaner_cache_io_end(req);
@ -637,27 +634,25 @@ static void _ocf_cleaner_cache_io_cmpl(struct ocf_io *io, int error)
*/ */
static int _ocf_cleaner_fire_cache(struct ocf_request *req) static int _ocf_cleaner_fire_cache(struct ocf_request *req)
{ {
struct ocf_cache *cache = req->cache; ocf_cache_t cache = req->cache;
ocf_core_t core;
uint32_t i; uint32_t i;
struct ocf_map_info *iter = req->map; struct ocf_map_info *iter = req->map;
uint64_t addr, offset; uint64_t addr, offset;
ocf_part_id_t part_id; ocf_part_id_t part_id;
struct ocf_io *io; struct ocf_io *io;
int err; int err;
struct ocf_counters_block *cache_stats;
/* Protect IO completion race */ /* Protect IO completion race */
env_atomic_inc(&req->req_remaining); env_atomic_inc(&req->req_remaining);
for (i = 0; i < req->core_line_count; i++, iter++) { for (i = 0; i < req->core_line_count; i++, iter++) {
if (iter->core_id == OCF_CORE_MAX) core = ocf_cache_get_core(cache, iter->core_id);
if (!core)
continue; continue;
if (iter->status == LOOKUP_MISS) if (iter->status == LOOKUP_MISS)
continue; continue;
cache_stats = &cache->core[iter->core_id].
counters->cache_blocks;
OCF_DEBUG_PARAM(req->cache, "Cache read, line = %u", OCF_DEBUG_PARAM(req->cache, "Cache read, line = %u",
iter->coll_idx); iter->coll_idx);
@ -689,7 +684,8 @@ static int _ocf_cleaner_fire_cache(struct ocf_request *req)
continue; continue;
} }
env_atomic64_add(ocf_line_size(cache), &cache_stats->read_bytes); ocf_core_stats_cache_block_update(core, part_id, OCF_READ,
ocf_line_size(cache));
ocf_volume_submit_io(io); ocf_volume_submit_io(io);
} }

View File

@ -227,9 +227,8 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
struct ocf_request *req, int dir, uint64_t offset, struct ocf_request *req, int dir, uint64_t offset,
uint64_t size, unsigned int reqs, ocf_req_end_t callback) uint64_t size, unsigned int reqs, ocf_req_end_t callback)
{ {
struct ocf_counters_block *cache_stats;
uint64_t flags = req->ioi.io.flags; uint64_t flags = req->ioi.io.flags;
uint32_t class = req->ioi.io.io_class; uint32_t io_class = req->ioi.io.io_class;
uint64_t addr, bytes, total_bytes = 0; uint64_t addr, bytes, total_bytes = 0;
struct ocf_io *io; struct ocf_io *io;
int err; int err;
@ -240,8 +239,6 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
ENV_BUG_ON(req->byte_length < offset + size); ENV_BUG_ON(req->byte_length < offset + size);
ENV_BUG_ON(first_cl + reqs > req->core_line_count); ENV_BUG_ON(first_cl + reqs > req->core_line_count);
cache_stats = &req->core->counters->cache_blocks;
if (reqs == 1) { if (reqs == 1) {
addr = ocf_metadata_map_lg2phy(cache, addr = ocf_metadata_map_lg2phy(cache,
req->map[first_cl].coll_idx); req->map[first_cl].coll_idx);
@ -251,7 +248,7 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
bytes = size; bytes = size;
io = ocf_new_cache_io(cache, req->io_queue, io = ocf_new_cache_io(cache, req->io_queue,
addr, bytes, dir, class, flags); addr, bytes, dir, io_class, flags);
if (!io) { if (!io) {
callback(req, -OCF_ERR_NO_MEM); callback(req, -OCF_ERR_NO_MEM);
goto update_stats; goto update_stats;
@ -298,7 +295,7 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
ENV_BUG_ON(bytes == 0); ENV_BUG_ON(bytes == 0);
io = ocf_new_cache_io(cache, req->io_queue, io = ocf_new_cache_io(cache, req->io_queue,
addr, bytes, dir, class, flags); addr, bytes, dir, io_class, flags);
if (!io) { if (!io) {
/* Finish all IOs which left with ERROR */ /* Finish all IOs which left with ERROR */
for (; i < reqs; i++) for (; i < reqs; i++)
@ -323,30 +320,23 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache,
ENV_BUG_ON(total_bytes != size); ENV_BUG_ON(total_bytes != size);
update_stats: update_stats:
if (dir == OCF_WRITE) ocf_core_stats_cache_block_update(req->core, io_class, dir, total_bytes);
env_atomic64_add(total_bytes, &cache_stats->write_bytes);
else if (dir == OCF_READ)
env_atomic64_add(total_bytes, &cache_stats->read_bytes);
} }
void ocf_submit_volume_req(ocf_volume_t volume, struct ocf_request *req, void ocf_submit_volume_req(ocf_volume_t volume, struct ocf_request *req,
ocf_req_end_t callback) ocf_req_end_t callback)
{ {
struct ocf_counters_block *core_stats;
uint64_t flags = req->ioi.io.flags; uint64_t flags = req->ioi.io.flags;
uint32_t class = req->ioi.io.io_class; uint32_t io_class = req->ioi.io.io_class;
int dir = req->rw; int dir = req->rw;
struct ocf_io *io; struct ocf_io *io;
int err; int err;
core_stats = &req->core->counters->core_blocks; ocf_core_stats_core_block_update(req->core, io_class, dir,
if (dir == OCF_WRITE) req->byte_length);
env_atomic64_add(req->byte_length, &core_stats->write_bytes);
else if (dir == OCF_READ)
env_atomic64_add(req->byte_length, &core_stats->read_bytes);
io = ocf_volume_new_io(volume, req->io_queue, req->byte_position, io = ocf_volume_new_io(volume, req->io_queue, req->byte_position,
req->byte_length, dir, class, flags); req->byte_length, dir, io_class, flags);
if (!io) { if (!io) {
callback(req, -OCF_ERR_NO_MEM); callback(req, -OCF_ERR_NO_MEM);
return; return;

View File

@ -25,7 +25,7 @@ from .data import Data
from .io import Io, IoDir from .io import Io, IoDir
from .queue import Queue from .queue import Queue
from .shared import Uuid, OcfCompletion, OcfError, SeqCutOffPolicy from .shared import Uuid, OcfCompletion, OcfError, SeqCutOffPolicy
from .stats.core import CoreStats from .stats.core import CoreInfo
from .stats.shared import UsageStats, RequestsStats, BlocksStats, ErrorsStats from .stats.shared import UsageStats, RequestsStats, BlocksStats, ErrorsStats
from .volume import Volume from .volume import Volume
from ..ocf import OcfLib from ..ocf import OcfLib
@ -111,7 +111,7 @@ class Core:
return Io.from_pointer(io) return Io.from_pointer(io)
def get_stats(self): def get_stats(self):
core_stats = CoreStats() core_info = CoreInfo()
usage = UsageStats() usage = UsageStats()
req = RequestsStats() req = RequestsStats()
blocks = BlocksStats() blocks = BlocksStats()
@ -125,8 +125,8 @@ class Core:
self.cache.read_unlock() self.cache.read_unlock()
raise OcfError("Failed collecting core stats", status) raise OcfError("Failed collecting core stats", status)
status = self.cache.owner.lib.ocf_core_get_stats( status = self.cache.owner.lib.ocf_core_get_info(
self.handle, byref(core_stats) self.handle, byref(core_info)
) )
if status: if status:
self.cache.read_unlock() self.cache.read_unlock()
@ -134,10 +134,10 @@ class Core:
self.cache.read_unlock() self.cache.read_unlock()
return { return {
"size": Size(core_stats.core_size_bytes), "size": Size(core_info.core_size_bytes),
"dirty_for": timedelta(seconds=core_stats.dirty_for), "dirty_for": timedelta(seconds=core_info.dirty_for),
"seq_cutoff_policy": SeqCutOffPolicy(core_stats.seq_cutoff_policy), "seq_cutoff_policy": SeqCutOffPolicy(core_info.seq_cutoff_policy),
"seq_cutoff_threshold": core_stats.seq_cutoff_threshold, "seq_cutoff_threshold": core_info.seq_cutoff_threshold,
"usage": struct_to_dict(usage), "usage": struct_to_dict(usage),
"req": struct_to_dict(req), "req": struct_to_dict(req),
"blocks": struct_to_dict(blocks), "blocks": struct_to_dict(blocks),
@ -207,8 +207,8 @@ lib.ocf_mngt_core_set_seq_cutoff_policy.argtypes = [c_void_p, c_uint32]
lib.ocf_mngt_core_set_seq_cutoff_policy.restype = c_int lib.ocf_mngt_core_set_seq_cutoff_policy.restype = c_int
lib.ocf_stats_collect_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p] lib.ocf_stats_collect_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
lib.ocf_stats_collect_core.restype = c_int lib.ocf_stats_collect_core.restype = c_int
lib.ocf_core_get_stats.argtypes = [c_void_p, c_void_p] lib.ocf_core_get_info.argtypes = [c_void_p, c_void_p]
lib.ocf_core_get_stats.restype = c_int lib.ocf_core_get_info.restype = c_int
lib.ocf_core_new_io_wrapper.argtypes = [ lib.ocf_core_new_io_wrapper.argtypes = [
c_void_p, c_void_p,
c_void_p, c_void_p,

View File

@ -9,22 +9,13 @@ from ctypes import c_uint32, c_uint64, Structure
from .shared import OcfStatsReq, OcfStatsBlock, OcfStatsDebug, OcfStatsError from .shared import OcfStatsReq, OcfStatsBlock, OcfStatsDebug, OcfStatsError
class CoreStats(Structure): class CoreInfo(Structure):
_fields_ = [ _fields_ = [
("core_size", c_uint64), ("core_size", c_uint64),
("core_size_bytes", c_uint64), ("core_size_bytes", c_uint64),
("cache_occupancy", c_uint32),
("dirty", c_uint32), ("dirty", c_uint32),
("flushed", c_uint32), ("flushed", c_uint32),
("dirty_for", c_uint32), ("dirty_for", c_uint32),
("read_reqs", OcfStatsReq),
("write_reqs", OcfStatsReq),
("cache_volume", OcfStatsBlock),
("core_volume", OcfStatsBlock),
("core", OcfStatsBlock),
("cache_errors", OcfStatsError),
("core_errors", OcfStatsError),
("debug_stat", OcfStatsDebug),
("seq_cutoff_threshold", c_uint32), ("seq_cutoff_threshold", c_uint32),
("seq_cutoff_policy", c_uint32), ("seq_cutoff_policy", c_uint32),
] ]