commit
3acbe657c5
@ -9,19 +9,23 @@
|
|||||||
int ocf_metadata_concurrency_init(struct ocf_metadata_lock *metadata_lock)
|
int ocf_metadata_concurrency_init(struct ocf_metadata_lock *metadata_lock)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned i;
|
unsigned evp_iter;
|
||||||
|
unsigned part_iter;
|
||||||
|
|
||||||
err = env_spinlock_init(&metadata_lock->eviction);
|
for (evp_iter = 0; evp_iter < OCF_NUM_EVICTION_LISTS; evp_iter++) {
|
||||||
if (err)
|
err = env_spinlock_init(&metadata_lock->eviction[evp_iter]);
|
||||||
return err;
|
if (err)
|
||||||
|
goto eviction_err;
|
||||||
|
}
|
||||||
|
|
||||||
env_rwlock_init(&metadata_lock->status);
|
env_rwlock_init(&metadata_lock->status);
|
||||||
|
|
||||||
err = env_rwsem_init(&metadata_lock->global);
|
err = env_rwsem_init(&metadata_lock->global);
|
||||||
if (err)
|
if (err)
|
||||||
goto rwsem_err;
|
goto rwsem_err;
|
||||||
|
|
||||||
for (i = 0; i < OCF_IO_CLASS_MAX; i++) {
|
for (part_iter = 0; part_iter < OCF_IO_CLASS_MAX; part_iter++) {
|
||||||
err = env_spinlock_init(&metadata_lock->partition[i]);
|
err = env_spinlock_init(&metadata_lock->partition[part_iter]);
|
||||||
if (err)
|
if (err)
|
||||||
goto spinlocks_err;
|
goto spinlocks_err;
|
||||||
}
|
}
|
||||||
@ -29,11 +33,15 @@ int ocf_metadata_concurrency_init(struct ocf_metadata_lock *metadata_lock)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
spinlocks_err:
|
spinlocks_err:
|
||||||
while (i--)
|
while (part_iter--)
|
||||||
env_spinlock_destroy(&metadata_lock->partition[i]);
|
env_spinlock_destroy(&metadata_lock->partition[part_iter]);
|
||||||
rwsem_err:
|
rwsem_err:
|
||||||
env_rwlock_destroy(&metadata_lock->status);
|
env_rwlock_destroy(&metadata_lock->status);
|
||||||
env_spinlock_destroy(&metadata_lock->eviction);
|
|
||||||
|
eviction_err:
|
||||||
|
while (evp_iter--)
|
||||||
|
env_spinlock_destroy(&metadata_lock->eviction[evp_iter]);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,11 +49,12 @@ void ocf_metadata_concurrency_deinit(struct ocf_metadata_lock *metadata_lock)
|
|||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
for (i = 0; i < OCF_IO_CLASS_MAX; i++) {
|
for (i = 0; i < OCF_IO_CLASS_MAX; i++)
|
||||||
env_spinlock_destroy(&metadata_lock->partition[i]);
|
env_spinlock_destroy(&metadata_lock->partition[i]);
|
||||||
}
|
|
||||||
|
|
||||||
env_spinlock_destroy(&metadata_lock->eviction);
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
env_spinlock_destroy(&metadata_lock->eviction[i]);
|
||||||
|
|
||||||
env_rwlock_destroy(&metadata_lock->status);
|
env_rwlock_destroy(&metadata_lock->status);
|
||||||
env_rwsem_destroy(&metadata_lock->global);
|
env_rwsem_destroy(&metadata_lock->global);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
*/
|
*/
|
||||||
#include "../ocf_cache_priv.h"
|
#include "../ocf_cache_priv.h"
|
||||||
|
#include "../eviction/eviction.h"
|
||||||
|
|
||||||
#ifndef __OCF_METADATA_CONCURRENCY_H__
|
#ifndef __OCF_METADATA_CONCURRENCY_H__
|
||||||
#define __OCF_METADATA_CONCURRENCY_H__
|
#define __OCF_METADATA_CONCURRENCY_H__
|
||||||
@ -22,17 +23,49 @@ void ocf_metadata_concurrency_attached_deinit(
|
|||||||
struct ocf_metadata_lock *metadata_lock);
|
struct ocf_metadata_lock *metadata_lock);
|
||||||
|
|
||||||
static inline void ocf_metadata_eviction_lock(
|
static inline void ocf_metadata_eviction_lock(
|
||||||
struct ocf_metadata_lock *metadata_lock)
|
struct ocf_metadata_lock *metadata_lock, unsigned ev_list)
|
||||||
{
|
{
|
||||||
env_spinlock_lock(&metadata_lock->eviction);
|
env_spinlock_lock(&metadata_lock->eviction[ev_list]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ocf_metadata_eviction_unlock(
|
static inline void ocf_metadata_eviction_unlock(
|
||||||
|
struct ocf_metadata_lock *metadata_lock, unsigned ev_list)
|
||||||
|
{
|
||||||
|
env_spinlock_unlock(&metadata_lock->eviction[ev_list]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ocf_metadata_eviction_lock_all(
|
||||||
struct ocf_metadata_lock *metadata_lock)
|
struct ocf_metadata_lock *metadata_lock)
|
||||||
{
|
{
|
||||||
env_spinlock_unlock(&metadata_lock->eviction);
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
ocf_metadata_eviction_lock(metadata_lock, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void ocf_metadata_eviction_unlock_all(
|
||||||
|
struct ocf_metadata_lock *metadata_lock)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
ocf_metadata_eviction_unlock(metadata_lock, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OCF_METADATA_EVICTION_LOCK(cline) \
|
||||||
|
ocf_metadata_eviction_lock(&cache->metadata.lock, \
|
||||||
|
cline % OCF_NUM_EVICTION_LISTS)
|
||||||
|
|
||||||
|
#define OCF_METADATA_EVICTION_UNLOCK(cline) \
|
||||||
|
ocf_metadata_eviction_unlock(&cache->metadata.lock, \
|
||||||
|
cline % OCF_NUM_EVICTION_LISTS)
|
||||||
|
|
||||||
|
#define OCF_METADATA_EVICTION_LOCK_ALL() \
|
||||||
|
ocf_metadata_eviction_lock_all(&cache->metadata.lock)
|
||||||
|
|
||||||
|
#define OCF_METADATA_EVICTION_UNLOCK_ALL() \
|
||||||
|
ocf_metadata_eviction_unlock_all(&cache->metadata.lock)
|
||||||
|
|
||||||
static inline void ocf_metadata_partition_lock(
|
static inline void ocf_metadata_partition_lock(
|
||||||
struct ocf_metadata_lock *metadata_lock,
|
struct ocf_metadata_lock *metadata_lock,
|
||||||
ocf_part_id_t part_id)
|
ocf_part_id_t part_id)
|
||||||
@ -47,12 +80,6 @@ static inline void ocf_metadata_partition_unlock(
|
|||||||
env_spinlock_unlock(&metadata_lock->partition[part_id]);
|
env_spinlock_unlock(&metadata_lock->partition[part_id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OCF_METADATA_EVICTION_LOCK() \
|
|
||||||
ocf_metadata_eviction_lock(&cache->metadata.lock)
|
|
||||||
|
|
||||||
#define OCF_METADATA_EVICTION_UNLOCK() \
|
|
||||||
ocf_metadata_eviction_unlock(&cache->metadata.lock)
|
|
||||||
|
|
||||||
void ocf_metadata_start_exclusive_access(
|
void ocf_metadata_start_exclusive_access(
|
||||||
struct ocf_metadata_lock *metadata_lock);
|
struct ocf_metadata_lock *metadata_lock);
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ static void ocf_engine_map_cache_line(struct ocf_request *req,
|
|||||||
*cache_line);
|
*cache_line);
|
||||||
ocf_metadata_end_collision_shared_access(cache, *cache_line);
|
ocf_metadata_end_collision_shared_access(cache, *cache_line);
|
||||||
|
|
||||||
ocf_eviction_init_cache_line(cache, *cache_line, part_id);
|
ocf_eviction_init_cache_line(cache, *cache_line);
|
||||||
|
|
||||||
/* Update LRU:: Move this node to head of lru list. */
|
/* Update LRU:: Move this node to head of lru list. */
|
||||||
ocf_eviction_set_hot_cache_line(cache, *cache_line);
|
ocf_eviction_set_hot_cache_line(cache, *cache_line);
|
||||||
|
@ -42,11 +42,10 @@ static uint32_t ocf_evict_calculate(struct ocf_user_part *part,
|
|||||||
|
|
||||||
static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
||||||
ocf_queue_t io_queue, const uint32_t evict_cline_no,
|
ocf_queue_t io_queue, const uint32_t evict_cline_no,
|
||||||
ocf_part_id_t target_part_id)
|
struct ocf_user_part *target_part)
|
||||||
{
|
{
|
||||||
uint32_t to_evict = 0, evicted = 0;
|
uint32_t to_evict = 0, evicted = 0;
|
||||||
struct ocf_user_part *part;
|
struct ocf_user_part *part;
|
||||||
struct ocf_user_part *target_part = &cache->user_parts[target_part_id];
|
|
||||||
ocf_part_id_t part_id;
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
/* For each partition from the lowest priority to highest one */
|
/* For each partition from the lowest priority to highest one */
|
||||||
@ -68,7 +67,7 @@ static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
|||||||
/* It seams that no more partition for eviction */
|
/* It seams that no more partition for eviction */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (part_id == target_part_id) {
|
if (part_id == target_part->id) {
|
||||||
/* Omit targeted, evict from different first */
|
/* Omit targeted, evict from different first */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -84,7 +83,7 @@ static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
evicted += ocf_eviction_need_space(cache, io_queue,
|
evicted += ocf_eviction_need_space(cache, io_queue,
|
||||||
part_id, to_evict);
|
part, to_evict);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ocf_eviction_can_evict(cache))
|
if (!ocf_eviction_can_evict(cache))
|
||||||
@ -95,7 +94,7 @@ static inline uint32_t ocf_evict_do(ocf_cache_t cache,
|
|||||||
to_evict = ocf_evict_calculate(target_part, evict_cline_no);
|
to_evict = ocf_evict_calculate(target_part, evict_cline_no);
|
||||||
if (to_evict) {
|
if (to_evict) {
|
||||||
evicted += ocf_eviction_need_space(cache, io_queue,
|
evicted += ocf_eviction_need_space(cache, io_queue,
|
||||||
target_part_id, to_evict);
|
target_part, to_evict);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,14 +107,14 @@ int space_managment_evict_do(struct ocf_cache *cache,
|
|||||||
{
|
{
|
||||||
uint32_t evicted;
|
uint32_t evicted;
|
||||||
uint32_t free;
|
uint32_t free;
|
||||||
|
struct ocf_user_part *req_part = &cache->user_parts[req->part_id];
|
||||||
|
|
||||||
free = ocf_freelist_num_free(cache->freelist);
|
free = ocf_freelist_num_free(cache->freelist);
|
||||||
if (evict_cline_no <= free)
|
if (evict_cline_no <= free)
|
||||||
return LOOKUP_MAPPED;
|
return LOOKUP_MAPPED;
|
||||||
|
|
||||||
evict_cline_no -= free;
|
evict_cline_no -= free;
|
||||||
evicted = ocf_evict_do(cache, req->io_queue, evict_cline_no,
|
evicted = ocf_evict_do(cache, req->io_queue, evict_cline_no, req_part);
|
||||||
req->part_id);
|
|
||||||
|
|
||||||
if (evict_cline_no <= evicted)
|
if (evict_cline_no <= evicted)
|
||||||
return LOOKUP_MAPPED;
|
return LOOKUP_MAPPED;
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
#define OCF_TO_EVICTION_MIN 128UL
|
#define OCF_TO_EVICTION_MIN 128UL
|
||||||
#define OCF_PENDING_EVICTION_LIMIT 512UL
|
#define OCF_PENDING_EVICTION_LIMIT 512UL
|
||||||
|
|
||||||
|
#define OCF_NUM_EVICTION_LISTS 32
|
||||||
|
|
||||||
|
struct ocf_user_part;
|
||||||
|
|
||||||
struct eviction_policy {
|
struct eviction_policy {
|
||||||
union {
|
union {
|
||||||
struct lru_eviction_policy lru;
|
struct lru_eviction_policy lru;
|
||||||
@ -37,17 +41,16 @@ struct eviction_policy_ops {
|
|||||||
ocf_cache_line_t cline);
|
ocf_cache_line_t cline);
|
||||||
bool (*can_evict)(ocf_cache_t cache);
|
bool (*can_evict)(ocf_cache_t cache);
|
||||||
uint32_t (*req_clines)(ocf_cache_t cache,
|
uint32_t (*req_clines)(ocf_cache_t cache,
|
||||||
ocf_queue_t io_queue, ocf_part_id_t part_id,
|
ocf_queue_t io_queue, struct ocf_user_part *part,
|
||||||
uint32_t cline_no);
|
uint32_t cline_no);
|
||||||
void (*hot_cline)(ocf_cache_t cache,
|
void (*hot_cline)(ocf_cache_t cache,
|
||||||
ocf_cache_line_t cline);
|
ocf_cache_line_t cline);
|
||||||
void (*init_evp)(ocf_cache_t cache,
|
void (*init_evp)(ocf_cache_t cache, struct ocf_user_part *part);
|
||||||
ocf_part_id_t part_id);
|
|
||||||
void (*dirty_cline)(ocf_cache_t cache,
|
void (*dirty_cline)(ocf_cache_t cache,
|
||||||
ocf_part_id_t part_id,
|
struct ocf_user_part *part,
|
||||||
uint32_t cline_no);
|
uint32_t cline_no);
|
||||||
void (*clean_cline)(ocf_cache_t cache,
|
void (*clean_cline)(ocf_cache_t cache,
|
||||||
ocf_part_id_t part_id,
|
struct ocf_user_part *part,
|
||||||
uint32_t cline_no);
|
uint32_t cline_no);
|
||||||
const char *name;
|
const char *name;
|
||||||
};
|
};
|
||||||
|
@ -163,48 +163,137 @@ void evp_lru_init_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
|||||||
node->next = end_marker;
|
node->next = end_marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct ocf_lru_list *evp_lru_get_list(struct ocf_user_part *part,
|
||||||
|
uint32_t evp, bool clean)
|
||||||
|
{
|
||||||
|
return clean ? &part->runtime->eviction[evp].policy.lru.clean :
|
||||||
|
&part->runtime->eviction[evp].policy.lru.dirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct ocf_lru_list *evp_get_cline_list(ocf_cache_t cache,
|
||||||
|
ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, cline);
|
||||||
|
struct ocf_user_part *part = &cache->user_parts[part_id];
|
||||||
|
uint32_t ev_list = (cline % OCF_NUM_EVICTION_LISTS);
|
||||||
|
|
||||||
|
return evp_lru_get_list(part, ev_list,
|
||||||
|
!metadata_test_dirty(cache, cline));
|
||||||
|
}
|
||||||
|
|
||||||
/* the caller must hold the metadata lock */
|
/* the caller must hold the metadata lock */
|
||||||
void evp_lru_rm_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
void evp_lru_rm_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
||||||
{
|
{
|
||||||
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, cline);
|
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
|
||||||
struct ocf_lru_list *list;
|
struct ocf_lru_list *list;
|
||||||
|
|
||||||
list = metadata_test_dirty(cache, cline) ?
|
list = evp_get_cline_list(cache, cline);
|
||||||
&part->runtime->eviction.policy.lru.dirty :
|
|
||||||
&part->runtime->eviction.policy.lru.clean;
|
|
||||||
|
|
||||||
remove_lru_list(cache, list, cline);
|
remove_lru_list(cache, list, cline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void lru_iter_init(struct ocf_lru_iter *iter, ocf_cache_t cache,
|
||||||
|
struct ocf_user_part *part, uint32_t start_evp, bool clean)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/* entire iterator implementation depends on gcc builtins for
|
||||||
|
bit operations which works on 64 bit integers at most */
|
||||||
|
ENV_BUILD_BUG_ON(OCF_NUM_EVICTION_LISTS > sizeof(iter->evp) * 8);
|
||||||
|
|
||||||
|
iter->cache = cache;
|
||||||
|
iter->part = part;
|
||||||
|
/* set iterator value to start_evp - 1 modulo OCF_NUM_EVICTION_LISTS */
|
||||||
|
iter->evp = (start_evp + OCF_NUM_EVICTION_LISTS - 1) % OCF_NUM_EVICTION_LISTS;
|
||||||
|
iter->num_avail_evps = OCF_NUM_EVICTION_LISTS;
|
||||||
|
iter->next_avail_evp = ((1ULL << OCF_NUM_EVICTION_LISTS) - 1);
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
iter->curr_cline[i] = evp_lru_get_list(part, i, clean)->tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t _lru_next_evp(struct ocf_lru_iter *iter)
|
||||||
|
{
|
||||||
|
unsigned increment;
|
||||||
|
|
||||||
|
increment = __builtin_ffsll(iter->next_avail_evp);
|
||||||
|
iter->next_avail_evp = ocf_rotate_right(iter->next_avail_evp,
|
||||||
|
increment, OCF_NUM_EVICTION_LISTS);
|
||||||
|
iter->evp = (iter->evp + increment) % OCF_NUM_EVICTION_LISTS;
|
||||||
|
|
||||||
|
return iter->evp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _lru_evp_is_empty(struct ocf_lru_iter *iter)
|
||||||
|
{
|
||||||
|
return !(iter->next_avail_evp & (1ULL << (OCF_NUM_EVICTION_LISTS - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _lru_evp_set_empty(struct ocf_lru_iter *iter)
|
||||||
|
{
|
||||||
|
iter->next_avail_evp &= ~(1ULL << (OCF_NUM_EVICTION_LISTS - 1));
|
||||||
|
iter->num_avail_evps--;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool _lru_evp_all_empty(struct ocf_lru_iter *iter)
|
||||||
|
{
|
||||||
|
return iter->num_avail_evps == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get next non-empty lru list if available */
|
||||||
|
static inline ocf_cache_line_t lru_iter_next(struct ocf_lru_iter *iter)
|
||||||
|
{
|
||||||
|
struct lru_eviction_policy_meta *node;
|
||||||
|
uint32_t curr_evp;
|
||||||
|
ocf_cache_line_t ret;
|
||||||
|
|
||||||
|
curr_evp = _lru_next_evp(iter);
|
||||||
|
|
||||||
|
while (iter->curr_cline[curr_evp] == end_marker) {
|
||||||
|
if (!_lru_evp_is_empty(iter)) {
|
||||||
|
/* mark list as empty */
|
||||||
|
_lru_evp_set_empty(iter);
|
||||||
|
}
|
||||||
|
if (_lru_evp_all_empty(iter)) {
|
||||||
|
/* all lists empty */
|
||||||
|
return end_marker;
|
||||||
|
}
|
||||||
|
curr_evp = _lru_next_evp(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
node = &ocf_metadata_get_eviction_policy(iter->cache,
|
||||||
|
iter->curr_cline[curr_evp])->lru;
|
||||||
|
ret = iter->curr_cline[curr_evp];
|
||||||
|
iter->curr_cline[curr_evp] = node->prev;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void evp_lru_clean_end(void *private_data, int error)
|
static void evp_lru_clean_end(void *private_data, int error)
|
||||||
{
|
{
|
||||||
struct ocf_refcnt *counter = private_data;
|
struct ocf_lru_iter *iter = private_data;
|
||||||
|
|
||||||
ocf_refcnt_dec(counter);
|
ocf_refcnt_dec(&iter->part->cleaning);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int evp_lru_clean_getter(ocf_cache_t cache,
|
static int evp_lru_clean_getter(ocf_cache_t cache, void *getter_context,
|
||||||
void *getter_context, uint32_t item, ocf_cache_line_t *line)
|
uint32_t item, ocf_cache_line_t *line)
|
||||||
{
|
{
|
||||||
struct ocf_cleaner_attribs *attribs = getter_context;
|
struct ocf_lru_iter *iter = getter_context;
|
||||||
ocf_cache_line_t prev_cline, curr_cline = attribs->getter_item;
|
ocf_cache_line_t cline;
|
||||||
|
|
||||||
while (curr_cline != end_marker) {
|
while (true) {
|
||||||
prev_cline = ocf_metadata_get_eviction_policy(cache,
|
cline = lru_iter_next(iter);
|
||||||
curr_cline)->lru.prev;
|
|
||||||
|
if (cline == end_marker)
|
||||||
|
break;
|
||||||
|
|
||||||
/* Prevent evicting already locked items */
|
/* Prevent evicting already locked items */
|
||||||
if (ocf_cache_line_is_used(cache, curr_cline)) {
|
if (ocf_cache_line_is_used(cache, cline)) {
|
||||||
curr_cline = prev_cline;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENV_BUG_ON(!metadata_test_dirty(cache, curr_cline));
|
ENV_BUG_ON(!metadata_test_dirty(cache, cline));
|
||||||
|
|
||||||
*line = curr_cline;
|
*line = cline;
|
||||||
attribs->getter_item = prev_cline;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,20 +301,18 @@ static int evp_lru_clean_getter(ocf_cache_t cache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
||||||
ocf_part_id_t part_id, uint32_t count)
|
struct ocf_user_part *part, uint32_t count)
|
||||||
{
|
{
|
||||||
struct ocf_refcnt *counter = &cache->refcnt.cleaning[part_id];
|
struct ocf_refcnt *counter = &part->cleaning;
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
|
||||||
struct ocf_cleaner_attribs attribs = {
|
struct ocf_cleaner_attribs attribs = {
|
||||||
.cache_line_lock = true,
|
.cache_line_lock = true,
|
||||||
.do_sort = true,
|
.do_sort = true,
|
||||||
|
|
||||||
.cmpl_context = counter,
|
.cmpl_context = &part->eviction_clean_iter,
|
||||||
.cmpl_fn = evp_lru_clean_end,
|
.cmpl_fn = evp_lru_clean_end,
|
||||||
|
|
||||||
.getter = evp_lru_clean_getter,
|
.getter = evp_lru_clean_getter,
|
||||||
.getter_context = &attribs,
|
.getter_context = &part->eviction_clean_iter,
|
||||||
.getter_item = part->runtime->eviction.policy.lru.dirty.tail,
|
|
||||||
|
|
||||||
.count = count > 32 ? 32 : count,
|
.count = count > 32 ? 32 : count,
|
||||||
|
|
||||||
@ -247,6 +334,9 @@ static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lru_iter_init(&part->eviction_clean_iter, cache, part,
|
||||||
|
part->eviction_clean_iter.evp, false);
|
||||||
|
|
||||||
ocf_cleaner_fire(cache, &attribs);
|
ocf_cleaner_fire(cache, &attribs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,64 +384,69 @@ bool evp_lru_can_evict(ocf_cache_t cache)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the caller must hold the metadata lock */
|
static bool dirty_pages_present(ocf_cache_t cache, struct ocf_user_part *part)
|
||||||
uint32_t evp_lru_req_clines(ocf_cache_t cache, ocf_queue_t io_queue,
|
|
||||||
ocf_part_id_t part_id, uint32_t cline_no)
|
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
ocf_cache_line_t curr_cline, prev_cline;
|
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
if (evp_lru_get_list(part, i, false)->tail != end_marker)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the caller must hold the metadata lock */
|
||||||
|
uint32_t evp_lru_req_clines(ocf_cache_t cache, ocf_queue_t io_queue,
|
||||||
|
struct ocf_user_part *part, uint32_t cline_no)
|
||||||
|
{
|
||||||
|
struct ocf_lru_iter iter;
|
||||||
|
uint32_t i;
|
||||||
|
ocf_cache_line_t cline;
|
||||||
|
|
||||||
if (cline_no == 0)
|
if (cline_no == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
i = 0;
|
lru_iter_init(&iter, cache, part, part->next_eviction_list, true);
|
||||||
curr_cline = part->runtime->eviction.policy.lru.clean.tail;
|
|
||||||
/* Find cachelines to be evicted. */
|
i = 0;
|
||||||
while (i < cline_no) {
|
while (i < cline_no) {
|
||||||
|
cline = lru_iter_next(&iter);
|
||||||
|
|
||||||
|
if (cline == end_marker)
|
||||||
|
break;
|
||||||
|
|
||||||
if (!evp_lru_can_evict(cache))
|
if (!evp_lru_can_evict(cache))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (curr_cline == end_marker)
|
|
||||||
break;
|
|
||||||
|
|
||||||
prev_cline = ocf_metadata_get_eviction_policy(cache,
|
|
||||||
curr_cline)->lru.prev;
|
|
||||||
|
|
||||||
/* Prevent evicting already locked items */
|
/* Prevent evicting already locked items */
|
||||||
if (ocf_cache_line_is_used(cache, curr_cline)) {
|
if (ocf_cache_line_is_used(cache, cline))
|
||||||
curr_cline = prev_cline;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
ENV_BUG_ON(metadata_test_dirty(cache, curr_cline));
|
ENV_BUG_ON(metadata_test_dirty(cache, cline));
|
||||||
|
|
||||||
if (ocf_volume_is_atomic(&cache->device->volume)) {
|
if (ocf_volume_is_atomic(&cache->device->volume)) {
|
||||||
/* atomic cache, we have to trim cache lines before
|
/* atomic cache, we have to trim cache lines before
|
||||||
* eviction
|
* eviction
|
||||||
*/
|
*/
|
||||||
evp_lru_zero_line(cache, io_queue, curr_cline);
|
evp_lru_zero_line(cache, io_queue, cline);
|
||||||
|
continue;
|
||||||
} else {
|
|
||||||
ocf_metadata_start_collision_shared_access(cache,
|
|
||||||
curr_cline);
|
|
||||||
set_cache_line_invalid_no_flush(cache, 0,
|
|
||||||
ocf_line_end_sector(cache),
|
|
||||||
curr_cline);
|
|
||||||
ocf_metadata_end_collision_shared_access(cache,
|
|
||||||
curr_cline);
|
|
||||||
|
|
||||||
/* Goto next item. */
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
curr_cline = prev_cline;
|
ocf_metadata_start_collision_shared_access(
|
||||||
|
cache, cline);
|
||||||
|
set_cache_line_invalid_no_flush(cache, 0,
|
||||||
|
ocf_line_end_sector(cache),
|
||||||
|
cline);
|
||||||
|
ocf_metadata_end_collision_shared_access(
|
||||||
|
cache, cline);
|
||||||
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < cline_no && part->runtime->eviction.policy.lru.dirty.tail !=
|
part->next_eviction_list = iter.evp;
|
||||||
end_marker) {
|
|
||||||
evp_lru_clean(cache, io_queue, part_id, cline_no - i);
|
if (i < cline_no && dirty_pages_present(cache, part))
|
||||||
}
|
evp_lru_clean(cache, io_queue, part, cline_no - i);
|
||||||
|
|
||||||
/* Return number of clines that were really evicted */
|
/* Return number of clines that were really evicted */
|
||||||
return i;
|
return i;
|
||||||
@ -360,18 +455,11 @@ uint32_t evp_lru_req_clines(ocf_cache_t cache, ocf_queue_t io_queue,
|
|||||||
/* the caller must hold the metadata lock */
|
/* the caller must hold the metadata lock */
|
||||||
void evp_lru_hot_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
void evp_lru_hot_cline(ocf_cache_t cache, ocf_cache_line_t cline)
|
||||||
{
|
{
|
||||||
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, cline);
|
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
|
||||||
struct lru_eviction_policy_meta *node;
|
struct lru_eviction_policy_meta *node;
|
||||||
int cline_dirty;
|
|
||||||
struct ocf_lru_list *list;
|
struct ocf_lru_list *list;
|
||||||
|
|
||||||
node = &ocf_metadata_get_eviction_policy(cache, cline)->lru;
|
node = &ocf_metadata_get_eviction_policy(cache, cline)->lru;
|
||||||
|
list = evp_get_cline_list(cache, cline);
|
||||||
cline_dirty = metadata_test_dirty(cache, cline);
|
|
||||||
list = cline_dirty ?
|
|
||||||
&part->runtime->eviction.policy.lru.dirty :
|
|
||||||
&part->runtime->eviction.policy.lru.clean;
|
|
||||||
|
|
||||||
if (node->next != end_marker ||
|
if (node->next != end_marker ||
|
||||||
node->prev != end_marker ||
|
node->prev != end_marker ||
|
||||||
@ -390,48 +478,50 @@ static inline void _lru_init(struct ocf_lru_list *list)
|
|||||||
list->tail = end_marker;
|
list->tail = end_marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void evp_lru_init_evp(ocf_cache_t cache, ocf_part_id_t part_id)
|
void evp_lru_init_evp(ocf_cache_t cache, struct ocf_user_part *part)
|
||||||
{
|
{
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
|
||||||
struct ocf_lru_list *clean_list;
|
struct ocf_lru_list *clean_list;
|
||||||
struct ocf_lru_list *dirty_list;
|
struct ocf_lru_list *dirty_list;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
clean_list = &part->runtime->eviction.policy.lru.clean;
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
dirty_list = &part->runtime->eviction.policy.lru.dirty;
|
clean_list = evp_lru_get_list(part, i, true);
|
||||||
|
dirty_list = evp_lru_get_list(part, i, false);
|
||||||
|
|
||||||
_lru_init(clean_list);
|
_lru_init(clean_list);
|
||||||
_lru_init(dirty_list);
|
_lru_init(dirty_list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void evp_lru_clean_cline(ocf_cache_t cache, ocf_part_id_t part_id,
|
void evp_lru_clean_cline(ocf_cache_t cache, struct ocf_user_part *part,
|
||||||
uint32_t cline)
|
uint32_t cline)
|
||||||
{
|
{
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
uint32_t ev_list = (cline % OCF_NUM_EVICTION_LISTS);
|
||||||
struct ocf_lru_list *clean_list;
|
struct ocf_lru_list *clean_list;
|
||||||
struct ocf_lru_list *dirty_list;
|
struct ocf_lru_list *dirty_list;
|
||||||
|
|
||||||
clean_list = &part->runtime->eviction.policy.lru.clean;
|
clean_list = evp_lru_get_list(part, ev_list, true);
|
||||||
dirty_list = &part->runtime->eviction.policy.lru.dirty;
|
dirty_list = evp_lru_get_list(part, ev_list, false);
|
||||||
|
|
||||||
OCF_METADATA_EVICTION_LOCK();
|
OCF_METADATA_EVICTION_LOCK(cline);
|
||||||
remove_lru_list(cache, dirty_list, cline);
|
remove_lru_list(cache, dirty_list, cline);
|
||||||
add_lru_head(cache, clean_list, cline);
|
add_lru_head(cache, clean_list, cline);
|
||||||
OCF_METADATA_EVICTION_UNLOCK();
|
OCF_METADATA_EVICTION_UNLOCK(cline);
|
||||||
}
|
}
|
||||||
|
|
||||||
void evp_lru_dirty_cline(ocf_cache_t cache, ocf_part_id_t part_id,
|
void evp_lru_dirty_cline(ocf_cache_t cache, struct ocf_user_part *part,
|
||||||
uint32_t cline)
|
uint32_t cline)
|
||||||
{
|
{
|
||||||
struct ocf_user_part *part = &cache->user_parts[part_id];
|
uint32_t ev_list = (cline % OCF_NUM_EVICTION_LISTS);
|
||||||
struct ocf_lru_list *clean_list;
|
struct ocf_lru_list *clean_list;
|
||||||
struct ocf_lru_list *dirty_list;
|
struct ocf_lru_list *dirty_list;
|
||||||
|
|
||||||
clean_list = &part->runtime->eviction.policy.lru.clean;
|
clean_list = evp_lru_get_list(part, ev_list, true);
|
||||||
dirty_list = &part->runtime->eviction.policy.lru.dirty;
|
dirty_list = evp_lru_get_list(part, ev_list, false);
|
||||||
|
|
||||||
OCF_METADATA_EVICTION_LOCK();
|
OCF_METADATA_EVICTION_LOCK(cline);
|
||||||
remove_lru_list(cache, clean_list, cline);
|
remove_lru_list(cache, clean_list, cline);
|
||||||
add_lru_head(cache, dirty_list, cline);
|
add_lru_head(cache, dirty_list, cline);
|
||||||
OCF_METADATA_EVICTION_UNLOCK();
|
OCF_METADATA_EVICTION_UNLOCK(cline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,14 +8,18 @@
|
|||||||
#include "eviction.h"
|
#include "eviction.h"
|
||||||
#include "lru_structs.h"
|
#include "lru_structs.h"
|
||||||
|
|
||||||
|
struct ocf_user_part;
|
||||||
|
|
||||||
void evp_lru_init_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
void evp_lru_init_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
||||||
void evp_lru_rm_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
void evp_lru_rm_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
||||||
bool evp_lru_can_evict(struct ocf_cache *cache);
|
bool evp_lru_can_evict(struct ocf_cache *cache);
|
||||||
uint32_t evp_lru_req_clines(struct ocf_cache *cache, ocf_queue_t io_queue,
|
uint32_t evp_lru_req_clines(struct ocf_cache *cache, ocf_queue_t io_queue,
|
||||||
ocf_part_id_t part_id, uint32_t cline_no);
|
struct ocf_user_part *part, uint32_t cline_no);
|
||||||
void evp_lru_hot_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
void evp_lru_hot_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
||||||
void evp_lru_init_evp(struct ocf_cache *cache, ocf_part_id_t part_id);
|
void evp_lru_init_evp(struct ocf_cache *cache, struct ocf_user_part *part);
|
||||||
void evp_lru_dirty_cline(struct ocf_cache *cache, ocf_part_id_t part_id, uint32_t cline);
|
void evp_lru_dirty_cline(struct ocf_cache *cache, struct ocf_user_part *part,
|
||||||
void evp_lru_clean_cline(struct ocf_cache *cache, ocf_part_id_t part_id, uint32_t cline);
|
uint32_t cline);
|
||||||
|
void evp_lru_clean_cline(struct ocf_cache *cache, struct ocf_user_part *part,
|
||||||
|
uint32_t cline);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
* @note This operation is called under WR metadata lock
|
* @note This operation is called under WR metadata lock
|
||||||
*/
|
*/
|
||||||
static inline void ocf_eviction_init_cache_line(struct ocf_cache *cache,
|
static inline void ocf_eviction_init_cache_line(struct ocf_cache *cache,
|
||||||
ocf_cache_line_t line, ocf_part_id_t part_id)
|
ocf_cache_line_t line)
|
||||||
{
|
{
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
|
|
||||||
@ -36,13 +36,12 @@ static inline void ocf_eviction_purge_cache_line(
|
|||||||
ENV_BUG_ON(type >= ocf_eviction_max);
|
ENV_BUG_ON(type >= ocf_eviction_max);
|
||||||
|
|
||||||
if (likely(evict_policy_ops[type].rm_cline)) {
|
if (likely(evict_policy_ops[type].rm_cline)) {
|
||||||
OCF_METADATA_EVICTION_LOCK();
|
OCF_METADATA_EVICTION_LOCK(line);
|
||||||
evict_policy_ops[type].rm_cline(cache, line);
|
evict_policy_ops[type].rm_cline(cache, line);
|
||||||
OCF_METADATA_EVICTION_UNLOCK();
|
OCF_METADATA_EVICTION_UNLOCK(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool ocf_eviction_can_evict(struct ocf_cache *cache)
|
static inline bool ocf_eviction_can_evict(struct ocf_cache *cache)
|
||||||
{
|
{
|
||||||
uint8_t type = cache->conf_meta->eviction_policy_type;
|
uint8_t type = cache->conf_meta->eviction_policy_type;
|
||||||
@ -54,7 +53,8 @@ static inline bool ocf_eviction_can_evict(struct ocf_cache *cache)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t ocf_eviction_need_space(struct ocf_cache *cache,
|
static inline uint32_t ocf_eviction_need_space(struct ocf_cache *cache,
|
||||||
ocf_queue_t io_queue, ocf_part_id_t part_id, uint32_t clines)
|
ocf_queue_t io_queue, struct ocf_user_part *part,
|
||||||
|
uint32_t clines)
|
||||||
{
|
{
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
@ -69,7 +69,7 @@ static inline uint32_t ocf_eviction_need_space(struct ocf_cache *cache,
|
|||||||
* eviction lock.
|
* eviction lock.
|
||||||
*/
|
*/
|
||||||
result = evict_policy_ops[type].req_clines(cache, io_queue,
|
result = evict_policy_ops[type].req_clines(cache, io_queue,
|
||||||
part_id, clines);
|
part, clines);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -83,23 +83,23 @@ static inline void ocf_eviction_set_hot_cache_line(
|
|||||||
ENV_BUG_ON(type >= ocf_eviction_max);
|
ENV_BUG_ON(type >= ocf_eviction_max);
|
||||||
|
|
||||||
if (likely(evict_policy_ops[type].hot_cline)) {
|
if (likely(evict_policy_ops[type].hot_cline)) {
|
||||||
OCF_METADATA_EVICTION_LOCK();
|
OCF_METADATA_EVICTION_LOCK(line);
|
||||||
evict_policy_ops[type].hot_cline(cache, line);
|
evict_policy_ops[type].hot_cline(cache, line);
|
||||||
OCF_METADATA_EVICTION_UNLOCK();
|
OCF_METADATA_EVICTION_UNLOCK(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void ocf_eviction_initialize(struct ocf_cache *cache,
|
static inline void ocf_eviction_initialize(struct ocf_cache *cache,
|
||||||
ocf_part_id_t part_id)
|
struct ocf_user_part *part)
|
||||||
{
|
{
|
||||||
uint8_t type = cache->conf_meta->eviction_policy_type;
|
uint8_t type = cache->conf_meta->eviction_policy_type;
|
||||||
|
|
||||||
ENV_BUG_ON(type >= ocf_eviction_max);
|
ENV_BUG_ON(type >= ocf_eviction_max);
|
||||||
|
|
||||||
if (likely(evict_policy_ops[type].init_evp)) {
|
if (likely(evict_policy_ops[type].init_evp)) {
|
||||||
OCF_METADATA_EVICTION_LOCK();
|
OCF_METADATA_EVICTION_LOCK_ALL();
|
||||||
evict_policy_ops[type].init_evp(cache, part_id);
|
evict_policy_ops[type].init_evp(cache, part);
|
||||||
OCF_METADATA_EVICTION_UNLOCK();
|
OCF_METADATA_EVICTION_UNLOCK_ALL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,6 +563,7 @@ int ocf_metadata_hash_init(struct ocf_cache *cache,
|
|||||||
for (i = 0; i < OCF_IO_CLASS_MAX + 1; i++) {
|
for (i = 0; i < OCF_IO_CLASS_MAX + 1; i++) {
|
||||||
cache->user_parts[i].config = &part_config[i];
|
cache->user_parts[i].config = &part_config[i];
|
||||||
cache->user_parts[i].runtime = &part_runtime[i];
|
cache->user_parts[i].runtime = &part_runtime[i];
|
||||||
|
cache->user_parts[i].id = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set core metadata */
|
/* Set core metadata */
|
||||||
@ -1949,7 +1950,7 @@ static void _recovery_rebuild_cline_metadata(ocf_cache_t cache,
|
|||||||
ocf_metadata_add_to_collision(cache, core_id, core_line, hash_index,
|
ocf_metadata_add_to_collision(cache, core_id, core_line, hash_index,
|
||||||
cache_line);
|
cache_line);
|
||||||
|
|
||||||
ocf_eviction_init_cache_line(cache, cache_line, part_id);
|
ocf_eviction_init_cache_line(cache, cache_line);
|
||||||
|
|
||||||
ocf_eviction_set_hot_cache_line(cache, cache_line);
|
ocf_eviction_set_hot_cache_line(cache, cache_line);
|
||||||
|
|
||||||
|
@ -29,15 +29,37 @@ struct ocf_user_part_config {
|
|||||||
struct ocf_user_part_runtime {
|
struct ocf_user_part_runtime {
|
||||||
uint32_t curr_size;
|
uint32_t curr_size;
|
||||||
uint32_t head;
|
uint32_t head;
|
||||||
struct eviction_policy eviction;
|
struct eviction_policy eviction[OCF_NUM_EVICTION_LISTS];
|
||||||
struct cleaning_policy cleaning;
|
struct cleaning_policy cleaning;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ocf_user_part {
|
/* Iterator state, visiting all eviction lists within a partition
|
||||||
struct ocf_user_part_config *config;
|
in round robin order */
|
||||||
struct ocf_user_part_runtime *runtime;
|
struct ocf_lru_iter {
|
||||||
|
/* cache object */
|
||||||
|
ocf_cache_t cache;
|
||||||
|
/* target partition */
|
||||||
|
struct ocf_user_part *part;
|
||||||
|
/* per-partition cacheline iterator */
|
||||||
|
ocf_cache_line_t curr_cline[OCF_NUM_EVICTION_LISTS];
|
||||||
|
/* available (non-empty) eviction list bitmap rotated so that current
|
||||||
|
@evp is on the most significant bit */
|
||||||
|
unsigned long long next_avail_evp;
|
||||||
|
/* number of available eviction lists */
|
||||||
|
uint32_t num_avail_evps;
|
||||||
|
/* current eviction list index */
|
||||||
|
uint32_t evp;
|
||||||
|
};
|
||||||
|
|
||||||
struct ocf_lst_entry lst_valid;
|
struct ocf_user_part {
|
||||||
|
struct ocf_user_part_config *config;
|
||||||
|
struct ocf_user_part_runtime *runtime;
|
||||||
|
struct ocf_refcnt cleaning;
|
||||||
|
ocf_part_id_t id;
|
||||||
|
|
||||||
|
struct ocf_lru_iter eviction_clean_iter;
|
||||||
|
uint32_t next_eviction_list;
|
||||||
|
struct ocf_lst_entry lst_valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,7 +412,7 @@ struct ocf_metadata_lock
|
|||||||
{
|
{
|
||||||
env_rwsem global; /*!< global metadata lock (GML) */
|
env_rwsem global; /*!< global metadata lock (GML) */
|
||||||
env_rwlock status; /*!< Fast lock for status bits */
|
env_rwlock status; /*!< Fast lock for status bits */
|
||||||
env_spinlock eviction; /*!< Fast lock for eviction policy */
|
env_spinlock eviction[OCF_NUM_EVICTION_LISTS]; /*!< Fast lock for eviction policy */
|
||||||
env_rwsem *hash; /*!< Hash bucket locks */
|
env_rwsem *hash; /*!< Hash bucket locks */
|
||||||
env_rwsem *collision_pages; /*!< Collision table page locks */
|
env_rwsem *collision_pages; /*!< Collision table page locks */
|
||||||
env_spinlock partition[OCF_IO_CLASS_MAX]; /* partition lock */
|
env_spinlock partition[OCF_IO_CLASS_MAX]; /* partition lock */
|
||||||
|
@ -177,7 +177,7 @@ static void __init_partitions(ocf_cache_t cache)
|
|||||||
|
|
||||||
/* Add other partition to the cache and make it as dummy */
|
/* Add other partition to the cache and make it as dummy */
|
||||||
for (i_part = 0; i_part < OCF_IO_CLASS_MAX; i_part++) {
|
for (i_part = 0; i_part < OCF_IO_CLASS_MAX; i_part++) {
|
||||||
ocf_refcnt_freeze(&cache->refcnt.cleaning[i_part]);
|
ocf_refcnt_freeze(&cache->user_parts[i_part].cleaning);
|
||||||
|
|
||||||
if (i_part == PARTITION_DEFAULT)
|
if (i_part == PARTITION_DEFAULT)
|
||||||
continue;
|
continue;
|
||||||
@ -191,14 +191,15 @@ static void __init_partitions(ocf_cache_t cache)
|
|||||||
|
|
||||||
static void __init_partitions_attached(ocf_cache_t cache)
|
static void __init_partitions_attached(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
|
struct ocf_user_part *part;
|
||||||
ocf_part_id_t part_id;
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
for (part_id = 0; part_id < OCF_IO_CLASS_MAX; part_id++) {
|
for (part_id = 0; part_id < OCF_IO_CLASS_MAX; part_id++) {
|
||||||
cache->user_parts[part_id].runtime->head =
|
part = &cache->user_parts[part_id];
|
||||||
cache->device->collision_table_entries;
|
|
||||||
cache->user_parts[part_id].runtime->curr_size = 0;
|
|
||||||
|
|
||||||
ocf_eviction_initialize(cache, part_id);
|
part->runtime->head = cache->device->collision_table_entries;
|
||||||
|
part->runtime->curr_size = 0;
|
||||||
|
ocf_eviction_initialize(cache, part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +122,6 @@ struct ocf_cache {
|
|||||||
/* # of requests accessing attached metadata, excluding
|
/* # of requests accessing attached metadata, excluding
|
||||||
* management reqs */
|
* management reqs */
|
||||||
struct ocf_refcnt metadata;
|
struct ocf_refcnt metadata;
|
||||||
/* # of forced cleaning requests (eviction path) */
|
|
||||||
struct ocf_refcnt cleaning[OCF_IO_CLASS_MAX];
|
|
||||||
} refcnt;
|
} refcnt;
|
||||||
|
|
||||||
uint32_t fallback_pt_error_threshold;
|
uint32_t fallback_pt_error_threshold;
|
||||||
|
@ -49,4 +49,11 @@
|
|||||||
/* call conditional reschedule with default interval */
|
/* call conditional reschedule with default interval */
|
||||||
#define OCF_COND_RESCHED_DEFAULT(cnt) OCF_COND_RESCHED(cnt, 1000000)
|
#define OCF_COND_RESCHED_DEFAULT(cnt) OCF_COND_RESCHED(cnt, 1000000)
|
||||||
|
|
||||||
|
static inline unsigned long long
|
||||||
|
ocf_rotate_right(unsigned long long bits, unsigned shift, unsigned width)
|
||||||
|
{
|
||||||
|
return ((bits >> shift) | (bits << (width - shift))) &
|
||||||
|
((1ULL << width) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -101,6 +101,7 @@ void set_cache_line_clean(struct ocf_cache *cache, uint8_t start_bit,
|
|||||||
{
|
{
|
||||||
ocf_cache_line_t line = req->map[map_idx].coll_idx;
|
ocf_cache_line_t line = req->map[map_idx].coll_idx;
|
||||||
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line);
|
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line);
|
||||||
|
struct ocf_user_part *part = &cache->user_parts[part_id];
|
||||||
uint8_t evp_type = cache->conf_meta->eviction_policy_type;
|
uint8_t evp_type = cache->conf_meta->eviction_policy_type;
|
||||||
bool line_is_clean;
|
bool line_is_clean;
|
||||||
|
|
||||||
@ -130,7 +131,7 @@ void set_cache_line_clean(struct ocf_cache *cache, uint8_t start_bit,
|
|||||||
part_counters[part_id].dirty_clines);
|
part_counters[part_id].dirty_clines);
|
||||||
|
|
||||||
if (likely(evict_policy_ops[evp_type].clean_cline))
|
if (likely(evict_policy_ops[evp_type].clean_cline))
|
||||||
evict_policy_ops[evp_type].clean_cline(cache, part_id, line);
|
evict_policy_ops[evp_type].clean_cline(cache, part, line);
|
||||||
|
|
||||||
ocf_purge_cleaning_policy(cache, line);
|
ocf_purge_cleaning_policy(cache, line);
|
||||||
}
|
}
|
||||||
@ -143,6 +144,7 @@ void set_cache_line_dirty(struct ocf_cache *cache, uint8_t start_bit,
|
|||||||
{
|
{
|
||||||
ocf_cache_line_t line = req->map[map_idx].coll_idx;
|
ocf_cache_line_t line = req->map[map_idx].coll_idx;
|
||||||
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line);
|
ocf_part_id_t part_id = ocf_metadata_get_partition_id(cache, line);
|
||||||
|
struct ocf_user_part *part = &cache->user_parts[part_id];
|
||||||
uint8_t evp_type = cache->conf_meta->eviction_policy_type;
|
uint8_t evp_type = cache->conf_meta->eviction_policy_type;
|
||||||
bool line_was_dirty;
|
bool line_was_dirty;
|
||||||
|
|
||||||
@ -170,7 +172,7 @@ void set_cache_line_dirty(struct ocf_cache *cache, uint8_t start_bit,
|
|||||||
part_counters[part_id].dirty_clines);
|
part_counters[part_id].dirty_clines);
|
||||||
|
|
||||||
if (likely(evict_policy_ops[evp_type].dirty_cline))
|
if (likely(evict_policy_ops[evp_type].dirty_cline))
|
||||||
evict_policy_ops[evp_type].dirty_cline(cache, part_id, line);
|
evict_policy_ops[evp_type].dirty_cline(cache, part, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,7 +1017,7 @@ void ocf_cleaner_refcnt_freeze(ocf_cache_t cache)
|
|||||||
ocf_part_id_t part_id;
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
for_each_part(cache, curr_part, part_id)
|
for_each_part(cache, curr_part, part_id)
|
||||||
ocf_refcnt_freeze(&cache->refcnt.cleaning[part_id]);
|
ocf_refcnt_freeze(&curr_part->cleaning);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache)
|
void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache)
|
||||||
@ -1026,7 +1026,7 @@ void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache)
|
|||||||
ocf_part_id_t part_id;
|
ocf_part_id_t part_id;
|
||||||
|
|
||||||
for_each_part(cache, curr_part, part_id)
|
for_each_part(cache, curr_part, part_id)
|
||||||
ocf_refcnt_unfreeze(&cache->refcnt.cleaning[part_id]);
|
ocf_refcnt_unfreeze(&curr_part->cleaning);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ocf_cleaner_refcnt_register_zero_cb_finish(void *priv)
|
static void ocf_cleaner_refcnt_register_zero_cb_finish(void *priv)
|
||||||
@ -1050,7 +1050,7 @@ void ocf_cleaner_refcnt_register_zero_cb(ocf_cache_t cache,
|
|||||||
|
|
||||||
for_each_part(cache, curr_part, part_id) {
|
for_each_part(cache, curr_part, part_id) {
|
||||||
env_atomic_inc(&ctx->waiting);
|
env_atomic_inc(&ctx->waiting);
|
||||||
ocf_refcnt_register_zero_cb(&cache->refcnt.cleaning[part_id],
|
ocf_refcnt_register_zero_cb(&curr_part->cleaning,
|
||||||
ocf_cleaner_refcnt_register_zero_cb_finish, ctx);
|
ocf_cleaner_refcnt_register_zero_cb_finish, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
* @retval Non-zero Means skip this cache line and do not clean it
|
* @retval Non-zero Means skip this cache line and do not clean it
|
||||||
*/
|
*/
|
||||||
typedef int (*ocf_cleaner_get_item)(struct ocf_cache *cache,
|
typedef int (*ocf_cleaner_get_item)(struct ocf_cache *cache,
|
||||||
void *getter_context, uint32_t item, ocf_cache_line_t *line);
|
void *getter_context, uint32_t item,
|
||||||
|
ocf_cache_line_t *line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Cleaning attributes for clean request
|
* @brief Cleaning attributes for clean request
|
||||||
|
@ -142,7 +142,7 @@ void ocf_part_move(struct ocf_request *req)
|
|||||||
ocf_metadata_add_to_partition(cache, id_new, line);
|
ocf_metadata_add_to_partition(cache, id_new, line);
|
||||||
|
|
||||||
/* Add to new eviction */
|
/* Add to new eviction */
|
||||||
ocf_eviction_init_cache_line(cache, line, id_new);
|
ocf_eviction_init_cache_line(cache, line);
|
||||||
ocf_eviction_set_hot_cache_line(cache, line);
|
ocf_eviction_set_hot_cache_line(cache, line);
|
||||||
|
|
||||||
/* Check if cache line is dirty. If yes then need to change
|
/* Check if cache line is dirty. If yes then need to change
|
||||||
|
@ -9,3 +9,9 @@ GENERATING NEW TEST
|
|||||||
|
|
||||||
RUNNING SINGLE TEST
|
RUNNING SINGLE TEST
|
||||||
Executable tests files are stored by default in 'UT_dir/build/sources_to_test_repository/'
|
Executable tests files are stored by default in 'UT_dir/build/sources_to_test_repository/'
|
||||||
|
|
||||||
|
REQUIREMENTS FOR BUILD:
|
||||||
|
- cmocka
|
||||||
|
- cmake
|
||||||
|
- ctags (Exuberant version)
|
||||||
|
- nm, gcc, make
|
||||||
|
481
tests/unit/tests/eviction/lru.c/lru_iter.c
Normal file
481
tests/unit/tests/eviction/lru.c/lru_iter.c
Normal file
@ -0,0 +1,481 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/eviction/lru.c</tested_file_path>
|
||||||
|
* <tested_function>lru_iter_next</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE
|
||||||
|
* ONE FUNCTION PER LINE
|
||||||
|
* lru_iter_init
|
||||||
|
* _lru_next_evp
|
||||||
|
* _lru_evp_is_empty
|
||||||
|
* _lru_evp_set_empty
|
||||||
|
* _lru_evp_all_empty
|
||||||
|
* ocf_rotate_right
|
||||||
|
* </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 "lru.h"
|
||||||
|
#include "ops.h"
|
||||||
|
#include "../utils/utils_cleaner.h"
|
||||||
|
#include "../utils/utils_cache_line.h"
|
||||||
|
#include "../concurrency/ocf_concurrency.h"
|
||||||
|
#include "../mngt/ocf_mngt_common.h"
|
||||||
|
#include "../engine/engine_zero.h"
|
||||||
|
#include "../ocf_request.h"
|
||||||
|
|
||||||
|
#include "eviction/lru.c/lru_iter_generated_wraps.c"
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
ocf_cache_line_t test_cases[10 * OCF_NUM_EVICTION_LISTS][OCF_NUM_EVICTION_LISTS][20];
|
||||||
|
unsigned num_cases = 20;
|
||||||
|
|
||||||
|
void write_test_case_description(void)
|
||||||
|
{
|
||||||
|
unsigned i, j, l;
|
||||||
|
unsigned test_case = 0;
|
||||||
|
|
||||||
|
// case 0 - all lists empty
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
test_cases[0][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 1 - all lists with single element
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
test_cases[0][i][test_case] = 10 * i;
|
||||||
|
test_cases[1][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2 - all lists have between 1 and 5 elements, increasingly
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = 1 + i / (OCF_NUM_EVICTION_LISTS / 4);
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 10 * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 3 - all lists have between 1 and 5 elements, modulo index
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = 1 + (i % 5);
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 10 * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4 - all lists have between 0 and 4 elements, increasingly
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = i / (OCF_NUM_EVICTION_LISTS / 4);
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 10 * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 5 - all lists have between 0 and 4 elements, modulo index
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = (i % 5);
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 10 * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 6 - list length increasing by 1 from 0
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = i;
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = OCF_NUM_EVICTION_LISTS * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 7 - list length increasing by 1 from 1
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = i + 1;
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 2 * OCF_NUM_EVICTION_LISTS * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 8 - list length increasing by 4 from 0
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = 4 * i;
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 4 * OCF_NUM_EVICTION_LISTS * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 9 - list length increasing by 4 from 1
|
||||||
|
test_case++;
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned num_elements = 4 * i + 1;
|
||||||
|
|
||||||
|
for (j = 0; j < num_elements; j++)
|
||||||
|
test_cases[j][i][test_case] = 5 * OCF_NUM_EVICTION_LISTS * i + j;
|
||||||
|
test_cases[j][i][test_case] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cases 10-19: cases 0-9 rotated right by 4
|
||||||
|
l = test_case;
|
||||||
|
test_case++;
|
||||||
|
while(test_case < 2 * (l + 1)) {
|
||||||
|
unsigned matching_case = test_case - l - 1;
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
unsigned curr_list = (i + 4) % OCF_NUM_EVICTION_LISTS;
|
||||||
|
j = 0;
|
||||||
|
while(test_cases[j][i][matching_case] != -1) {
|
||||||
|
test_cases[j][curr_list][test_case] =
|
||||||
|
test_cases[j][i][matching_case];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
test_cases[j][curr_list][test_case] = -1;
|
||||||
|
}
|
||||||
|
test_case++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
for (test_case = 0; test_case < num_cases; test_case++) {
|
||||||
|
print_message("test case no %d\n", test_case);
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) {
|
||||||
|
print_message("list %02u: ", i);
|
||||||
|
j = 0;
|
||||||
|
while (test_cases[j][i][test_case] != -1) {
|
||||||
|
print_message("%u ", test_cases[j][i][test_case]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
print_message("<EOL>\n");
|
||||||
|
}
|
||||||
|
print_message("========\n\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned current_case;
|
||||||
|
|
||||||
|
struct ocf_lru_list list;
|
||||||
|
|
||||||
|
struct ocf_lru_list *__wrap_evp_lru_get_list(struct ocf_user_part *part,
|
||||||
|
uint32_t evp, bool clean)
|
||||||
|
{
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
while (test_cases[i][evp][current_case] != -1)
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
list.head = -1;
|
||||||
|
list.tail = -1;
|
||||||
|
list.num_nodes = 0;
|
||||||
|
} else {
|
||||||
|
list.head = test_cases[0][evp][current_case];
|
||||||
|
list.tail = test_cases[i - 1][evp][current_case];
|
||||||
|
list.num_nodes = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &list;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline struct ocf_lru_list *__wrap_evp_get_cline_list(ocf_cache_t cache,
|
||||||
|
ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
return __wrap_evp_lru_get_list(NULL, cline % OCF_NUM_EVICTION_LISTS, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
union eviction_policy_meta policy;
|
||||||
|
|
||||||
|
union eviction_policy_meta *__wrap_ocf_metadata_get_eviction_policy(
|
||||||
|
struct ocf_cache *cache, ocf_cache_line_t line)
|
||||||
|
{
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
{
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
while (test_cases[j][i][current_case] != -1) {
|
||||||
|
if (test_cases[j][i][current_case] == line) {
|
||||||
|
if (j == 0) {
|
||||||
|
policy.lru.prev = -1;
|
||||||
|
} else {
|
||||||
|
policy.lru.prev =
|
||||||
|
test_cases[j - 1][i][current_case];
|
||||||
|
}
|
||||||
|
|
||||||
|
policy.lru.next = test_cases[j + 1][i][current_case];
|
||||||
|
#ifdef DEBUG
|
||||||
|
print_message("[%u] next %u prev %u\n",
|
||||||
|
line, policy.lru.next,
|
||||||
|
policy.lru.prev);
|
||||||
|
#endif
|
||||||
|
return &policy;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
print_message("use case %d cache line %d not found\n",
|
||||||
|
current_case, line);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _lru_run_test(unsigned test_case)
|
||||||
|
{
|
||||||
|
unsigned start_pos;
|
||||||
|
current_case = test_case;
|
||||||
|
|
||||||
|
for (start_pos = 0; start_pos < OCF_NUM_EVICTION_LISTS; start_pos++)
|
||||||
|
{
|
||||||
|
struct ocf_lru_iter iter;
|
||||||
|
ocf_cache_line_t cache_line, expected_cache_line;
|
||||||
|
unsigned curr_evp = start_pos;
|
||||||
|
unsigned pos[OCF_NUM_EVICTION_LISTS];
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
{
|
||||||
|
pos[i] = -1;
|
||||||
|
while(test_cases[pos[i] + 1][i][test_case] != -1)
|
||||||
|
pos[i]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
lru_iter_init(&iter, NULL, NULL, start_pos, false);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* get cacheline from iterator */
|
||||||
|
cache_line = lru_iter_next(&iter);
|
||||||
|
|
||||||
|
/* check what is expected to be returned from iterator */
|
||||||
|
if (pos[curr_evp] == -1) {
|
||||||
|
i = 1;
|
||||||
|
while (i < OCF_NUM_EVICTION_LISTS &&
|
||||||
|
pos[(curr_evp + i) % OCF_NUM_EVICTION_LISTS]
|
||||||
|
== -1) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i == OCF_NUM_EVICTION_LISTS) {
|
||||||
|
/* reached end of lists */
|
||||||
|
expected_cache_line = -1;
|
||||||
|
} else {
|
||||||
|
curr_evp = (curr_evp + i) % OCF_NUM_EVICTION_LISTS;
|
||||||
|
expected_cache_line = test_cases[pos[curr_evp]]
|
||||||
|
[curr_evp][test_case];
|
||||||
|
pos[curr_evp]--;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
expected_cache_line = test_cases[pos[curr_evp]]
|
||||||
|
[curr_evp][test_case];
|
||||||
|
pos[curr_evp]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_int_equal(cache_line, expected_cache_line);
|
||||||
|
|
||||||
|
curr_evp = (curr_evp + 1) % OCF_NUM_EVICTION_LISTS;
|
||||||
|
} while (cache_line != -1);
|
||||||
|
|
||||||
|
/* make sure all cachelines are visited */
|
||||||
|
for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++)
|
||||||
|
{
|
||||||
|
assert_int_equal((unsigned)-1, pos[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test00(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 00\n");
|
||||||
|
_lru_run_test(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test01(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 01\n");
|
||||||
|
_lru_run_test(1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test02(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 02\n");
|
||||||
|
_lru_run_test(2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test03(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 03\n");
|
||||||
|
_lru_run_test(3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test04(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 04\n");
|
||||||
|
_lru_run_test(4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test05(void **state)
|
||||||
|
{
|
||||||
|
|
||||||
|
print_test_description("lru iter test case 05\n");
|
||||||
|
_lru_run_test(5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test06(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 06\n");
|
||||||
|
_lru_run_test(6);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test07(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 07\n");
|
||||||
|
_lru_run_test(7);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test08(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 08\n");
|
||||||
|
_lru_run_test(8);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test09(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 09\n");
|
||||||
|
_lru_run_test(9);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test10(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 00\n");
|
||||||
|
_lru_run_test(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test11(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 11\n");
|
||||||
|
_lru_run_test(11);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test12(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 12\n");
|
||||||
|
_lru_run_test(12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test13(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 13\n");
|
||||||
|
_lru_run_test(13);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test14(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 14\n");
|
||||||
|
_lru_run_test(14);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test15(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 15\n");
|
||||||
|
_lru_run_test(15);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test16(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 16\n");
|
||||||
|
_lru_run_test(16);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test17(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 17\n");
|
||||||
|
_lru_run_test(17);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test18(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 18\n");
|
||||||
|
_lru_run_test(18);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lru_iter_next_test19(void **state)
|
||||||
|
{
|
||||||
|
print_test_description("lru iter test case 19\n");
|
||||||
|
_lru_run_test(19);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(lru_iter_next_test00),
|
||||||
|
cmocka_unit_test(lru_iter_next_test01),
|
||||||
|
cmocka_unit_test(lru_iter_next_test02),
|
||||||
|
cmocka_unit_test(lru_iter_next_test03),
|
||||||
|
cmocka_unit_test(lru_iter_next_test04),
|
||||||
|
cmocka_unit_test(lru_iter_next_test05),
|
||||||
|
cmocka_unit_test(lru_iter_next_test06),
|
||||||
|
cmocka_unit_test(lru_iter_next_test07),
|
||||||
|
cmocka_unit_test(lru_iter_next_test08),
|
||||||
|
cmocka_unit_test(lru_iter_next_test09),
|
||||||
|
cmocka_unit_test(lru_iter_next_test10),
|
||||||
|
cmocka_unit_test(lru_iter_next_test11),
|
||||||
|
cmocka_unit_test(lru_iter_next_test12),
|
||||||
|
cmocka_unit_test(lru_iter_next_test13),
|
||||||
|
cmocka_unit_test(lru_iter_next_test14),
|
||||||
|
cmocka_unit_test(lru_iter_next_test15),
|
||||||
|
cmocka_unit_test(lru_iter_next_test16),
|
||||||
|
cmocka_unit_test(lru_iter_next_test17),
|
||||||
|
cmocka_unit_test(lru_iter_next_test18),
|
||||||
|
cmocka_unit_test(lru_iter_next_test19)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test for lru_iter_next\n");
|
||||||
|
|
||||||
|
write_test_case_description();
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user