Merge pull request #451 from arutk/exact_evict_count
only request evict size equal to request unmapped count
This commit is contained in:
commit
d03ea719cd
@ -430,55 +430,50 @@ static inline int ocf_prepare_clines_miss(struct ocf_request *req,
|
||||
{
|
||||
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;
|
||||
|
||||
/* requests to disabled partitions go in pass-through */
|
||||
if (!ocf_part_is_enabled(&req->cache->user_parts[req->part_id])) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
return lock_status;
|
||||
}
|
||||
|
||||
if (!ocf_part_has_space(req)) {
|
||||
ocf_req_hash_unlock_rd(req);
|
||||
goto eviction;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
ocf_engine_map(req);
|
||||
|
||||
if (!ocf_req_test_mapping_error(req)) {
|
||||
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);
|
||||
|
||||
eviction:
|
||||
ocf_metadata_start_exclusive_access(metadata_lock);
|
||||
|
||||
ocf_part_check_space(req, &clines_to_evict);
|
||||
/* repeat traversation to pick up latest metadata status */
|
||||
ocf_engine_traverse(req);
|
||||
|
||||
if (space_managment_evict_do(req->cache, req, clines_to_evict) ==
|
||||
LOOKUP_MISS) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
if (!ocf_part_has_space(req))
|
||||
ocf_req_set_part_evict(req);
|
||||
else
|
||||
ocf_req_clear_part_evict(req);
|
||||
|
||||
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 */
|
||||
if (space_managment_evict_do(req->cache, req,
|
||||
ocf_engine_unmapped_count(req)) == LOOKUP_MISS) {
|
||||
ocf_req_set_mapping_error(req);
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ int ocf_read_fast(struct ocf_request *req)
|
||||
{
|
||||
bool hit;
|
||||
int lock = OCF_LOCK_NOT_ACQUIRED;
|
||||
bool part_has_space = false;
|
||||
bool part_has_space;
|
||||
|
||||
/* Get OCF request - increase reference counter */
|
||||
ocf_req_get(req);
|
||||
@ -126,8 +126,7 @@ int ocf_read_fast(struct ocf_request *req)
|
||||
|
||||
hit = ocf_engine_is_hit(req);
|
||||
|
||||
if (ocf_part_check_space(req, NULL) == OCF_PART_HAS_SPACE)
|
||||
part_has_space = true;
|
||||
part_has_space = ocf_part_has_space(req);
|
||||
|
||||
if (hit && part_has_space) {
|
||||
ocf_io_start(&req->ioi.io);
|
||||
@ -197,8 +196,7 @@ int ocf_write_fast(struct ocf_request *req)
|
||||
|
||||
mapped = ocf_engine_is_mapped(req);
|
||||
|
||||
if (ocf_part_check_space(req, NULL) == OCF_PART_HAS_SPACE)
|
||||
part_has_space = true;
|
||||
part_has_space = ocf_part_has_space(req);
|
||||
|
||||
if (mapped && part_has_space) {
|
||||
ocf_io_start(&req->ioi.io);
|
||||
|
@ -60,53 +60,92 @@ static inline uint32_t ocf_evict_part_do(ocf_cache_t cache,
|
||||
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)
|
||||
static inline uint32_t ocf_evict_partitions(ocf_cache_t cache,
|
||||
ocf_queue_t io_queue, uint32_t evict_cline_no,
|
||||
bool overflown_only, uint32_t max_priority)
|
||||
{
|
||||
uint32_t to_evict = 0, evicted = 0;
|
||||
struct ocf_user_part *part;
|
||||
ocf_part_id_t part_id;
|
||||
unsigned overflow_size;
|
||||
|
||||
/* For each partition from the lowest priority to highest one */
|
||||
for_each_part(cache, part, part_id) {
|
||||
|
||||
if (!ocf_eviction_can_evict(cache))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Check stop and continue conditions
|
||||
*/
|
||||
if (target_part->config->priority > part->config->priority) {
|
||||
if (max_priority > part->config->priority) {
|
||||
/*
|
||||
* iterate partition have higher priority, do not evict
|
||||
* iterate partition have higher priority,
|
||||
* do not evict
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (!part->config->flags.eviction) {
|
||||
/* It seams that no more partition for eviction */
|
||||
/* no more partitions available for viction
|
||||
*/
|
||||
break;
|
||||
}
|
||||
if (evicted >= evict_cline_no) {
|
||||
/* Evicted requested number of cache line, stop */
|
||||
goto out;
|
||||
|
||||
if (overflown_only) {
|
||||
overflow_size = ocf_part_overflow_size(cache, part);
|
||||
if (overflow_size == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
to_evict = ocf_evict_calculate(cache, part, evict_cline_no,
|
||||
true);
|
||||
to_evict = ocf_evict_calculate(cache, part,
|
||||
evict_cline_no - evicted, true);
|
||||
if (to_evict == 0) {
|
||||
/* No cache lines to evict for this partition */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (overflown_only)
|
||||
to_evict = OCF_MIN(to_evict, overflow_size);
|
||||
|
||||
evicted += ocf_eviction_need_space(cache, io_queue,
|
||||
part, to_evict);
|
||||
|
||||
if (evicted >= evict_cline_no) {
|
||||
/* Evicted requested number of cache line, stop
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
return evicted;
|
||||
}
|
||||
|
||||
static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
||||
ocf_queue_t io_queue, uint32_t evict_cline_no,
|
||||
struct ocf_user_part *target_part)
|
||||
{
|
||||
uint32_t evicted;
|
||||
|
||||
/* First attempt to evict overflown partitions in order to
|
||||
* achieve configured maximum size. Ignoring partitions
|
||||
* priority in this case, as overflown partitions should
|
||||
* free its cachelines regardless of destination partition
|
||||
* priority. */
|
||||
evicted = ocf_evict_partitions(cache, io_queue, evict_cline_no,
|
||||
true, OCF_IO_CLASS_PRIO_HIGHEST);
|
||||
if (evicted >= evict_cline_no)
|
||||
return evicted;
|
||||
/* Not enough cachelines in overflown partitions. Go through
|
||||
* partitions with priority <= target partition and attempt
|
||||
* to evict from those. */
|
||||
evict_cline_no -= evicted;
|
||||
evicted += ocf_evict_partitions(cache, io_queue, evict_cline_no,
|
||||
false, target_part->config->priority);
|
||||
|
||||
return evicted;
|
||||
}
|
||||
|
||||
int space_managment_evict_do(struct ocf_cache *cache,
|
||||
struct ocf_request *req, uint32_t evict_cline_no)
|
||||
{
|
||||
|
@ -190,82 +190,3 @@ 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;
|
||||
}
|
||||
|
@ -100,20 +100,29 @@ 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 uint32_t ocf_part_overflow_size(struct ocf_cache *cache,
|
||||
struct ocf_user_part *part)
|
||||
{
|
||||
uint32_t part_occupancy = ocf_part_get_occupancy(part);
|
||||
uint32_t part_occupancy_limit = ocf_part_get_max_size(cache, part);
|
||||
|
||||
if (part_occupancy > part_occupancy_limit)
|
||||
return part_occupancy - part_occupancy_limit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool ocf_part_has_space(struct ocf_request *req)
|
||||
{
|
||||
struct ocf_user_part *target_part = &req->cache->user_parts[req->part_id];
|
||||
uint64_t part_occupancy_limit =
|
||||
ocf_part_get_max_size(req->cache, target_part);
|
||||
uint64_t needed_cache_lines = ocf_engine_repart_count(req) +
|
||||
ocf_engine_unmapped_count(req);
|
||||
uint64_t part_occupancy = ocf_part_get_occupancy(target_part);
|
||||
|
||||
return (part_occupancy + needed_cache_lines <= part_occupancy_limit);
|
||||
}
|
||||
|
||||
static inline ocf_cache_mode_t ocf_part_get_cache_mode(ocf_cache_t cache,
|
||||
ocf_part_id_t part_id)
|
||||
|
@ -44,8 +44,7 @@ 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)
|
||||
uint32_t __wrap_ocf_part_has_space(struct ocf_request *req)
|
||||
{
|
||||
return mock();
|
||||
}
|
||||
@ -98,7 +97,7 @@ 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);
|
||||
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);
|
||||
}
|
||||
@ -107,13 +106,8 @@ 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");
|
||||
print_test_description("\tMark 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);
|
||||
|
||||
@ -126,12 +120,12 @@ static void ocf_prepare_clines_miss_test03(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
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);
|
||||
|
||||
@ -149,9 +143,10 @@ static void ocf_prepare_clines_miss_test04(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
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);
|
||||
@ -165,8 +160,8 @@ static void ocf_prepare_clines_miss_test05(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
@ -185,8 +180,8 @@ static void ocf_prepare_clines_miss_test06(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
@ -210,8 +205,8 @@ static void ocf_prepare_clines_miss_test07(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
will_return(__wrap_ocf_part_has_space, false);
|
||||
|
||||
expect_function_call(__wrap_space_managment_evict_do);
|
||||
will_return(__wrap_space_managment_evict_do, LOOKUP_HIT);
|
||||
@ -233,7 +228,8 @@ static void ocf_prepare_clines_miss_test08(void **state)
|
||||
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);
|
||||
will_return(__wrap_ocf_part_is_enabled, true);
|
||||
will_return(__wrap_ocf_part_has_space, true);
|
||||
|
||||
expect_function_call(__wrap_ocf_engine_map);
|
||||
will_return(__wrap_ocf_req_test_mapping_error, false);
|
||||
|
291
tests/unit/tests/eviction/eviction.c/eviction.c
Normal file
291
tests/unit/tests/eviction/eviction.c/eviction.c
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* <tested_file_path>src/eviction/eviction.c</tested_file_path>
|
||||
* <tested_function>ocf_evict_do</tested_function>
|
||||
* <functions_to_leave>
|
||||
ocf_evict_partitions
|
||||
* </functions_to_leave>
|
||||
*/
|
||||
|
||||
#undef static
|
||||
|
||||
#undef inline
|
||||
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include "print_desc.h"
|
||||
|
||||
#include "eviction.h"
|
||||
#include "ops.h"
|
||||
#include "../utils/utils_part.h"
|
||||
|
||||
#include "eviction/eviction.c/eviction_generated_wraps.c"
|
||||
|
||||
struct test_cache
|
||||
{
|
||||
struct ocf_cache cache;
|
||||
struct ocf_user_part_config part[OCF_IO_CLASS_MAX];
|
||||
struct ocf_user_part upart[OCF_IO_CLASS_MAX];
|
||||
uint32_t overflow[OCF_IO_CLASS_MAX];
|
||||
uint32_t evictable[OCF_IO_CLASS_MAX];
|
||||
};
|
||||
|
||||
bool __wrap_ocf_eviction_can_evict(ocf_cache_t cache)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_part_overflow_size(struct ocf_cache *cache,
|
||||
struct ocf_user_part *part)
|
||||
{
|
||||
struct test_cache* tcache = cache;
|
||||
|
||||
return tcache->overflow[part->id];
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_evict_calculate(ocf_cache_t cache,
|
||||
struct ocf_user_part *part, uint32_t to_evict, bool roundup)
|
||||
{
|
||||
struct test_cache* tcache = cache;
|
||||
|
||||
return min(tcache->evictable[part->id], to_evict);
|
||||
}
|
||||
|
||||
uint32_t __wrap_ocf_eviction_need_space(struct ocf_cache *cache,
|
||||
ocf_queue_t io_queue, struct ocf_user_part *part,
|
||||
uint32_t clines)
|
||||
{
|
||||
struct test_cache *tcache = (struct test_cache *)cache;
|
||||
unsigned overflown_consumed = min(clines, tcache->overflow[part->id]);
|
||||
|
||||
tcache->overflow[part->id] -= overflown_consumed;
|
||||
tcache->evictable[part->id] -= clines;
|
||||
|
||||
check_expected(part);
|
||||
check_expected(clines);
|
||||
function_called();
|
||||
return mock();
|
||||
}
|
||||
|
||||
int __wrap_ocf_log_raw(ocf_logger_t logger, ocf_logger_lvl_t lvl,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
int __wrap_ocf_log_stack_trace_raw(ocf_logger_t logger)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ocf_ctx_t __wrap_ocf_cache_get_ctx(ocf_cache_t cache)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool ocf_cache_is_device_attached(ocf_cache_t cache)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: copy-pasted from OCF */
|
||||
int ocf_part_lst_cmp_valid(struct ocf_cache *cache,
|
||||
struct ocf_lst_entry *e1, struct ocf_lst_entry *e2)
|
||||
{
|
||||
struct ocf_user_part *p1 = container_of(e1, struct ocf_user_part,
|
||||
lst_valid);
|
||||
struct ocf_user_part *p2 = container_of(e2, struct ocf_user_part,
|
||||
lst_valid);
|
||||
size_t p1_size = ocf_cache_is_device_attached(cache) ?
|
||||
p1->runtime->curr_size : 0;
|
||||
size_t p2_size = ocf_cache_is_device_attached(cache) ?
|
||||
p2->runtime->curr_size : 0;
|
||||
|
||||
int v1 = p1->config->priority;
|
||||
int v2 = p2->config->priority;
|
||||
|
||||
/*
|
||||
* If partition is invalid the priority depends on current size:
|
||||
* 1. Partition is empty - move to the end of list
|
||||
* 2. Partition is not empty - move to the beginning of the list. This
|
||||
* partition will be evicted first
|
||||
*/
|
||||
|
||||
if (p1->config->priority == OCF_IO_CLASS_PRIO_PINNED)
|
||||
p1->config->flags.eviction = false;
|
||||
else
|
||||
p1->config->flags.eviction = true;
|
||||
|
||||
if (p2->config->priority == OCF_IO_CLASS_PRIO_PINNED)
|
||||
p2->config->flags.eviction = false;
|
||||
else
|
||||
p2->config->flags.eviction = true;
|
||||
|
||||
if (!p1->config->flags.valid) {
|
||||
if (p1_size) {
|
||||
v1 = SHRT_MAX;
|
||||
p1->config->flags.eviction = true;
|
||||
} else {
|
||||
v1 = SHRT_MIN;
|
||||
p1->config->flags.eviction = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!p2->config->flags.valid) {
|
||||
if (p2_size) {
|
||||
v2 = SHRT_MAX;
|
||||
p2->config->flags.eviction = true;
|
||||
} else {
|
||||
v2 = SHRT_MIN;
|
||||
p2->config->flags.eviction = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (v1 == v2) {
|
||||
v1 = p1 - cache->user_parts;
|
||||
v2 = p2 - cache->user_parts;
|
||||
}
|
||||
|
||||
return v2 - v1;
|
||||
}
|
||||
|
||||
static struct ocf_lst_entry *_list_getter(
|
||||
struct ocf_cache *cache, ocf_cache_line_t idx)
|
||||
{
|
||||
struct test_cache* tcache = cache;
|
||||
|
||||
return &tcache->upart[idx].lst_valid;
|
||||
}
|
||||
|
||||
static void init_part_list(struct test_cache *tcache)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < OCF_IO_CLASS_MAX; i++) {
|
||||
tcache->upart[i].id = i;
|
||||
tcache->upart[i].config = &tcache->part[i];
|
||||
tcache->upart[i].config->priority = i+1;
|
||||
tcache->upart[i].config->flags.eviction = 1;
|
||||
}
|
||||
|
||||
ocf_lst_init((ocf_cache_t)tcache, &tcache->cache.lst_part, OCF_IO_CLASS_MAX,
|
||||
_list_getter, ocf_part_lst_cmp_valid);
|
||||
for (i = 0; i < OCF_IO_CLASS_MAX; i++) {
|
||||
ocf_lst_init_entry(&tcache->cache.lst_part, &tcache->upart[i].lst_valid);
|
||||
ocf_lst_add_tail(&tcache->cache.lst_part, i);
|
||||
}
|
||||
}
|
||||
|
||||
#define _expect_evict_call(tcache, part_id, req_count, ret_count) \
|
||||
do { \
|
||||
expect_value(__wrap_ocf_eviction_need_space, part, &tcache.upart[part_id]); \
|
||||
expect_value(__wrap_ocf_eviction_need_space, clines, req_count); \
|
||||
expect_function_call(__wrap_ocf_eviction_need_space); \
|
||||
will_return(__wrap_ocf_eviction_need_space, ret_count); \
|
||||
} while (false);
|
||||
|
||||
static void ocf_evict_do_test01(void **state)
|
||||
{
|
||||
struct test_cache tcache = {};
|
||||
unsigned evicted;
|
||||
|
||||
print_test_description("one IO class, no overflow\n");
|
||||
|
||||
init_part_list(&tcache);
|
||||
|
||||
tcache.evictable[10] = 100;
|
||||
|
||||
_expect_evict_call(tcache, 10, 50, 50);
|
||||
|
||||
evicted = ocf_evict_do((ocf_cache_t *)&tcache, NULL, 50, &tcache.upart[0]);
|
||||
assert_int_equal(evicted, 50);
|
||||
}
|
||||
|
||||
static void ocf_evict_do_test02(void **state)
|
||||
{
|
||||
struct test_cache tcache = {};
|
||||
unsigned i;
|
||||
unsigned evicted;
|
||||
|
||||
print_test_description("one overflown IO class\n");
|
||||
|
||||
init_part_list(&tcache);
|
||||
|
||||
tcache.evictable[10] = 100;
|
||||
tcache.overflow[10] = 100;
|
||||
|
||||
_expect_evict_call(tcache, 10, 50, 50);
|
||||
|
||||
evicted = ocf_evict_do((ocf_cache_t *)&tcache, NULL, 50, &tcache.upart[0]);
|
||||
assert_int_equal(evicted, 50);
|
||||
}
|
||||
|
||||
static void ocf_evict_do_test03(void **state)
|
||||
{
|
||||
struct test_cache tcache = {};
|
||||
unsigned i;
|
||||
unsigned evicted;
|
||||
|
||||
print_test_description("multiple non-overflown IO class\n");
|
||||
|
||||
init_part_list(&tcache);
|
||||
|
||||
tcache.evictable[10] = 100;
|
||||
tcache.evictable[12] = 100;
|
||||
tcache.evictable[16] = 100;
|
||||
tcache.evictable[17] = 100;
|
||||
|
||||
_expect_evict_call(tcache, 10, 100, 100);
|
||||
_expect_evict_call(tcache, 12, 100, 100);
|
||||
_expect_evict_call(tcache, 16, 100, 100);
|
||||
_expect_evict_call(tcache, 17, 50, 50);
|
||||
|
||||
evicted = ocf_evict_do((ocf_cache_t *)&tcache, NULL, 350, &tcache.upart[0]);
|
||||
assert_int_equal(evicted, 350);
|
||||
}
|
||||
|
||||
static void ocf_evict_do_test04(void **state)
|
||||
{
|
||||
struct test_cache tcache = {};
|
||||
unsigned i;
|
||||
unsigned evicted;
|
||||
|
||||
print_test_description("multiple IO class with and without overflow\n");
|
||||
|
||||
init_part_list(&tcache);
|
||||
|
||||
tcache.evictable[10] = 100;
|
||||
tcache.evictable[12] = 100;
|
||||
tcache.overflow[12] = 40;
|
||||
tcache.evictable[14] = 100;
|
||||
tcache.overflow[14] = 100;
|
||||
tcache.evictable[16] = 100;
|
||||
tcache.evictable[17] = 100;
|
||||
tcache.evictable[18] = 100;
|
||||
tcache.overflow[18] = 100;
|
||||
|
||||
_expect_evict_call(tcache, 12, 40, 40);
|
||||
_expect_evict_call(tcache, 14, 100, 100);
|
||||
_expect_evict_call(tcache, 18, 100, 100);
|
||||
_expect_evict_call(tcache, 10, 100, 100);
|
||||
_expect_evict_call(tcache, 12, 60, 60);
|
||||
_expect_evict_call(tcache, 16, 100, 100);
|
||||
_expect_evict_call(tcache, 17, 80, 80);
|
||||
|
||||
evicted = ocf_evict_do((ocf_cache_t *)&tcache, NULL, 580, &tcache.upart[0]);
|
||||
assert_int_equal(evicted, 580);
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
const struct CMUnitTest tests[] = {
|
||||
cmocka_unit_test(ocf_evict_do_test01),
|
||||
cmocka_unit_test(ocf_evict_do_test02),
|
||||
cmocka_unit_test(ocf_evict_do_test03),
|
||||
cmocka_unit_test(ocf_evict_do_test04)
|
||||
};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
@ -1,516 +0,0 @@
|
||||
/*
|
||||
* <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