Merge pull request #413 from mmichal10/occ-per-ioclass
Occupancy per ioclass
This commit is contained in:
commit
7f60d73511
1
env/posix/ocf_env.h
vendored
1
env/posix/ocf_env.h
vendored
@ -46,6 +46,7 @@
|
||||
#define min(a,b) MIN(a,b)
|
||||
|
||||
#define ENV_PRIu64 "lu"
|
||||
#define ENV_PRId64 "ld"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
|
@ -40,8 +40,8 @@ struct ocf_io_class_info {
|
||||
|
||||
uint32_t max_size;
|
||||
/*!< Maximum number of cache lines that might be assigned into
|
||||
* this IO class. If current size reach maximum size no more
|
||||
* allocation for this IO class takes place
|
||||
* this IO class. If current size reaches maximum size then some
|
||||
* of ioclass's cachelines are evicted.
|
||||
*/
|
||||
|
||||
uint8_t eviction_policy_type;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "../utils/utils_cache_line.h"
|
||||
#include "../ocf_request.h"
|
||||
#include "../utils/utils_cleaner.h"
|
||||
#include "../utils/utils_part.h"
|
||||
#include "../metadata/metadata.h"
|
||||
#include "../eviction/eviction.h"
|
||||
#include "../promotion/promotion.h"
|
||||
@ -127,7 +128,8 @@ void ocf_engine_update_req_info(struct ocf_cache *cache,
|
||||
/*
|
||||
* Need to move this cache line into other partition
|
||||
*/
|
||||
_entry->re_part = req->info.re_part = true;
|
||||
_entry->re_part = true;
|
||||
req->info.re_part_no++;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -254,7 +256,7 @@ static void ocf_engine_map_cache_line(struct ocf_request *req,
|
||||
ocf_cleaning_t clean_policy_type;
|
||||
|
||||
if (!ocf_freelist_get_cache_line(cache->freelist, cache_line)) {
|
||||
req->info.mapping_error = 1;
|
||||
ocf_req_set_mapping_error(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -334,7 +336,7 @@ static void ocf_engine_map(struct ocf_request *req)
|
||||
|
||||
if (ocf_engine_unmapped_count(req) >
|
||||
ocf_freelist_num_free(cache->freelist)) {
|
||||
req->info.mapping_error = 1;
|
||||
ocf_req_set_mapping_error(req);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -353,7 +355,7 @@ static void ocf_engine_map(struct ocf_request *req)
|
||||
ocf_engine_map_cache_line(req, entry->core_line,
|
||||
entry->hash, &entry->coll_idx);
|
||||
|
||||
if (req->info.mapping_error) {
|
||||
if (ocf_req_test_mapping_error(req)) {
|
||||
/*
|
||||
* Eviction error (mapping error), need to
|
||||
* clean, return and do pass through
|
||||
@ -375,7 +377,7 @@ static void ocf_engine_map(struct ocf_request *req)
|
||||
|
||||
}
|
||||
|
||||
if (!req->info.mapping_error) {
|
||||
if (!ocf_req_test_mapping_error(req)) {
|
||||
/* request has been inserted into cache - purge it from promotion
|
||||
* policy */
|
||||
ocf_promotion_req_purge(cache->promotion_policy, req);
|
||||
@ -408,15 +410,6 @@ static void _ocf_engine_clean_end(void *private_data, int error)
|
||||
}
|
||||
}
|
||||
|
||||
static int ocf_engine_evict(struct ocf_request *req)
|
||||
{
|
||||
if (!ocf_engine_unmapped_count(req))
|
||||
return 0;
|
||||
|
||||
return space_managment_evict_do(req->cache, req,
|
||||
ocf_engine_unmapped_count(req));
|
||||
}
|
||||
|
||||
static int lock_clines(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
@ -432,13 +425,139 @@ static int lock_clines(struct ocf_request *req,
|
||||
}
|
||||
}
|
||||
|
||||
static inline int ocf_prepare_clines_hit(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
int lock_status = -OCF_ERR_NO_LOCK;
|
||||
struct ocf_metadata_lock *metadata_lock = &req->cache->metadata.lock;
|
||||
uint32_t clines_to_evict;
|
||||
int res;
|
||||
|
||||
/* Cachelines are mapped in correct partition */
|
||||
if (ocf_part_is_enabled(&req->cache->user_parts[req->part_id]) &&
|
||||
!ocf_engine_needs_repart(req)) {
|
||||
lock_status = lock_clines(req, engine_cbs);
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
res = ocf_part_check_space(req, &clines_to_evict);
|
||||
|
||||
if (res == OCF_PART_HAS_SPACE)
|
||||
lock_status = lock_clines(req, engine_cbs);
|
||||
|
||||
/* Since target part is empty and disabled, request should be submited in
|
||||
* pass-through */
|
||||
if (res == OCF_PART_IS_DISABLED)
|
||||
ocf_req_set_mapping_error(req);
|
||||
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
|
||||
if (res != OCF_PART_IS_FULL)
|
||||
return lock_status;
|
||||
|
||||
ocf_metadata_start_exclusive_access(metadata_lock);
|
||||
ocf_part_check_space(req, &clines_to_evict);
|
||||
|
||||
if (space_managment_evict_do(req->cache, req, clines_to_evict) ==
|
||||
LOOKUP_MISS) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ocf_part_is_enabled(&req->cache->user_parts[req->part_id])) {
|
||||
/* Target part is disabled but had some cachelines assigned. Submit
|
||||
* request in pass-through after eviction has been made */
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
lock_status = lock_clines(req, engine_cbs);
|
||||
|
||||
unlock:
|
||||
ocf_metadata_end_exclusive_access(metadata_lock);
|
||||
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
static inline int ocf_prepare_clines_miss(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
int lock_status = -OCF_ERR_NO_LOCK;
|
||||
struct ocf_metadata_lock *metadata_lock = &req->cache->metadata.lock;
|
||||
uint32_t clines_to_evict = 0;
|
||||
int res;
|
||||
|
||||
/* Mapping must be performed holding (at least) hash-bucket write lock */
|
||||
ocf_req_hash_lock_upgrade(req);
|
||||
|
||||
/* Verify whether partition occupancy threshold is not reached yet or cache
|
||||
* is not out of free cachelines */
|
||||
res = ocf_part_check_space(req, &clines_to_evict);
|
||||
if (res == OCF_PART_IS_DISABLED) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
ocf_req_hash_unlock_wr(req);
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
if (res == OCF_PART_HAS_SPACE) {
|
||||
ocf_engine_map(req);
|
||||
if (ocf_req_test_mapping_error(req)) {
|
||||
goto eviction;
|
||||
}
|
||||
|
||||
lock_status = lock_clines(req, engine_cbs);
|
||||
if (lock_status < 0) {
|
||||
/* Mapping succeeded, but we failed to acquire cacheline lock.
|
||||
* Don't try to evict, just return error to caller */
|
||||
ocf_req_set_mapping_error(req);
|
||||
}
|
||||
|
||||
ocf_req_hash_unlock_wr(req);
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
eviction:
|
||||
ocf_req_hash_unlock_wr(req);
|
||||
ocf_metadata_start_exclusive_access(metadata_lock);
|
||||
|
||||
ocf_part_check_space(req, &clines_to_evict);
|
||||
|
||||
if (space_managment_evict_do(req->cache, req, clines_to_evict) ==
|
||||
LOOKUP_MISS) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ocf_part_is_enabled(&req->cache->user_parts[req->part_id])) {
|
||||
/* Partition is disabled but it had cachelines assigned. Now, that they
|
||||
* are evicted, don't try to map cachelines - we don't want to insert
|
||||
* new cachelines - the request should be submited in pass through mode
|
||||
* instead */
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ocf_engine_map(req);
|
||||
if (ocf_req_test_mapping_error(req))
|
||||
goto unlock;
|
||||
|
||||
lock_status = lock_clines(req, engine_cbs);
|
||||
if (lock_status < 0)
|
||||
ocf_req_set_mapping_error(req);
|
||||
|
||||
unlock:
|
||||
ocf_metadata_end_exclusive_access(metadata_lock);
|
||||
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
int ocf_engine_prepare_clines(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
bool mapped;
|
||||
bool promote = true;
|
||||
int lock = -ENOENT;
|
||||
struct ocf_metadata_lock *metadata_lock = &req->cache->metadata.lock;
|
||||
int lock = -OCF_ERR_NO_LOCK;
|
||||
|
||||
/* Calculate hashes for hash-bucket locking */
|
||||
ocf_req_hash(req);
|
||||
@ -452,50 +571,19 @@ int ocf_engine_prepare_clines(struct ocf_request *req,
|
||||
ocf_engine_traverse(req);
|
||||
|
||||
mapped = ocf_engine_is_mapped(req);
|
||||
if (mapped) {
|
||||
/* Request cachelines are already mapped, acquire cacheline
|
||||
* lock */
|
||||
lock = lock_clines(req, engine_cbs);
|
||||
} else {
|
||||
/* check if request should promote cachelines */
|
||||
promote = ocf_promotion_req_should_promote(
|
||||
req->cache->promotion_policy, req);
|
||||
if (!promote)
|
||||
req->info.mapping_error = 1;
|
||||
}
|
||||
if (mapped)
|
||||
return ocf_prepare_clines_hit(req, engine_cbs);
|
||||
|
||||
if (mapped || !promote) {
|
||||
/* Will not attempt mapping - release hash bucket lock */
|
||||
/* check if request should promote cachelines */
|
||||
promote = ocf_promotion_req_should_promote(
|
||||
req->cache->promotion_policy, req);
|
||||
if (!promote) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
} else {
|
||||
/* Need to map (potentially evict) cachelines. Mapping must be
|
||||
* performed holding (at least) hash-bucket write lock */
|
||||
ocf_req_hash_lock_upgrade(req);
|
||||
ocf_engine_map(req);
|
||||
if (!req->info.mapping_error)
|
||||
lock = lock_clines(req, engine_cbs);
|
||||
ocf_req_hash_unlock_wr(req);
|
||||
|
||||
if (req->info.mapping_error) {
|
||||
/* Not mapped - evict cachelines under global exclusive
|
||||
* lock*/
|
||||
ocf_metadata_start_exclusive_access(metadata_lock);
|
||||
|
||||
/* Now there is exclusive access for metadata. May
|
||||
* traverse once again and evict cachelines if needed.
|
||||
*/
|
||||
if (ocf_engine_evict(req) == LOOKUP_MAPPED)
|
||||
ocf_engine_map(req);
|
||||
|
||||
if (!req->info.mapping_error)
|
||||
lock = lock_clines(req, engine_cbs);
|
||||
|
||||
ocf_metadata_end_exclusive_access(metadata_lock);
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
return lock;
|
||||
return ocf_prepare_clines_miss(req, engine_cbs);
|
||||
}
|
||||
|
||||
static int _ocf_engine_clean_getter(struct ocf_cache *cache,
|
||||
|
@ -47,6 +47,20 @@ static inline bool ocf_engine_is_hit(struct ocf_request *req)
|
||||
*/
|
||||
#define ocf_engine_is_miss(req) (!ocf_engine_is_hit(req))
|
||||
|
||||
/**
|
||||
* @brief Check if all the cache lines are assigned to a good partition
|
||||
*
|
||||
* @param req OCF request
|
||||
*
|
||||
* @retval true request's cache lines are assigned to a good partition
|
||||
* @retval false some of the request's cache lines needs to be reassigned to
|
||||
* a target partition
|
||||
*/
|
||||
static inline bool ocf_engine_needs_repart(struct ocf_request *req)
|
||||
{
|
||||
return req->info.re_part_no > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if all cache lines are mapped fully
|
||||
*
|
||||
@ -98,6 +112,18 @@ static inline uint32_t ocf_engine_unmapped_count(struct ocf_request *req)
|
||||
return req->core_line_count - (req->info.hit_no + req->info.invalid_no);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get number of cache lines to repart
|
||||
*
|
||||
* @param req OCF request
|
||||
*
|
||||
* @retval Number of cache lines to repart
|
||||
*/
|
||||
static inline uint32_t ocf_engine_repart_count(struct ocf_request *req)
|
||||
{
|
||||
return req->info.re_part_no;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get number of IOs to perform cache read or write
|
||||
*
|
||||
|
@ -69,7 +69,7 @@ static int _ocf_read_fast_do(struct ocf_request *req)
|
||||
/* Get OCF request - increase reference counter */
|
||||
ocf_req_get(req);
|
||||
|
||||
if (req->info.re_part) {
|
||||
if (ocf_engine_needs_repart(req)) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
|
||||
ocf_req_hash_lock_wr(req);
|
||||
@ -108,6 +108,7 @@ int ocf_read_fast(struct ocf_request *req)
|
||||
{
|
||||
bool hit;
|
||||
int lock = OCF_LOCK_NOT_ACQUIRED;
|
||||
bool part_has_space = false;
|
||||
|
||||
/* Get OCF request - increase reference counter */
|
||||
ocf_req_get(req);
|
||||
@ -124,14 +125,18 @@ int ocf_read_fast(struct ocf_request *req)
|
||||
ocf_engine_traverse(req);
|
||||
|
||||
hit = ocf_engine_is_hit(req);
|
||||
if (hit) {
|
||||
|
||||
if (ocf_part_check_space(req, NULL) == OCF_PART_HAS_SPACE)
|
||||
part_has_space = true;
|
||||
|
||||
if (hit && part_has_space) {
|
||||
ocf_io_start(&req->ioi.io);
|
||||
lock = ocf_req_async_lock_rd(req, ocf_engine_on_resume);
|
||||
}
|
||||
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
|
||||
if (hit) {
|
||||
if (hit && part_has_space) {
|
||||
OCF_DEBUG_RQ(req, "Fast path success");
|
||||
|
||||
if (lock >= 0) {
|
||||
@ -154,10 +159,7 @@ int ocf_read_fast(struct ocf_request *req)
|
||||
/* Put OCF request - decrease reference counter */
|
||||
ocf_req_put(req);
|
||||
|
||||
if (hit)
|
||||
return OCF_FAST_PATH_YES;
|
||||
else
|
||||
return OCF_FAST_PATH_NO;
|
||||
return (hit && part_has_space) ? OCF_FAST_PATH_YES : OCF_FAST_PATH_NO;
|
||||
}
|
||||
|
||||
/* __ __ _ _ ______ _ _____ _ _
|
||||
@ -177,6 +179,7 @@ int ocf_write_fast(struct ocf_request *req)
|
||||
{
|
||||
bool mapped;
|
||||
int lock = OCF_LOCK_NOT_ACQUIRED;
|
||||
int part_has_space = false;
|
||||
|
||||
/* Get OCF request - increase reference counter */
|
||||
ocf_req_get(req);
|
||||
@ -193,14 +196,18 @@ int ocf_write_fast(struct ocf_request *req)
|
||||
ocf_engine_traverse(req);
|
||||
|
||||
mapped = ocf_engine_is_mapped(req);
|
||||
if (mapped) {
|
||||
|
||||
if (ocf_part_check_space(req, NULL) == OCF_PART_HAS_SPACE)
|
||||
part_has_space = true;
|
||||
|
||||
if (mapped && part_has_space) {
|
||||
ocf_io_start(&req->ioi.io);
|
||||
lock = ocf_req_async_lock_wr(req, ocf_engine_on_resume);
|
||||
}
|
||||
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
|
||||
if (mapped) {
|
||||
if (mapped && part_has_space) {
|
||||
if (lock >= 0) {
|
||||
OCF_DEBUG_RQ(req, "Fast path success");
|
||||
|
||||
@ -223,6 +230,5 @@ int ocf_write_fast(struct ocf_request *req)
|
||||
/* Put OCF request - decrease reference counter */
|
||||
ocf_req_put(req);
|
||||
|
||||
return mapped ? OCF_FAST_PATH_YES : OCF_FAST_PATH_NO;
|
||||
|
||||
return (mapped && part_has_space) ? OCF_FAST_PATH_YES : OCF_FAST_PATH_NO;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ int ocf_read_pt_do(struct ocf_request *req)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (req->info.re_part) {
|
||||
if (ocf_engine_needs_repart(req)) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
|
||||
ocf_req_hash_lock_wr(req);
|
||||
|
@ -172,7 +172,7 @@ static int _ocf_read_generic_do(struct ocf_request *req)
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
}
|
||||
|
||||
if (req->info.re_part) {
|
||||
if (ocf_engine_needs_repart(req)) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
|
||||
ocf_req_hash_lock_wr(req);
|
||||
@ -243,7 +243,7 @@ int ocf_read_generic(struct ocf_request *req)
|
||||
|
||||
lock = ocf_engine_prepare_clines(req, &_rd_engine_callbacks);
|
||||
|
||||
if (!req->info.mapping_error) {
|
||||
if (!ocf_req_test_mapping_error(req)) {
|
||||
if (lock >= 0) {
|
||||
if (lock != OCF_LOCK_ACQUIRED) {
|
||||
/* Lock was not acquired, need to wait for resume */
|
||||
|
@ -121,7 +121,7 @@ static inline void _ocf_write_wb_submit(struct ocf_request *req)
|
||||
* 3. Then continue processing request (flush metadata)
|
||||
*/
|
||||
|
||||
if (req->info.re_part) {
|
||||
if (ocf_engine_needs_repart(req)) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
|
||||
ocf_req_hash_lock_wr(req);
|
||||
@ -189,7 +189,7 @@ int ocf_write_wb(struct ocf_request *req)
|
||||
|
||||
lock = ocf_engine_prepare_clines(req, &_wb_engine_callbacks);
|
||||
|
||||
if (!req->info.mapping_error) {
|
||||
if (!ocf_req_test_mapping_error(req)) {
|
||||
if (lock >= 0) {
|
||||
if (lock != OCF_LOCK_ACQUIRED) {
|
||||
/* WR lock was not acquired, need to wait for resume */
|
||||
|
@ -118,7 +118,7 @@ static void _ocf_write_wt_update_bits(struct ocf_request *req)
|
||||
ocf_req_hash_unlock_wr(req);
|
||||
}
|
||||
|
||||
if (req->info.re_part) {
|
||||
if (ocf_engine_needs_repart(req)) {
|
||||
OCF_DEBUG_RQ(req, "Re-Part");
|
||||
|
||||
ocf_req_hash_lock_wr(req);
|
||||
@ -183,7 +183,7 @@ int ocf_write_wt(struct ocf_request *req)
|
||||
|
||||
lock = ocf_engine_prepare_clines(req, &_wt_engine_callbacks);
|
||||
|
||||
if (!req->info.mapping_error) {
|
||||
if (!ocf_req_test_mapping_error(req)) {
|
||||
if (lock >= 0) {
|
||||
if (lock != OCF_LOCK_ACQUIRED) {
|
||||
/* WR lock was not acquired, need to wait for resume */
|
||||
|
@ -20,10 +20,14 @@ struct eviction_policy_ops evict_policy_ops[ocf_eviction_max] = {
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t ocf_evict_calculate(struct ocf_user_part *part,
|
||||
uint32_t to_evict)
|
||||
static uint32_t ocf_evict_calculate(ocf_cache_t cache,
|
||||
struct ocf_user_part *part, uint32_t to_evict, bool roundup)
|
||||
{
|
||||
if (part->runtime->curr_size <= part->config->min_size) {
|
||||
|
||||
uint32_t curr_part_size = ocf_part_get_occupancy(part);
|
||||
uint32_t min_part_size = ocf_part_get_min_size(cache, part);
|
||||
|
||||
if (curr_part_size <= min_part_size) {
|
||||
/*
|
||||
* Cannot evict from this partition because current size
|
||||
* is less than minimum size
|
||||
@ -31,15 +35,31 @@ static uint32_t ocf_evict_calculate(struct ocf_user_part *part,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (to_evict < OCF_TO_EVICTION_MIN)
|
||||
if (roundup && to_evict < OCF_TO_EVICTION_MIN)
|
||||
to_evict = OCF_TO_EVICTION_MIN;
|
||||
|
||||
if (to_evict > (part->runtime->curr_size - part->config->min_size))
|
||||
to_evict = part->runtime->curr_size - part->config->min_size;
|
||||
if (to_evict > (curr_part_size - min_part_size))
|
||||
to_evict = curr_part_size - min_part_size;
|
||||
|
||||
return to_evict;
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_evict_part_do(ocf_cache_t cache,
|
||||
ocf_queue_t io_queue, const uint32_t evict_cline_no,
|
||||
struct ocf_user_part *target_part)
|
||||
{
|
||||
uint32_t to_evict = 0;
|
||||
|
||||
if (!evp_lru_can_evict(cache))
|
||||
return 0;
|
||||
|
||||
to_evict = ocf_evict_calculate(cache, target_part, evict_cline_no,
|
||||
false);
|
||||
|
||||
return ocf_eviction_need_space(cache, io_queue,
|
||||
target_part, to_evict);
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
||||
ocf_queue_t io_queue, const uint32_t evict_cline_no,
|
||||
struct ocf_user_part *target_part)
|
||||
@ -67,16 +87,13 @@ static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
||||
/* It seams that no more partition for eviction */
|
||||
break;
|
||||
}
|
||||
if (part_id == target_part->id) {
|
||||
/* Omit targeted, evict from different first */
|
||||
continue;
|
||||
}
|
||||
if (evicted >= evict_cline_no) {
|
||||
/* Evicted requested number of cache line, stop */
|
||||
goto out;
|
||||
}
|
||||
|
||||
to_evict = ocf_evict_calculate(part, evict_cline_no);
|
||||
to_evict = ocf_evict_calculate(cache, part, evict_cline_no,
|
||||
true);
|
||||
if (to_evict == 0) {
|
||||
/* No cache lines to evict for this partition */
|
||||
continue;
|
||||
@ -86,18 +103,6 @@ static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
||||
part, to_evict);
|
||||
}
|
||||
|
||||
if (!ocf_eviction_can_evict(cache))
|
||||
goto out;
|
||||
|
||||
if (evicted < evict_cline_no) {
|
||||
/* Now we can evict form targeted partition */
|
||||
to_evict = ocf_evict_calculate(target_part, evict_cline_no);
|
||||
if (to_evict) {
|
||||
evicted += ocf_eviction_need_space(cache, io_queue,
|
||||
target_part, to_evict);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return evicted;
|
||||
}
|
||||
@ -109,16 +114,22 @@ int space_managment_evict_do(struct ocf_cache *cache,
|
||||
uint32_t free;
|
||||
struct ocf_user_part *req_part = &cache->user_parts[req->part_id];
|
||||
|
||||
free = ocf_freelist_num_free(cache->freelist);
|
||||
if (evict_cline_no <= free)
|
||||
return LOOKUP_MAPPED;
|
||||
if (ocf_req_part_evict(req)) {
|
||||
evicted = ocf_evict_part_do(cache, req->io_queue, evict_cline_no,
|
||||
req_part);
|
||||
} else {
|
||||
free = ocf_freelist_num_free(cache->freelist);
|
||||
if (evict_cline_no <= free)
|
||||
return LOOKUP_MAPPED;
|
||||
|
||||
evict_cline_no -= free;
|
||||
evicted = ocf_evict_do(cache, req->io_queue, evict_cline_no, req_part);
|
||||
evict_cline_no -= free;
|
||||
|
||||
evicted = ocf_evict_do(cache, req->io_queue, evict_cline_no, req_part);
|
||||
}
|
||||
|
||||
if (evict_cline_no <= evicted)
|
||||
return LOOKUP_MAPPED;
|
||||
|
||||
req->info.mapping_error |= true;
|
||||
ocf_req_set_mapping_error(req);
|
||||
return LOOKUP_MISS;
|
||||
}
|
||||
|
@ -58,11 +58,11 @@ struct eviction_policy_ops {
|
||||
extern struct eviction_policy_ops evict_policy_ops[ocf_eviction_max];
|
||||
|
||||
/*
|
||||
* Deallocates space from low priority partitions.
|
||||
* Deallocates space according to eviction priorities.
|
||||
*
|
||||
* Returns -1 on error
|
||||
* or the destination partition ID for the free buffers
|
||||
* (it matches label and is part of the object (#core_id) IO group)
|
||||
* @returns:
|
||||
* 'LOOKUP_HIT' if evicted enough cachelines to serve @req
|
||||
* 'LOOKUP_MISS' otherwise
|
||||
*/
|
||||
int space_managment_evict_do(ocf_cache_t cache,
|
||||
struct ocf_request *req, uint32_t evict_cline_no);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#define PARTITION_DEFAULT 0
|
||||
#define PARTITION_INVALID ((ocf_part_id_t)-1)
|
||||
#define PARTITION_SIZE_MAX ((ocf_cache_line_t)-1)
|
||||
#define PARTITION_SIZE_MAX 100
|
||||
|
||||
void ocf_metadata_get_partition_info(
|
||||
struct ocf_cache *cache, ocf_cache_line_t line,
|
||||
|
@ -11,26 +11,26 @@
|
||||
#include "../eviction/eviction.h"
|
||||
|
||||
struct ocf_user_part_config {
|
||||
char name[OCF_IO_CLASS_NAME_MAX];
|
||||
uint32_t min_size;
|
||||
uint32_t max_size;
|
||||
int16_t priority;
|
||||
ocf_cache_mode_t cache_mode;
|
||||
struct {
|
||||
uint8_t valid : 1;
|
||||
uint8_t added : 1;
|
||||
uint8_t eviction : 1;
|
||||
/*!< This bits is setting during partition sorting,
|
||||
* and means that can evict from this partition
|
||||
*/
|
||||
} flags;
|
||||
char name[OCF_IO_CLASS_NAME_MAX];
|
||||
uint32_t min_size;
|
||||
uint32_t max_size;
|
||||
int16_t priority;
|
||||
ocf_cache_mode_t cache_mode;
|
||||
struct {
|
||||
uint8_t valid : 1;
|
||||
uint8_t added : 1;
|
||||
uint8_t eviction : 1;
|
||||
/*!< This bits is setting during partition sorting,
|
||||
* and means that can evict from this partition
|
||||
*/
|
||||
} flags;
|
||||
};
|
||||
|
||||
struct ocf_user_part_runtime {
|
||||
uint32_t curr_size;
|
||||
uint32_t head;
|
||||
struct eviction_policy eviction[OCF_NUM_EVICTION_LISTS];
|
||||
struct cleaning_policy cleaning;
|
||||
uint32_t curr_size;
|
||||
uint32_t head;
|
||||
struct eviction_policy eviction[OCF_NUM_EVICTION_LISTS];
|
||||
struct cleaning_policy cleaning;
|
||||
};
|
||||
|
||||
/* Iterator state, visiting all eviction lists within a partition
|
||||
|
@ -31,6 +31,8 @@ int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache,
|
||||
uint32_t max_size, uint8_t priority, bool valid)
|
||||
{
|
||||
uint32_t size;
|
||||
struct ocf_lst_entry *iter;
|
||||
uint32_t iter_id;
|
||||
|
||||
if (!name)
|
||||
return -OCF_ERR_INVAL;
|
||||
@ -41,6 +43,9 @@ int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache,
|
||||
if (cache->user_parts[part_id].config->flags.valid)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
if (min_size > max_size)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
if (max_size > PARTITION_SIZE_MAX)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
@ -51,6 +56,14 @@ int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache,
|
||||
return -OCF_ERR_INVAL;
|
||||
}
|
||||
|
||||
for_each_lst(&cache->lst_part, iter, iter_id) {
|
||||
if (iter_id == part_id) {
|
||||
ocf_cache_log(cache, log_err,
|
||||
"Part with id %hu already exists\n", part_id);
|
||||
return -OCF_ERR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof(cache->user_parts[part_id].config->name);
|
||||
if (env_strncpy(cache->user_parts[part_id].config->name, size, name, size))
|
||||
return -OCF_ERR_INVAL;
|
||||
@ -77,8 +90,7 @@ static int _ocf_mngt_set_partition_size(struct ocf_cache *cache,
|
||||
if (min > max)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
if (_ocf_mngt_count_parts_min_size(cache) + min
|
||||
>= cache->device->collision_table_entries) {
|
||||
if (_ocf_mngt_count_parts_min_size(cache) + min > PARTITION_SIZE_MAX) {
|
||||
/* Illegal configuration in which sum of all min_sizes exceeds
|
||||
* cache size.
|
||||
*/
|
||||
@ -126,17 +138,17 @@ static int _ocf_mngt_io_class_configure(ocf_cache_t cache,
|
||||
/* Try set partition size */
|
||||
if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) {
|
||||
ocf_cache_log(cache, log_info,
|
||||
"Setting IO class size, id: %u, name: '%s' "
|
||||
"[ ERROR ]\n", part_id, dest_part->config->name);
|
||||
"Setting IO class size, id: %u, name: '%s', max size: %u%%"
|
||||
" [ ERROR ]\n", part_id, dest_part->config->name, max);
|
||||
return -OCF_ERR_INVAL;
|
||||
}
|
||||
ocf_part_set_prio(cache, dest_part, prio);
|
||||
dest_part->config->cache_mode = cache_mode;
|
||||
|
||||
ocf_cache_log(cache, log_info,
|
||||
"Updating unclassified IO class, id: "
|
||||
"%u [ OK ]\n", part_id);
|
||||
|
||||
"Updating unclassified IO class, id: %u, name :'%s',"
|
||||
"max size: %u%% [ OK ]\n",
|
||||
part_id, dest_part->config->name, max);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -150,23 +162,23 @@ static int _ocf_mngt_io_class_configure(ocf_cache_t cache,
|
||||
/* Try set partition size */
|
||||
if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) {
|
||||
ocf_cache_log(cache, log_info,
|
||||
"Setting IO class size, id: %u, name: '%s' "
|
||||
"[ ERROR ]\n", part_id, dest_part->config->name);
|
||||
"Setting IO class size, id: %u, name: '%s', max size %u%%"
|
||||
"[ ERROR ]\n", part_id, dest_part->config->name, max);
|
||||
return -OCF_ERR_INVAL;
|
||||
}
|
||||
|
||||
if (ocf_part_is_valid(dest_part)) {
|
||||
/* Updating existing */
|
||||
ocf_cache_log(cache, log_info, "Updating existing IO "
|
||||
"class, id: %u, name: '%s' [ OK ]\n",
|
||||
part_id, dest_part->config->name);
|
||||
"class, id: %u, name: '%s', max size %u%% [ OK ]\n",
|
||||
part_id, dest_part->config->name, max);
|
||||
} else {
|
||||
/* Adding new */
|
||||
ocf_part_set_valid(cache, part_id, true);
|
||||
|
||||
ocf_cache_log(cache, log_info, "Adding new IO class, "
|
||||
"id: %u, name: '%s' [ OK ]\n", part_id,
|
||||
dest_part->config->name);
|
||||
"id: %u, name: '%s', max size %u%% [ OK ]\n", part_id,
|
||||
dest_part->config->name, max);
|
||||
}
|
||||
|
||||
ocf_part_set_prio(cache, dest_part, prio);
|
||||
|
@ -13,9 +13,10 @@
|
||||
struct ocf_req_allocator;
|
||||
|
||||
struct ocf_req_info {
|
||||
/* Number of hits, invalid, misses. */
|
||||
/* Number of hits, invalid, misses, reparts. */
|
||||
unsigned int hit_no;
|
||||
unsigned int invalid_no;
|
||||
unsigned int re_part_no;
|
||||
|
||||
uint32_t dirty_all;
|
||||
/*!< Number of dirty line in request*/
|
||||
@ -32,11 +33,6 @@ struct ocf_req_info {
|
||||
uint32_t mapping_error : 1;
|
||||
/*!< Core lines in this request were not mapped into cache */
|
||||
|
||||
uint32_t re_part : 1;
|
||||
/*!< This bit indicate that in the request some cache lines
|
||||
* has to be moved to another partition
|
||||
*/
|
||||
|
||||
uint32_t core_error : 1;
|
||||
/*!< Error occured during I/O on core device */
|
||||
|
||||
@ -191,6 +187,9 @@ struct ocf_request {
|
||||
uint8_t wi_second_pass : 1;
|
||||
/*!< Set after first pass of WI write is completed */
|
||||
|
||||
uint8_t part_evict : 1;
|
||||
/* !< Some cachelines from request's partition must be evicted */
|
||||
|
||||
log_sid_t sid;
|
||||
/*!< Tracing sequence ID */
|
||||
|
||||
@ -332,6 +331,40 @@ void ocf_req_clear_map(struct ocf_request *req);
|
||||
*/
|
||||
void ocf_req_hash(struct ocf_request *req);
|
||||
|
||||
/**
|
||||
* @brief Request should trigger eviction from it's target partition
|
||||
*
|
||||
* @param req - OCF request
|
||||
*/
|
||||
static inline void ocf_req_set_part_evict(struct ocf_request *req)
|
||||
{
|
||||
req->part_evict = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request shouldn't trigger eviction from it's target partition
|
||||
*
|
||||
* @param req - OCF request
|
||||
*/
|
||||
static inline void ocf_req_clear_part_evict(struct ocf_request *req)
|
||||
{
|
||||
req->part_evict = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check wheter request shouldn't trigger eviction from it's target
|
||||
* partition or any partition
|
||||
*
|
||||
* @param req - OCF request
|
||||
* @return true - Eviciton should be triggered from request's target partition
|
||||
* @return false - Eviction should be triggered with respect to eviction
|
||||
* priority
|
||||
*/
|
||||
static inline bool ocf_req_part_evict(struct ocf_request *req)
|
||||
{
|
||||
return req->part_evict;
|
||||
}
|
||||
|
||||
int ocf_req_set_dirty(struct ocf_request *req);
|
||||
|
||||
/**
|
||||
@ -348,6 +381,16 @@ static inline void ocf_req_clear(struct ocf_request *req)
|
||||
env_atomic_set(&req->req_remaining, 0);
|
||||
}
|
||||
|
||||
static inline void ocf_req_set_mapping_error(struct ocf_request *req)
|
||||
{
|
||||
req->info.mapping_error = true;
|
||||
}
|
||||
|
||||
static inline bool ocf_req_test_mapping_error(struct ocf_request *req)
|
||||
{
|
||||
return req->info.mapping_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return OCF request reference count
|
||||
*
|
||||
|
@ -276,10 +276,7 @@ int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
|
||||
struct ocf_stats_io_class *stats)
|
||||
{
|
||||
ocf_cache_t cache;
|
||||
uint32_t cache_occupancy_total = 0;
|
||||
struct ocf_counters_part *part_stat;
|
||||
ocf_core_t i_core;
|
||||
ocf_core_id_t i_core_id;
|
||||
|
||||
OCF_CHECK_NULL(core);
|
||||
OCF_CHECK_NULL(stats);
|
||||
@ -292,11 +289,6 @@ int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
|
||||
if (!ocf_part_is_valid(&cache->user_parts[part_id]))
|
||||
return -OCF_ERR_IO_CLASS_NOT_EXIST;
|
||||
|
||||
for_each_core(cache, i_core, i_core_id) {
|
||||
cache_occupancy_total += env_atomic_read(
|
||||
&i_core->runtime_meta->cached_clines);
|
||||
}
|
||||
|
||||
part_stat = &core->counters->part_counters[part_id];
|
||||
|
||||
stats->occupancy_clines = env_atomic_read(&core->runtime_meta->
|
||||
@ -304,8 +296,7 @@ int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id,
|
||||
stats->dirty_clines = env_atomic_read(&core->runtime_meta->
|
||||
part_counters[part_id].dirty_clines);
|
||||
|
||||
stats->free_clines = cache->conf_meta->cachelines -
|
||||
cache_occupancy_total;
|
||||
stats->free_clines = 0;
|
||||
|
||||
copy_req_stats(&stats->read_reqs, &part_stat->read_reqs);
|
||||
copy_req_stats(&stats->write_reqs, &part_stat->write_reqs);
|
||||
|
@ -229,15 +229,9 @@ static void _ocf_stats_part_fill(ocf_cache_t cache, ocf_part_id_t part_id,
|
||||
_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->free,
|
||||
_lines4k(stats->free_clines, cache_line_size),
|
||||
_lines4k(cache_size, cache_line_size));
|
||||
|
||||
_set(&usage->clean,
|
||||
_lines4k(stats->occupancy_clines - stats->dirty_clines,
|
||||
|
@ -190,3 +190,82 @@ void ocf_part_set_valid(struct ocf_cache *cache, ocf_part_id_t id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_part_evict_size(struct ocf_request *req)
|
||||
{
|
||||
uint32_t needed_cache_lines, part_available, cache_lines_to_evict;
|
||||
uint32_t part_occupancy, part_occupancy_debt;
|
||||
struct ocf_user_part *target_part = &req->cache->user_parts[req->part_id];
|
||||
uint32_t part_occupancy_limit =
|
||||
ocf_part_get_max_size(req->cache, target_part);
|
||||
|
||||
needed_cache_lines = ocf_engine_repart_count(req) +
|
||||
ocf_engine_unmapped_count(req);
|
||||
|
||||
part_occupancy = ocf_part_get_occupancy(target_part);
|
||||
|
||||
if (part_occupancy_limit >= part_occupancy) {
|
||||
part_available = part_occupancy_limit - part_occupancy;
|
||||
part_occupancy_debt = 0;
|
||||
} else {
|
||||
/* Occupancy is greater than occupancy limit. Evict missing number of
|
||||
* cachelines, but no more than single eviction limit */
|
||||
part_occupancy_debt = min((uint32_t)OCF_PENDING_EVICTION_LIMIT,
|
||||
part_occupancy - part_occupancy_limit);
|
||||
part_available = 0;
|
||||
}
|
||||
|
||||
if (ocf_freelist_num_free(req->cache->freelist) <
|
||||
ocf_engine_unmapped_count(req)) {
|
||||
/* Number of cachelines to insert greater than number of free
|
||||
* cachelines */
|
||||
if (part_available >= needed_cache_lines) {
|
||||
/* Cache is full, but target's part occupancy limit is not reached
|
||||
*/
|
||||
ocf_req_clear_part_evict(req);
|
||||
cache_lines_to_evict = needed_cache_lines;
|
||||
} else {
|
||||
/* Cache is full and target part reached it's occupancy limit */
|
||||
ocf_req_set_part_evict(req);
|
||||
cache_lines_to_evict = needed_cache_lines - part_available;
|
||||
}
|
||||
|
||||
} else if (part_available < needed_cache_lines) {
|
||||
/* Enough of free cache lines, but partition reached it's occupancy
|
||||
* limit */
|
||||
cache_lines_to_evict = needed_cache_lines - part_available;
|
||||
ocf_req_set_part_evict(req);
|
||||
|
||||
} else if (part_available >= needed_cache_lines) {
|
||||
/* Enough free cachelines available and they can be assigned to target
|
||||
* partition */
|
||||
cache_lines_to_evict = 0;
|
||||
|
||||
}
|
||||
|
||||
return cache_lines_to_evict + part_occupancy_debt;
|
||||
}
|
||||
|
||||
uint32_t ocf_part_check_space(struct ocf_request *req, uint32_t *to_evict)
|
||||
{
|
||||
uint32_t ret = OCF_PART_IS_FULL;
|
||||
uint32_t _to_evict;
|
||||
struct ocf_user_part *target_part = &req->cache->user_parts[req->part_id];
|
||||
|
||||
if (!ocf_part_is_enabled(target_part) &&
|
||||
ocf_part_get_occupancy(target_part) == 0) {
|
||||
/* If partition is disabled, but has assigned cachelines, eviction has
|
||||
* to be triggered */
|
||||
return OCF_PART_IS_DISABLED;
|
||||
}
|
||||
|
||||
_to_evict = ocf_part_evict_size(req);
|
||||
|
||||
if (_to_evict == 0)
|
||||
ret = OCF_PART_HAS_SPACE;
|
||||
|
||||
if (to_evict)
|
||||
*to_evict = _to_evict;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "../ocf_request.h"
|
||||
#include "../engine/cache_engine.h"
|
||||
#include "../engine/engine_common.h"
|
||||
#include "../metadata/metadata_partition.h"
|
||||
|
||||
void ocf_part_init(struct ocf_cache *cache);
|
||||
@ -50,6 +51,38 @@ static inline ocf_part_id_t ocf_part_class2id(ocf_cache_t cache, uint64_t class)
|
||||
return PARTITION_DEFAULT;
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_part_get_occupancy(struct ocf_user_part *part)
|
||||
{
|
||||
return part->runtime->curr_size;
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_part_get_min_size(ocf_cache_t cache,
|
||||
struct ocf_user_part *part)
|
||||
{
|
||||
uint64_t ioclass_size;
|
||||
|
||||
ioclass_size = part->config->min_size * cache->conf_meta->cachelines;
|
||||
|
||||
ioclass_size /= 100;
|
||||
|
||||
return (uint32_t)ioclass_size;
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t ocf_part_get_max_size(ocf_cache_t cache,
|
||||
struct ocf_user_part *part)
|
||||
{
|
||||
uint64_t ioclass_size, max_size, cache_size;
|
||||
|
||||
max_size = part->config->max_size;
|
||||
cache_size = cache->conf_meta->cachelines;
|
||||
|
||||
ioclass_size = max_size * cache_size;
|
||||
ioclass_size = OCF_DIV_ROUND_UP(ioclass_size, 100);
|
||||
|
||||
return (uint32_t)ioclass_size;
|
||||
}
|
||||
|
||||
void ocf_part_move(struct ocf_request *req);
|
||||
|
||||
#define for_each_part(cache, part, id) \
|
||||
@ -61,7 +94,27 @@ static inline void ocf_part_sort(struct ocf_cache *cache)
|
||||
ocf_lst_sort(&cache->lst_part);
|
||||
}
|
||||
|
||||
static inline ocf_cache_mode_t ocf_part_get_cache_mode(struct ocf_cache *cache,
|
||||
static inline bool ocf_part_is_enabled(struct ocf_user_part *part)
|
||||
{
|
||||
return part->config->max_size != 0;
|
||||
}
|
||||
|
||||
#define OCF_PART_HAS_SPACE 0
|
||||
#define OCF_PART_IS_FULL 1
|
||||
#define OCF_PART_IS_DISABLED 2
|
||||
/**
|
||||
* Check whether there is enough free cachelines to serve request. If partition
|
||||
* occupancy limit is reached, `req->part_evict` is set to true. Otherwise
|
||||
* flag is set to false and eviction from any partition should be triggered.
|
||||
*
|
||||
* @return
|
||||
* OCF_PART_HAS_SPACE when cachelines alloted successfully
|
||||
* OCF_PART_IS_FULL when need to evict some cachelines to serve request
|
||||
* OCF_PART_IS_DISABLED when caching for particular partition is disabled
|
||||
*/
|
||||
uint32_t ocf_part_check_space(struct ocf_request *req, uint32_t *to_evict);
|
||||
|
||||
static inline ocf_cache_mode_t ocf_part_get_cache_mode(ocf_cache_t cache,
|
||||
ocf_part_id_t part_id)
|
||||
{
|
||||
if (part_id < OCF_IO_CLASS_MAX)
|
||||
|
@ -25,6 +25,7 @@ from ..ocf import OcfLib
|
||||
from .shared import (
|
||||
Uuid,
|
||||
OcfError,
|
||||
OcfErrorCode,
|
||||
CacheLineSize,
|
||||
CacheLines,
|
||||
OcfCompletion,
|
||||
@ -34,6 +35,7 @@ from ..utils import Size, struct_to_dict
|
||||
from .core import Core
|
||||
from .queue import Queue
|
||||
from .stats.cache import CacheInfo
|
||||
from .ioclass import IoClassesInfo, IoClassInfo
|
||||
from .stats.shared import UsageStats, RequestsStats, BlocksStats, ErrorsStats
|
||||
|
||||
|
||||
@ -75,6 +77,9 @@ class ConfValidValues:
|
||||
promotion_nhit_trigger_threshold_range = range(0, 100)
|
||||
|
||||
|
||||
CACHE_MODE_NONE = -1
|
||||
|
||||
|
||||
class CacheMode(IntEnum):
|
||||
WT = 0
|
||||
WB = 1
|
||||
@ -299,6 +304,93 @@ class Cache:
|
||||
if status:
|
||||
raise OcfError("Error setting cache seq cut off policy", status)
|
||||
|
||||
def get_partition_info(self, part_id: int):
|
||||
ioclass_info = IoClassInfo()
|
||||
self.read_lock()
|
||||
|
||||
status = self.owner.lib.ocf_cache_io_class_get_info(
|
||||
self.cache_handle, part_id, byref(ioclass_info)
|
||||
)
|
||||
|
||||
self.read_unlock()
|
||||
if status:
|
||||
raise OcfError("Error retriving ioclass info", status)
|
||||
|
||||
return {
|
||||
"_name": ioclass_info._name.decode("ascii"),
|
||||
"_cache_mode": ioclass_info._cache_mode,
|
||||
"_priority": int(ioclass_info._priority),
|
||||
"_curr_size": (ioclass_info._curr_size),
|
||||
"_min_size": int(ioclass_info._min_size),
|
||||
"_max_size": int(ioclass_info._max_size),
|
||||
"_eviction_policy_type": int(ioclass_info._eviction_policy_type),
|
||||
"_cleaning_policy_type": int(ioclass_info._cleaning_policy_type),
|
||||
}
|
||||
|
||||
def add_partition(
|
||||
self, part_id: int, name: str, min_size: int, max_size: int, priority: int, valid: bool
|
||||
):
|
||||
self.write_lock()
|
||||
|
||||
_name = name.encode("ascii")
|
||||
|
||||
status = self.owner.lib.ocf_mngt_add_partition_to_cache(
|
||||
self.cache_handle, part_id, _name, min_size, max_size, priority, valid
|
||||
)
|
||||
|
||||
self.write_unlock()
|
||||
|
||||
if status:
|
||||
raise OcfError("Error adding partition to cache", status)
|
||||
|
||||
def configure_partition(
|
||||
self,
|
||||
part_id: int,
|
||||
name: str,
|
||||
min_size: int,
|
||||
max_size: int,
|
||||
priority: int,
|
||||
cache_mode=CACHE_MODE_NONE,
|
||||
):
|
||||
ioclasses_info = IoClassesInfo()
|
||||
|
||||
self.read_lock()
|
||||
|
||||
for i in range(IoClassesInfo.MAX_IO_CLASSES):
|
||||
ioclass_info = IoClassInfo()
|
||||
status = self.owner.lib.ocf_cache_io_class_get_info(
|
||||
self.cache_handle, i, byref(ioclass_info)
|
||||
)
|
||||
if status not in [0, -OcfErrorCode.OCF_ERR_IO_CLASS_NOT_EXIST]:
|
||||
raise OcfError("Error retriving existing ioclass config", status)
|
||||
ioclasses_info._config[i]._class_id = i
|
||||
ioclasses_info._config[i]._name = (
|
||||
ioclass_info._name if len(ioclass_info._name) > 0 else 0
|
||||
)
|
||||
ioclasses_info._config[i]._prio = ioclass_info._priority
|
||||
ioclasses_info._config[i]._cache_mode = ioclass_info._cache_mode
|
||||
ioclasses_info._config[i]._min_size = ioclass_info._min_size
|
||||
ioclasses_info._config[i]._max_size = ioclass_info._max_size
|
||||
|
||||
self.read_unlock()
|
||||
|
||||
ioclasses_info._config[part_id]._name = name.encode("ascii")
|
||||
ioclasses_info._config[part_id]._cache_mode = int(cache_mode)
|
||||
ioclasses_info._config[part_id]._prio = priority
|
||||
ioclasses_info._config[part_id]._min_size = min_size
|
||||
ioclasses_info._config[part_id]._max_size = max_size
|
||||
|
||||
self.write_lock()
|
||||
|
||||
status = self.owner.lib.ocf_mngt_cache_io_classes_configure(
|
||||
self.cache_handle, byref(ioclasses_info)
|
||||
)
|
||||
|
||||
self.write_unlock()
|
||||
|
||||
if status:
|
||||
raise OcfError("Error adding partition to cache", status)
|
||||
|
||||
def configure_device(
|
||||
self, device, force=False, perform_test=True, cache_line_size=None
|
||||
):
|
||||
@ -339,6 +431,21 @@ class Cache:
|
||||
if c.results["error"]:
|
||||
raise OcfError("Attaching cache device failed", c.results["error"])
|
||||
|
||||
def detach_device(self):
|
||||
self.write_lock()
|
||||
|
||||
c = OcfCompletion([("cache", c_void_p), ("priv", c_void_p), ("error", c_int)])
|
||||
|
||||
self.owner.lib.ocf_mngt_cache_detach(
|
||||
self.cache_handle, c, None
|
||||
)
|
||||
|
||||
c.wait()
|
||||
self.write_unlock()
|
||||
|
||||
if c.results["error"]:
|
||||
raise OcfError("Attaching cache device failed", c.results["error"])
|
||||
|
||||
def load_cache(self, device):
|
||||
self.configure_device(device)
|
||||
c = OcfCompletion([("cache", c_void_p), ("priv", c_void_p), ("error", c_int)])
|
||||
@ -605,3 +712,17 @@ lib.ocf_mngt_cache_cleaning_set_param.argtypes = [
|
||||
c_uint32,
|
||||
]
|
||||
lib.ocf_mngt_cache_cleaning_set_param.restype = c_int
|
||||
lib.ocf_cache_io_class_get_info.restype = c_int
|
||||
lib.ocf_cache_io_class_get_info.argtypes = [c_void_p, c_uint32, c_void_p]
|
||||
lib.ocf_mngt_add_partition_to_cache.restype = c_int
|
||||
lib.ocf_mngt_add_partition_to_cache.argtypes = [
|
||||
c_void_p,
|
||||
c_uint16,
|
||||
c_char_p,
|
||||
c_uint32,
|
||||
c_uint32,
|
||||
c_uint8,
|
||||
c_bool,
|
||||
]
|
||||
lib.ocf_mngt_cache_io_classes_configure.restype = c_int
|
||||
lib.ocf_mngt_cache_io_classes_configure.argtypes = [c_void_p, c_void_p]
|
||||
|
36
tests/functional/pyocf/types/ioclass.py
Normal file
36
tests/functional/pyocf/types/ioclass.py
Normal file
@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright(c) 2019-2020 Intel Corporation
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
from ctypes import c_uint8, c_uint32, c_int, c_int16, c_uint16, c_char, c_char_p, Structure
|
||||
|
||||
|
||||
class IoClassInfo(Structure):
|
||||
MAX_IO_CLASS_NAME_SIZE = 1024
|
||||
_fields_ = [
|
||||
("_name", c_char * MAX_IO_CLASS_NAME_SIZE),
|
||||
("_cache_mode", c_int),
|
||||
("_priority", c_int16),
|
||||
("_curr_size", c_uint32),
|
||||
("_min_size", c_uint32),
|
||||
("_max_size", c_uint32),
|
||||
("_eviction_policy_type", c_uint8),
|
||||
("_cleaning_policy_type", c_int),
|
||||
]
|
||||
|
||||
|
||||
class IoClassConfig(Structure):
|
||||
_fields_ = [
|
||||
("_class_id", c_uint32),
|
||||
("_name", c_char_p),
|
||||
("_prio", c_uint16),
|
||||
("_cache_mode", c_int),
|
||||
("_min_size", c_uint32),
|
||||
("_max_size", c_uint32),
|
||||
]
|
||||
|
||||
|
||||
class IoClassesInfo(Structure):
|
||||
MAX_IO_CLASSES = 33
|
||||
_fields_ = [("_config", IoClassConfig * MAX_IO_CLASSES)]
|
121
tests/functional/tests/management/test_attach_cache.py
Normal file
121
tests/functional/tests/management/test_attach_cache.py
Normal file
@ -0,0 +1,121 @@
|
||||
#
|
||||
# Copyright(c) 2019-2020 Intel Corporation
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
import logging
|
||||
from ctypes import c_int, c_void_p, byref, c_uint32, memmove, cast
|
||||
from random import randrange
|
||||
from itertools import count
|
||||
|
||||
import pytest
|
||||
|
||||
from pyocf.ocf import OcfLib
|
||||
from pyocf.types.cache import (
|
||||
Cache,
|
||||
CacheMode,
|
||||
MetadataLayout,
|
||||
EvictionPolicy,
|
||||
CleaningPolicy,
|
||||
)
|
||||
from pyocf.types.core import Core
|
||||
from pyocf.types.data import Data
|
||||
from pyocf.types.io import IoDir
|
||||
from pyocf.types.shared import (
|
||||
OcfError,
|
||||
OcfCompletion,
|
||||
CacheLines,
|
||||
CacheLineSize,
|
||||
SeqCutOffPolicy,
|
||||
)
|
||||
from pyocf.types.volume import Volume
|
||||
from pyocf.utils import Size
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||
@pytest.mark.parametrize("mode", [CacheMode.WB, CacheMode.WT, CacheMode.WO])
|
||||
@pytest.mark.parametrize("new_cache_size", [25, 45])
|
||||
def test_attach_different_size(
|
||||
pyocf_ctx, new_cache_size, mode: CacheMode, cls: CacheLineSize
|
||||
):
|
||||
"""Start cache and add partition with limited occupancy. Fill partition with data,
|
||||
attach cache with different size and trigger IO. Verify if occupancy thresold is
|
||||
respected with both original and new cache device.
|
||||
"""
|
||||
cache_device = Volume(Size.from_MiB(35))
|
||||
core_device = Volume(Size.from_MiB(100))
|
||||
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||
core = Core.using_device(core_device)
|
||||
cache.add_core(core)
|
||||
|
||||
cache.configure_partition(
|
||||
part_id=1, name="test_part", min_size=0, max_size=50, priority=1
|
||||
)
|
||||
|
||||
cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)
|
||||
|
||||
cache_size = cache.get_stats()["conf"]["size"]
|
||||
|
||||
block_size = 4096
|
||||
data = bytes(block_size)
|
||||
|
||||
for i in range(cache_size.blocks_4k):
|
||||
io_to_exp_obj(core, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
||||
|
||||
part_current_size = CacheLines(
|
||||
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
||||
)
|
||||
|
||||
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
||||
|
||||
cache.detach_device()
|
||||
new_cache_device = Volume(Size.from_MiB(new_cache_size))
|
||||
cache.attach_device(new_cache_device, force=True)
|
||||
|
||||
cache_size = cache.get_stats()["conf"]["size"]
|
||||
|
||||
for i in range(cache_size.blocks_4k):
|
||||
io_to_exp_obj(core, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
||||
|
||||
part_current_size = CacheLines(
|
||||
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
||||
)
|
||||
|
||||
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
||||
|
||||
|
||||
def io_to_exp_obj(core, address, size, data, offset, direction, target_ioclass, flags):
|
||||
return _io(
|
||||
core.new_io,
|
||||
core.cache.get_default_queue(),
|
||||
address,
|
||||
size,
|
||||
data,
|
||||
offset,
|
||||
direction,
|
||||
target_ioclass,
|
||||
flags,
|
||||
)
|
||||
|
||||
|
||||
def _io(new_io, queue, address, size, data, offset, direction, target_ioclass, flags):
|
||||
io = new_io(queue, address, size, direction, target_ioclass, flags)
|
||||
if direction == IoDir.READ:
|
||||
_data = Data.from_bytes(bytes(size))
|
||||
else:
|
||||
_data = Data.from_bytes(data, offset, size)
|
||||
ret = __io(io, queue, address, size, _data, direction)
|
||||
if not ret and direction == IoDir.READ:
|
||||
memmove(cast(data, c_void_p).value + offset, _data.handle, size)
|
||||
return ret
|
||||
|
||||
|
||||
def __io(io, queue, address, size, data, direction):
|
||||
io.set_data(data, 0)
|
||||
completion = OcfCompletion([("err", c_int)])
|
||||
io.callback = completion.callback
|
||||
io.submit()
|
||||
completion.wait()
|
||||
return int(completion.results["err"])
|
198
tests/unit/tests/engine/engine_common.c/prepare_clines_hit.c
Normal file
198
tests/unit/tests/engine/engine_common.c/prepare_clines_hit.c
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* <tested_file_path>src/engine/engine_common.c</tested_file_path>
|
||||
* <tested_function>ocf_prepare_clines_hit</tested_function>
|
||||
* <functions_to_leave>
|
||||
* INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE
|
||||
* ONE FUNCTION PER LINE
|
||||
* </functions_to_leave>
|
||||
*/
|
||||
|
||||
#undef static
|
||||
|
||||
#undef inline
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include "print_desc.h"
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
#include "../ocf_priv.h"
|
||||
#include "../ocf_cache_priv.h"
|
||||
#include "../ocf_queue_priv.h"
|
||||
#include "../ocf_freelist.h"
|
||||
#include "engine_common.h"
|
||||
#include "engine_debug.h"
|
||||
#include "../utils/utils_cache_line.h"
|
||||
#include "../ocf_request.h"
|
||||
#include "../utils/utils_cleaner.h"
|
||||
#include "../utils/utils_part.h"
|
||||
#include "../metadata/metadata.h"
|
||||
#include "../eviction/eviction.h"
|
||||
#include "../promotion/promotion.h"
|
||||
#include "../concurrency/ocf_concurrency.h"
|
||||
|
||||
#include "engine/engine_common.c/prepare_clines_miss_generated_wraps.c"
|
||||
|
||||
void __wrap_ocf_req_hash_unlock_rd(struct ocf_request *req)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_part_check_space(struct ocf_request *req,
|
||||
uint32_t *to_evict)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
int __wrap_lock_clines(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
function_called();
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_metadata_start_exclusive_access(
|
||||
struct ocf_metadata_lock *metadata_lock)
|
||||
{
|
||||
}
|
||||
|
||||
void __wrap_ocf_metadata_end_exclusive_access(
|
||||
struct ocf_metadata_lock *metadata_lock)
|
||||
{
|
||||
}
|
||||
|
||||
int __wrap_space_managment_evict_do(struct ocf_cache *cache,
|
||||
struct ocf_request *req, uint32_t evict_cline_no)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
bool __wrap_ocf_part_is_enabled(struct ocf_user_part *target_part)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
bool __wrap_ocf_engine_needs_repart(struct ocf_request *req)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_req_set_mapping_error(struct ocf_request *req)
|
||||
{
|
||||
function_called();
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test01(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Request is hit and part is enabled\n");
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_engine_needs_repart, false);
|
||||
|
||||
will_return(__wrap_lock_clines, 0);
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), 0);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test02(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Request is hit but part is disabled - tigger eviction\n");
|
||||
will_return(__wrap_ocf_part_is_enabled, false);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_DISABLED);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test03(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Request needs repart, part has enough of a free space\n");
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_engine_needs_repart, true);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_HAS_SPACE);
|
||||
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
will_return(__wrap_lock_clines, 0);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), 0);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test04(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Request needs repart, eviction fails\n");
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_engine_needs_repart, true);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_MISS);
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test05(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Request needs repart, eviction passed, no lock\n");
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_engine_needs_repart, true);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
will_return(__wrap_lock_clines, OCF_ERR_NO_LOCK);
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_hit_test06(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Partition is disabled, but has some cachelines assigned.\n");
|
||||
print_test_description("Trigger eviction and but don't lock cachelines\n");
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, false);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, false);
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_hit(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test01),
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test02),
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test03),
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test04),
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test05),
|
||||
cmocka_unit_test(ocf_prepare_clines_hit_test06)
|
||||
};
|
||||
|
||||
print_message("Unit test for ocf_prepare_clines_hit\n");
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
263
tests/unit/tests/engine/engine_common.c/prepare_clines_miss.c
Normal file
263
tests/unit/tests/engine/engine_common.c/prepare_clines_miss.c
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* <tested_file_path>src/engine/engine_common.c</tested_file_path>
|
||||
* <tested_function>ocf_prepare_clines_miss</tested_function>
|
||||
* <functions_to_leave>
|
||||
* INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE
|
||||
* ONE FUNCTION PER LINE
|
||||
* </functions_to_leave>
|
||||
*/
|
||||
|
||||
#undef static
|
||||
|
||||
#undef inline
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include "print_desc.h"
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
#include "../ocf_priv.h"
|
||||
#include "../ocf_cache_priv.h"
|
||||
#include "../ocf_queue_priv.h"
|
||||
#include "../ocf_freelist.h"
|
||||
#include "engine_common.h"
|
||||
#include "engine_debug.h"
|
||||
#include "../utils/utils_cache_line.h"
|
||||
#include "../ocf_request.h"
|
||||
#include "../utils/utils_cleaner.h"
|
||||
#include "../utils/utils_part.h"
|
||||
#include "../metadata/metadata.h"
|
||||
#include "../eviction/eviction.h"
|
||||
#include "../promotion/promotion.h"
|
||||
#include "../concurrency/ocf_concurrency.h"
|
||||
|
||||
#include "engine/engine_common.c/prepare_clines_miss_generated_wraps.c"
|
||||
|
||||
void __wrap_ocf_req_hash_lock_upgrade(struct ocf_request *req)
|
||||
{
|
||||
}
|
||||
|
||||
void __wrap_ocf_req_hash_unlock_wr(struct ocf_request *req)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_part_check_space(struct ocf_request *req,
|
||||
uint32_t *to_evict)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
int __wrap_lock_clines(struct ocf_request *req,
|
||||
const struct ocf_engine_callbacks *engine_cbs)
|
||||
{
|
||||
function_called();
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_metadata_start_exclusive_access(
|
||||
struct ocf_metadata_lock *metadata_lock)
|
||||
{
|
||||
}
|
||||
|
||||
void __wrap_ocf_metadata_end_exclusive_access(
|
||||
struct ocf_metadata_lock *metadata_lock)
|
||||
{
|
||||
}
|
||||
|
||||
int __wrap_space_managment_evict_do(struct ocf_cache *cache,
|
||||
struct ocf_request *req, uint32_t evict_cline_no)
|
||||
{
|
||||
function_called();
|
||||
return mock();
|
||||
}
|
||||
|
||||
bool __wrap_ocf_part_is_enabled(struct ocf_user_part *target_part)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_engine_map(struct ocf_request *req)
|
||||
{
|
||||
function_called();
|
||||
}
|
||||
|
||||
bool __wrap_ocf_req_test_mapping_error(struct ocf_request *req)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_req_set_mapping_error(struct ocf_request *req)
|
||||
{
|
||||
function_called();
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test01(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is disabled and empty\n");
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_DISABLED);
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test02(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is disabled but has cachelines assigned.\n");
|
||||
print_test_description("\tTrigger eviction and mark mapping error\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_MAPPED);
|
||||
will_return(__wrap_ocf_part_is_enabled, false);
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test03(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled but doesn't have enough space.\n");
|
||||
print_test_description("\tEviction is ok and cachelines lock is acquired.\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_MAPPED);
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
|
||||
will_return(__wrap_ocf_req_test_mapping_error, false);
|
||||
|
||||
will_return(__wrap_lock_clines, 0);
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), 0);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test04(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled but doesn't have enough space.\n");
|
||||
print_test_description("\tEviction failed\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_MISS);
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test05(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled but doesn't have enough space.\n");
|
||||
print_test_description("Eviction is ok, but mapping failed.\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
will_return(__wrap_ocf_req_test_mapping_error, true);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test06(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled but doesn't have enough space.\n");
|
||||
print_test_description("Eviction and mapping were ok, but failed to lock cachelines.\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
will_return(__wrap_ocf_req_test_mapping_error, false);
|
||||
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
will_return(__wrap_lock_clines, -OCF_ERR_NO_LOCK);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_mapping_error);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), -OCF_ERR_NO_LOCK);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test07(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled but doesn't have enough space.\n");
|
||||
print_test_description("Eviction and mapping were ok, lock not acquired.\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_IS_FULL);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
will_return(__wrap_ocf_req_test_mapping_error, false);
|
||||
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
will_return(__wrap_lock_clines, OCF_LOCK_NOT_ACQUIRED);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), OCF_LOCK_NOT_ACQUIRED);
|
||||
}
|
||||
|
||||
static void ocf_prepare_clines_miss_test08(void **state)
|
||||
{
|
||||
struct ocf_request req = {};
|
||||
print_test_description("Target part is enabled has enough space.\n");
|
||||
print_test_description("\tMapping and cacheline lock are both ok\n");
|
||||
|
||||
will_return(__wrap_ocf_part_check_space, OCF_PART_HAS_SPACE);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
will_return(__wrap_ocf_req_test_mapping_error, false);
|
||||
|
||||
expect_function_call(__wrap_lock_clines);
|
||||
will_return(__wrap_lock_clines, OCF_LOCK_ACQUIRED);
|
||||
|
||||
assert_int_equal(ocf_prepare_clines_miss(&req, NULL), OCF_LOCK_ACQUIRED);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test01),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test02),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test03),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test04),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test05),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test06),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test07),
|
||||
cmocka_unit_test(ocf_prepare_clines_miss_test08)
|
||||
};
|
||||
|
||||
print_message("Unit test for ocf_prepare_clines_miss\n");
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
516
tests/unit/tests/utils/utils_part.c/ocf_part_evict_size.c
Normal file
516
tests/unit/tests/utils/utils_part.c/ocf_part_evict_size.c
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* <tested_file_path>src/utils/utils_part.c</tested_file_path>
|
||||
* <tested_function>ocf_part_evict_size</tested_function>
|
||||
* <functions_to_leave>
|
||||
* INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE
|
||||
* ONE FUNCTION PER LINE
|
||||
* </functions_to_leave>
|
||||
*/
|
||||
|
||||
#undef static
|
||||
|
||||
#undef inline
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include "print_desc.h"
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
#include "../ocf_cache_priv.h"
|
||||
#include "../ocf_request.h"
|
||||
#include "../metadata/metadata.h"
|
||||
#include "../engine/cache_engine.h"
|
||||
#include "../eviction/ops.h"
|
||||
#include "utils_part.h"
|
||||
|
||||
#include "utils/utils_part.c/ocf_part_evict_size_generated_wraps.c"
|
||||
|
||||
uint32_t __wrap_ocf_part_get_max_size(ocf_cache_t cache,
|
||||
struct ocf_user_part *target_part)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_engine_repart_count(struct ocf_request *req)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_engine_unmapped_count(struct ocf_request *req)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_part_get_occupancy(struct ocf_user_part *target_part)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
ocf_cache_line_t __wrap_ocf_freelist_num_free(ocf_freelist_t freelist)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
|
||||
void __wrap_ocf_req_set_part_evict(struct ocf_request *req)
|
||||
{
|
||||
function_called();
|
||||
}
|
||||
|
||||
void __wrap_ocf_req_clear_part_evict(struct ocf_request *req)
|
||||
{
|
||||
function_called();
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test01(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 512;
|
||||
uint32_t freelist_size = 500;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
print_test_description("Enough free space available");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
// Enough free cachelines to map a whole request
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), 0);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test02(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 960;
|
||||
uint32_t freelist_size = 500;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t available_cachelines = max_part_size - part_occupied_cachelines;
|
||||
uint32_t cachelines_to_evict = cachelines_to_map - available_cachelines;
|
||||
|
||||
print_test_description("Cache has enough free cachelines,"
|
||||
" but target partition must be evicted");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test03(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 320;
|
||||
uint32_t cachelines_to_map = 0;
|
||||
uint32_t part_occupied_cachelines = 512;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict = 0;
|
||||
|
||||
print_test_description("Only repart (no mapping). Freelist is empty but "
|
||||
"space in a target part is availabe,");
|
||||
print_test_description("\tso no cachelines should be "
|
||||
" evcited from cache");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test04(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 320;
|
||||
uint32_t cachelines_to_map = 0;
|
||||
uint32_t part_occupied_cachelines = 1100;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_debt = part_occupied_cachelines - max_part_size;
|
||||
uint32_t cachelines_to_evict = cachelines_to_repart + cachelines_debt;
|
||||
|
||||
print_test_description("Only repart (no mapping). Freelist is empty and no"
|
||||
" space in target part is availabe.");
|
||||
print_test_description("\tEvict only from target partition");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test05(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 960;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t available_cachelines = max_part_size - part_occupied_cachelines;
|
||||
uint32_t cachelines_to_evict = cachelines_to_map - available_cachelines;
|
||||
|
||||
print_test_description("Freelist is empty and no space in the target part "
|
||||
"is available");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test06(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 320;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t available_cachelines = max_part_size - part_occupied_cachelines;
|
||||
uint32_t cachelines_to_evict = cachelines_to_map;
|
||||
|
||||
print_test_description("Freelist is empty but target part has enough space");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_clear_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test07(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 1280;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t debt_cachelines = part_occupied_cachelines - max_part_size;
|
||||
uint32_t cachelines_to_evict = cachelines_to_map + debt_cachelines;
|
||||
|
||||
print_test_description("Freelist is empty and part occupancy exceeded");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req),
|
||||
(part_occupied_cachelines - max_part_size) + cachelines_to_map);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test08(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 320;
|
||||
uint32_t cachelines_to_map = 0;
|
||||
uint32_t part_occupied_cachelines = 1280;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t debt_cachelines = part_occupied_cachelines - max_part_size;
|
||||
uint32_t cachelines_to_evict = debt_cachelines + cachelines_to_repart;
|
||||
|
||||
print_test_description("Target part occupancy limit is exceeded during "
|
||||
"repart");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req),
|
||||
(part_occupied_cachelines - max_part_size) + cachelines_to_repart);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test09(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 320;
|
||||
uint32_t cachelines_to_map = 0;
|
||||
uint32_t part_occupied_cachelines = 320;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict = 0;
|
||||
|
||||
print_test_description("Repart while target part has enough of available "
|
||||
"space");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test10(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 320;
|
||||
uint32_t freelist_size = 320;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict = 0;
|
||||
|
||||
print_test_description("Enough of available cachelines in target part, "
|
||||
"freelist has exactly required number of free cachelines");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test11(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 1024;
|
||||
uint32_t cachelines_to_repart = 320;
|
||||
uint32_t cachelines_to_map = 0;
|
||||
uint32_t part_occupied_cachelines = 384;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict = 0;
|
||||
|
||||
print_test_description("Number of cachelines to repart is equal to number "
|
||||
"of cachelines available in the target partition");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
assert_int_equal(ocf_part_evict_size(&req), cachelines_to_evict);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test12(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 0;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 384;
|
||||
uint32_t freelist_size = 0;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict =
|
||||
part_occupied_cachelines + cachelines_to_map;
|
||||
|
||||
print_test_description("Freelist IS empty. Max occupancy set to 0, but "
|
||||
"some cachelines are still assigned to traget part - evict them");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_true(ocf_part_evict_size(&req) >= part_occupied_cachelines);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
static void ocf_part_evict_size_test13(void **state)
|
||||
{
|
||||
uint32_t max_part_size = 0;
|
||||
uint32_t cachelines_to_repart = 0;
|
||||
uint32_t cachelines_to_map = 320;
|
||||
uint32_t part_occupied_cachelines = 384;
|
||||
uint32_t freelist_size = 1024;
|
||||
|
||||
struct ocf_request req;
|
||||
req.cache = test_malloc(sizeof(struct ocf_cache));
|
||||
|
||||
uint32_t cachelines_to_evict =
|
||||
part_occupied_cachelines + cachelines_to_map;
|
||||
|
||||
print_test_description("Freelist IS NOT empty. Max occupancy set to 0, but"
|
||||
" some cachelines are still assigned to traget part - evict them");
|
||||
|
||||
will_return(__wrap_ocf_part_get_max_size, max_part_size);
|
||||
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
will_return(__wrap_ocf_engine_repart_count, cachelines_to_repart);
|
||||
|
||||
will_return(__wrap_ocf_part_get_occupancy, part_occupied_cachelines);
|
||||
|
||||
will_return(__wrap_ocf_freelist_num_free, freelist_size);
|
||||
will_return(__wrap_ocf_engine_unmapped_count, cachelines_to_map);
|
||||
|
||||
expect_function_call(__wrap_ocf_req_set_part_evict);
|
||||
|
||||
assert_true(ocf_part_evict_size(&req) >= part_occupied_cachelines);
|
||||
|
||||
test_free(req.cache);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(ocf_part_evict_size_test01),
|
||||
cmocka_unit_test(ocf_part_evict_size_test02),
|
||||
cmocka_unit_test(ocf_part_evict_size_test03),
|
||||
cmocka_unit_test(ocf_part_evict_size_test04),
|
||||
cmocka_unit_test(ocf_part_evict_size_test05),
|
||||
cmocka_unit_test(ocf_part_evict_size_test06),
|
||||
cmocka_unit_test(ocf_part_evict_size_test07),
|
||||
cmocka_unit_test(ocf_part_evict_size_test08),
|
||||
cmocka_unit_test(ocf_part_evict_size_test09),
|
||||
cmocka_unit_test(ocf_part_evict_size_test10),
|
||||
cmocka_unit_test(ocf_part_evict_size_test11),
|
||||
cmocka_unit_test(ocf_part_evict_size_test12),
|
||||
cmocka_unit_test(ocf_part_evict_size_test13)
|
||||
};
|
||||
|
||||
print_message("Unit test for ocf_part_evict_size\n");
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
Loading…
Reference in New Issue
Block a user