diff --git a/inc/ocf.h b/inc/ocf.h index 07c98b0..7b01411 100644 --- a/inc/ocf.h +++ b/inc/ocf.h @@ -29,7 +29,6 @@ #include "ocf_metadata_updater.h" #include "ocf_io_class.h" #include "ocf_stats.h" -#include "ocf_stats_builder.h" #include "ocf_mngt.h" #include "ocf_ctx.h" #include "ocf_err.h" diff --git a/inc/ocf_core.h b/inc/ocf_core.h index 24b099c..435dd74 100644 --- a/inc/ocf_core.h +++ b/inc/ocf_core.h @@ -16,6 +16,32 @@ #include "ocf_io.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 * @@ -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, 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__ */ diff --git a/inc/ocf_stats.h b/inc/ocf_stats.h index cfafd68..b326c74 100644 --- a/inc/ocf_stats.h +++ b/inc/ocf_stats.h @@ -5,154 +5,218 @@ /** * @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 - * manipulation of OCF IO statistics. + * This file contains routines pertaining to manipulation of OCF IO statistics. */ #ifndef __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: - * total - (partial_miss + full_miss) + * An example of presenting statistics: + *
+ * ╔══════════════════╤══════════╤═══════╤═════════════╗
+ * ║ 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 ║
+ * ╚══════════════════╧══════════╧═══════╧═════════════╝
+ * 
*/ -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; +struct ocf_stats_usage { + struct ocf_stat occupancy; + struct ocf_stat free; + struct ocf_stat clean; + struct ocf_stat dirty; }; /** - * @brief OCF error statistics + * @brief Requests statistcs + * + * An example of presenting statistics: + *
+ * ╔══════════════════════╤═══════╤═══════╤══════════╗
+ * ║ 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 ║
+ * ╚══════════════════════╧═══════╧═══════╧══════════╝
+ * 
*/ -struct ocf_stats_error { - /** Read errors */ - uint32_t read; - - /** Write errors */ - uint32_t write; +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 OCF block statistics in bytes + * @brief Block statistics + * + * An example of presenting statistics: + *
+ * ╔════════════════════════════════════╤═══════╤═══════╤═════════════╗
+ * ║ 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 ║
+ * ╚════════════════════════════════════╧═══════╧═══════╧═════════════╝
+ * 
*/ -struct ocf_stats_block { - /** Number of blocks read */ - uint64_t read; - - /** Number of blocks written */ - uint64_t write; +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; }; /** - * Statistics appropriate for given IO class + * @brief Errors statistics + * + * An example of presenting statistics: + *
+ * ╔════════════════════╤═══════╤═════╤══════════╗
+ * ║ 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 ║
+ * ╚════════════════════╧═══════╧═════╧══════════╝
+ * 
*/ -struct ocf_stats_io_class { - /** Read requests statistics */ - struct ocf_stats_req read_reqs; - - /** Writes requests statistics */ - struct ocf_stats_req write_reqs; - - /** Block requests statistics */ - 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]; +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; }; /** - * @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 { - /** Core size in cache line size unit */ - uint64_t core_size; +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); - /** 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; - - /** Number of block flushed in ongoing flush operation */ - uint32_t flushed; - - /** How long core is dirty in seconds unit */ - uint32_t dirty_for; - - /** 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; - - /** Sequential cutoff threshold (in bytes) */ - uint32_t seq_cutoff_threshold; - - /** Sequential cutoff policy */ - ocf_seq_cutoff_policy seq_cutoff_policy; -}; +/** + * @param Collect statistics for given ioclass + * + * @param cache Cache instance 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_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); /** * @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); -/** - * @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__ */ diff --git a/inc/ocf_stats_builder.h b/inc/ocf_stats_builder.h deleted file mode 100644 index 48a67e6..0000000 --- a/inc/ocf_stats_builder.h +++ /dev/null @@ -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: - *
- * ╔══════════════════╤══════════╤═══════╤═════════════╗
- * ║ 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 ║
- * ╚══════════════════╧══════════╧═══════╧═════════════╝
- * 
- */ -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: - *
- * ╔══════════════════════╤═══════╤═══════╤══════════╗
- * ║ 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 ║
- * ╚══════════════════════╧═══════╧═══════╧══════════╝
- * 
- */ -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: - *
- * ╔════════════════════════════════════╤═══════╤═══════╤═════════════╗
- * ║ 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 ║
- * ╚════════════════════════════════════╧═══════╧═══════╧═════════════╝
- * 
- */ -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: - *
- * ╔════════════════════╤═══════╤═════╤══════════╗
- * ║ 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 ║
- * ╚════════════════════╧═══════╧═════╧══════════╝
- * 
- */ -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__ */ diff --git a/src/engine/engine_bf.c b/src/engine/engine_bf.c index 865b793..5899feb 100644 --- a/src/engine/engine_bf.c +++ b/src/engine/engine_bf.c @@ -61,7 +61,7 @@ static void _ocf_backfill_complete(struct ocf_request *req, int error) req->data = NULL; 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); } else { ocf_req_unlock(req); diff --git a/src/engine/engine_common.c b/src/engine/engine_common.c index b01148d..c57aefe 100644 --- a/src/engine/engine_common.c +++ b/src/engine/engine_common.c @@ -446,42 +446,14 @@ void ocf_engine_clean(struct ocf_request *req) void ocf_engine_update_block_stats(struct ocf_request *req) { - ocf_part_id_t part_id = req->part_id; - struct ocf_counters_block *blocks; - - 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(); + ocf_core_stats_vol_block_update(req->core, req->part_id, req->rw, + req->byte_length); } void ocf_engine_update_request_stats(struct ocf_request *req) { - ocf_part_id_t part_id = req->part_id; - struct ocf_counters_req *reqs; - - 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); + ocf_core_stats_request_update(req->core, req->part_id, req->rw, + req->info.hit_no, req->core_line_count); } void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync) diff --git a/src/engine/engine_d2c.c b/src/engine/engine_d2c.c index 337769d..ef0c3c8 100644 --- a/src/engine/engine_d2c.c +++ b/src/engine/engine_d2c.c @@ -16,17 +16,13 @@ static void _ocf_d2c_completion(struct ocf_request *req, int error) { - ocf_core_t core = req->core; req->error = error; OCF_DEBUG_RQ(req, "Completion"); if (req->error) { req->info.core_error = 1; - if (req->rw == OCF_READ) - env_atomic_inc(&core->counters->core_errors.read); - else - env_atomic_inc(&core->counters->core_errors.write); + ocf_core_stats_core_error_update(req->core, req->rw); } /* Complete request */ @@ -51,13 +47,8 @@ int ocf_io_d2c(struct ocf_request *req) ocf_engine_update_block_stats(req); - if (req->rw == OCF_READ) { - env_atomic64_inc(&core->counters-> - part_counters[req->part_id].read_reqs.pass_through); - } else { - env_atomic64_inc(&core->counters-> - part_counters[req->part_id].write_reqs.pass_through); - } + ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw, + req->info.hit_no, req->core_line_count); /* Put OCF request - decrease reference counter */ ocf_req_put(req); diff --git a/src/engine/engine_fast.c b/src/engine/engine_fast.c index 3921104..d2a8153 100644 --- a/src/engine/engine_fast.c +++ b/src/engine/engine_fast.c @@ -43,7 +43,7 @@ static void _ocf_read_fast_complete(struct ocf_request *req, int error) if (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); } else { 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); - /* Updata statistics */ + /* Update statistics */ ocf_engine_update_request_stats(req); ocf_engine_update_block_stats(req); diff --git a/src/engine/engine_inv.c b/src/engine/engine_inv.c index fd30204..347d3cf 100644 --- a/src/engine/engine_inv.c +++ b/src/engine/engine_inv.c @@ -20,7 +20,7 @@ static void _ocf_invalidate_req(struct ocf_request *req, int error) { if (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)) diff --git a/src/engine/engine_pt.c b/src/engine/engine_pt.c index 852b953..bf18431 100644 --- a/src/engine/engine_pt.c +++ b/src/engine/engine_pt.c @@ -28,7 +28,7 @@ static void _ocf_read_pt_complete(struct ocf_request *req, int error) if (req->error) { 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 */ @@ -87,8 +87,8 @@ int ocf_read_pt_do(struct ocf_request *req) /* Update statistics */ ocf_engine_update_block_stats(req); - env_atomic64_inc(&req->core->counters-> - part_counters[req->part_id].read_reqs.pass_through); + ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw, + req->info.hit_no, req->core_line_count); /* Put OCF request - decrease reference counter */ ocf_req_put(req); diff --git a/src/engine/engine_rd.c b/src/engine/engine_rd.c index 4d6794f..2ca2d48 100644 --- a/src/engine/engine_rd.c +++ b/src/engine/engine_rd.c @@ -38,7 +38,7 @@ static void _ocf_read_generic_hit_complete(struct ocf_request *req, int error) OCF_DEBUG_RQ(req, "HIT completion"); 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); } else { @@ -77,7 +77,7 @@ static void _ocf_read_generic_miss_complete(struct ocf_request *req, int error) req->complete(req, req->error); 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); req->cp_data = NULL; diff --git a/src/engine/engine_wa.c b/src/engine/engine_wa.c index 5613445..3c854c2 100644 --- a/src/engine/engine_wa.c +++ b/src/engine/engine_wa.c @@ -24,7 +24,7 @@ static void _ocf_read_wa_complete(struct ocf_request *req, int error) if (req->error) { 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 */ @@ -76,8 +76,8 @@ int ocf_write_wa(struct ocf_request *req) /* Update statistics */ ocf_engine_update_block_stats(req); - env_atomic64_inc(&req->core->counters-> - part_counters[req->part_id].write_reqs.pass_through); + ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw, + req->info.hit_no, req->core_line_count); } /* Put OCF request - decrease reference counter */ diff --git a/src/engine/engine_wb.c b/src/engine/engine_wb.c index 73cafc1..f97793d 100644 --- a/src/engine/engine_wb.c +++ b/src/engine/engine_wb.c @@ -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) { if (error) { - env_atomic_inc(&req->core->counters->cache_errors.write); + ocf_core_stats_cache_error_update(req->core, OCF_WRITE); req->error |= error; } @@ -150,13 +150,13 @@ int ocf_write_wb_do(struct ocf_request *req) /* Get OCF request - increase reference counter */ ocf_req_get(req); - /* Updata status bits */ + /* Update status bits */ _ocf_write_wb_update_bits(req); /* Submit IO */ _ocf_write_wb_submit(req); - /* Updata statistics */ + /* Update statistics */ ocf_engine_update_request_stats(req); ocf_engine_update_block_stats(req); diff --git a/src/engine/engine_wi.c b/src/engine/engine_wi.c index 1fdae6b..b0d204c 100644 --- a/src/engine/engine_wi.c +++ b/src/engine/engine_wi.c @@ -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) { if (error) { - env_atomic_inc(&req->core->counters->cache_errors.write); + ocf_core_stats_cache_error_update(req->core, OCF_WRITE); req->error |= error; } @@ -77,7 +77,7 @@ static void _ocf_write_wi_core_complete(struct ocf_request *req, int error) if (error) { req->error = error; 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)) @@ -112,8 +112,8 @@ static int _ocf_write_wi_do(struct ocf_request *req) /* Update statistics */ ocf_engine_update_block_stats(req); - env_atomic64_inc(&req->core->counters-> - part_counters[req->part_id].write_reqs.pass_through); + ocf_core_stats_request_pt_update(req->core, req->part_id, req->rw, + req->info.hit_no, req->core_line_count); /* Put OCF request - decrease reference counter */ ocf_req_put(req); diff --git a/src/engine/engine_wo.c b/src/engine/engine_wo.c index f4fba5f..022d70b 100644 --- a/src/engine/engine_wo.c +++ b/src/engine/engine_wo.c @@ -21,7 +21,7 @@ static void ocf_read_wo_cache_complete(struct ocf_request *req, int 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; } @@ -148,7 +148,7 @@ static void _ocf_read_wo_core_complete(struct ocf_request *req, int error) if (error) { req->error |= error; 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 diff --git a/src/engine/engine_wt.c b/src/engine/engine_wt.c index 0d70cec..ac5fc41 100644 --- a/src/engine/engine_wt.c +++ b/src/engine/engine_wt.c @@ -48,7 +48,7 @@ static void _ocf_write_wt_cache_complete(struct ocf_request *req, int error) { if (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) 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) { req->error = error; 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); diff --git a/src/engine/engine_zero.c b/src/engine/engine_zero.c index f3d0439..7caa52f 100644 --- a/src/engine/engine_zero.c +++ b/src/engine/engine_zero.c @@ -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) { if (error) { - env_atomic_inc(&req->core->counters->cache_errors.write); + ocf_core_stats_cache_error_update(req->core, OCF_WRITE); req->error = error; } diff --git a/src/ocf_core.c b/src/ocf_core.c index c346aee..5c8dcfe 100644 --- a/src/ocf_core.c +++ b/src/ocf_core.c @@ -143,6 +143,13 @@ int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx, /* *** 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) { 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_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; +} diff --git a/src/ocf_stats.c b/src/ocf_stats.c index 0cb49e0..51a14f1 100644 --- a/src/ocf_stats.c +++ b/src/ocf_stats.c @@ -47,6 +47,8 @@ static void ocf_stats_part_init(struct ocf_counters_part *stats) ocf_stats_req_init(&stats->write_reqs); 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) @@ -55,6 +57,119 @@ static void ocf_stats_error_init(struct ocf_counters_error *stats) 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. @@ -77,9 +192,6 @@ void ocf_core_stats_initialize(ocf_core_t core) 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->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_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; } -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) { uint32_t i; - ocf_core_id_t core_id; - ocf_cache_t cache; struct ocf_counters_core *core_stats = NULL; struct ocf_counters_part *curr = NULL; OCF_CHECK_NULL(core); - core_id = ocf_core_get_id(core); - cache = ocf_core_get_cache(core); - if (!stats) 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)); - 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, &core_stats->core_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); 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-> 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); } - stats->flushed = env_atomic_read(&core->flushed); - - stats->dirty_for = _calc_dirty_for( - env_atomic64_read(&core->runtime_meta->dirty_since)); - return 0; } diff --git a/src/ocf_stats_builder.c b/src/ocf_stats_builder.c index 91847b9..5f8125a 100644 --- a/src/ocf_stats_builder.c +++ b/src/ocf_stats_builder.c @@ -18,11 +18,11 @@ } \ } 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; if (denominator) { - result = 1000 * numerator / denominator; + result = 10000 * numerator / denominator; } else { 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) { 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) @@ -82,6 +82,39 @@ static void _fill_req(struct ocf_stats_requests *req, struct ocf_stats_core *s) _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) { @@ -112,6 +145,36 @@ static void _fill_blocks(struct ocf_stats_blocks *blocks, _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) { @@ -137,6 +200,152 @@ static void _fill_errors(struct ocf_stats_errors *errors, _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, struct ocf_stats_usage *usage, struct ocf_stats_requests *req, @@ -194,29 +403,6 @@ int ocf_stats_collect_core(ocf_core_t core, 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) { struct ocf_stats_core stats, *total = cntx; diff --git a/src/ocf_stats_priv.h b/src/ocf_stats_priv.h index 71c3982..59319dd 100644 --- a/src/ocf_stats_priv.h +++ b/src/ocf_stats_priv.h @@ -23,6 +23,132 @@ struct ocf_counters_req { 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. */ @@ -31,6 +157,9 @@ struct ocf_counters_part { struct ocf_counters_req write_reqs; struct ocf_counters_block blocks; + + struct ocf_counters_block core_blocks; + struct ocf_counters_block cache_blocks; }; #ifdef OCF_DEBUG_STATS @@ -44,9 +173,6 @@ struct ocf_counters_debug { #endif 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 cache_errors; @@ -56,4 +182,60 @@ struct ocf_counters_core { #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 diff --git a/src/utils/utils_cleaner.c b/src/utils/utils_cleaner.c index ad9c458..46b6106 100644 --- a/src/utils/utils_cleaner.c +++ b/src/utils/utils_cleaner.c @@ -465,8 +465,7 @@ static void _ocf_cleaner_core_io_cmpl(struct ocf_io *io, int error) if (error) { map->invalid |= 1; _ocf_cleaner_set_error(req); - env_atomic_inc(&req->cache->core[map->core_id].counters-> - core_errors.write); + ocf_core_stats_core_error_update(req->core, OCF_WRITE); } _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; int err; ocf_cache_t cache = req->cache; - ocf_core_t core = ocf_cache_get_core(cache, iter->core_id); struct ocf_io *io; - struct ocf_counters_block *core_stats = - &cache->core[iter->core_id].counters->core_blocks; + ocf_core_t core = ocf_cache_get_core(cache, iter->core_id); ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, 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); - 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, " "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) { map->invalid |= 1; _ocf_cleaner_set_error(req); - env_atomic_inc(&req->cache->core[map->core_id].counters-> - cache_errors.read); + ocf_core_stats_cache_error_update(req->core, OCF_READ); } _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) { - struct ocf_cache *cache = req->cache; + ocf_cache_t cache = req->cache; + ocf_core_t core; uint32_t i; struct ocf_map_info *iter = req->map; uint64_t addr, offset; ocf_part_id_t part_id; struct ocf_io *io; int err; - struct ocf_counters_block *cache_stats; /* Protect IO completion race */ env_atomic_inc(&req->req_remaining); 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; if (iter->status == LOOKUP_MISS) continue; - cache_stats = &cache->core[iter->core_id]. - counters->cache_blocks; - OCF_DEBUG_PARAM(req->cache, "Cache read, line = %u", iter->coll_idx); @@ -689,7 +684,8 @@ static int _ocf_cleaner_fire_cache(struct ocf_request *req) 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); } diff --git a/src/utils/utils_io.c b/src/utils/utils_io.c index c57e731..db98e7b 100644 --- a/src/utils/utils_io.c +++ b/src/utils/utils_io.c @@ -227,9 +227,8 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache, struct ocf_request *req, int dir, uint64_t offset, uint64_t size, unsigned int reqs, ocf_req_end_t callback) { - struct ocf_counters_block *cache_stats; 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; struct ocf_io *io; 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(first_cl + reqs > req->core_line_count); - cache_stats = &req->core->counters->cache_blocks; - if (reqs == 1) { addr = ocf_metadata_map_lg2phy(cache, req->map[first_cl].coll_idx); @@ -251,7 +248,7 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache, bytes = size; io = ocf_new_cache_io(cache, req->io_queue, - addr, bytes, dir, class, flags); + addr, bytes, dir, io_class, flags); if (!io) { callback(req, -OCF_ERR_NO_MEM); goto update_stats; @@ -298,7 +295,7 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache, ENV_BUG_ON(bytes == 0); io = ocf_new_cache_io(cache, req->io_queue, - addr, bytes, dir, class, flags); + addr, bytes, dir, io_class, flags); if (!io) { /* Finish all IOs which left with ERROR */ for (; i < reqs; i++) @@ -323,30 +320,23 @@ void ocf_submit_cache_reqs(struct ocf_cache *cache, ENV_BUG_ON(total_bytes != size); update_stats: - if (dir == OCF_WRITE) - env_atomic64_add(total_bytes, &cache_stats->write_bytes); - else if (dir == OCF_READ) - env_atomic64_add(total_bytes, &cache_stats->read_bytes); + ocf_core_stats_cache_block_update(req->core, io_class, dir, total_bytes); } void ocf_submit_volume_req(ocf_volume_t volume, struct ocf_request *req, ocf_req_end_t callback) { - struct ocf_counters_block *core_stats; 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; struct ocf_io *io; int err; - core_stats = &req->core->counters->core_blocks; - if (dir == OCF_WRITE) - 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); + ocf_core_stats_core_block_update(req->core, io_class, dir, + req->byte_length); 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) { callback(req, -OCF_ERR_NO_MEM); return; diff --git a/tests/functional/pyocf/types/core.py b/tests/functional/pyocf/types/core.py index 9d39683..5c2564e 100644 --- a/tests/functional/pyocf/types/core.py +++ b/tests/functional/pyocf/types/core.py @@ -25,7 +25,7 @@ from .data import Data from .io import Io, IoDir from .queue import Queue 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 .volume import Volume from ..ocf import OcfLib @@ -111,7 +111,7 @@ class Core: return Io.from_pointer(io) def get_stats(self): - core_stats = CoreStats() + core_info = CoreInfo() usage = UsageStats() req = RequestsStats() blocks = BlocksStats() @@ -125,8 +125,8 @@ class Core: self.cache.read_unlock() raise OcfError("Failed collecting core stats", status) - status = self.cache.owner.lib.ocf_core_get_stats( - self.handle, byref(core_stats) + status = self.cache.owner.lib.ocf_core_get_info( + self.handle, byref(core_info) ) if status: self.cache.read_unlock() @@ -134,10 +134,10 @@ class Core: self.cache.read_unlock() return { - "size": Size(core_stats.core_size_bytes), - "dirty_for": timedelta(seconds=core_stats.dirty_for), - "seq_cutoff_policy": SeqCutOffPolicy(core_stats.seq_cutoff_policy), - "seq_cutoff_threshold": core_stats.seq_cutoff_threshold, + "size": Size(core_info.core_size_bytes), + "dirty_for": timedelta(seconds=core_info.dirty_for), + "seq_cutoff_policy": SeqCutOffPolicy(core_info.seq_cutoff_policy), + "seq_cutoff_threshold": core_info.seq_cutoff_threshold, "usage": struct_to_dict(usage), "req": struct_to_dict(req), "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_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_core_get_stats.argtypes = [c_void_p, c_void_p] -lib.ocf_core_get_stats.restype = c_int +lib.ocf_core_get_info.argtypes = [c_void_p, c_void_p] +lib.ocf_core_get_info.restype = c_int lib.ocf_core_new_io_wrapper.argtypes = [ c_void_p, c_void_p, diff --git a/tests/functional/pyocf/types/stats/core.py b/tests/functional/pyocf/types/stats/core.py index 5aaacce..dd2d066 100644 --- a/tests/functional/pyocf/types/stats/core.py +++ b/tests/functional/pyocf/types/stats/core.py @@ -9,22 +9,13 @@ from ctypes import c_uint32, c_uint64, Structure from .shared import OcfStatsReq, OcfStatsBlock, OcfStatsDebug, OcfStatsError -class CoreStats(Structure): +class CoreInfo(Structure): _fields_ = [ ("core_size", c_uint64), ("core_size_bytes", c_uint64), - ("cache_occupancy", c_uint32), ("dirty", c_uint32), ("flushed", 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_policy", c_uint32), ]