Merge pull request #247 from arutk/percpu_freelist_rebased
Per-execution-context freelists
This commit is contained in:
commit
9a46c402b2
58
env/posix/ocf_env.c
vendored
58
env/posix/ocf_env.c
vendored
@ -130,8 +130,64 @@ void env_stack_trace(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* *** CRC *** */
|
/* *** CRC *** */
|
||||||
|
|
||||||
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len)
|
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len)
|
||||||
{
|
{
|
||||||
return crc32(crc, data, len);
|
return crc32(crc, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* *** execution contexts *** */
|
||||||
|
pthread_mutex_t *exec_context_mutex;
|
||||||
|
|
||||||
|
static void __attribute__((constructor)) init_execution_context(void)
|
||||||
|
{
|
||||||
|
unsigned count = env_get_execution_context_count();
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
ENV_BUG_ON(count == 0);
|
||||||
|
exec_context_mutex = malloc(count * sizeof(exec_context_mutex[0]));
|
||||||
|
ENV_BUG_ON(exec_context_mutex == NULL);
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
ENV_BUG_ON(pthread_mutex_init(&exec_context_mutex[i], NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __attribute__((destructor)) deinit_execution_context(void)
|
||||||
|
{
|
||||||
|
unsigned count = env_get_execution_context_count();
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
ENV_BUG_ON(count == 0);
|
||||||
|
ENV_BUG_ON(exec_context_mutex == NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
ENV_BUG_ON(pthread_mutex_destroy(&exec_context_mutex[i]));
|
||||||
|
free(exec_context_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get_execuction_context must assure that after the call finishes, the caller
|
||||||
|
* will not get preempted from current execution context. For userspace env
|
||||||
|
* we simulate this behavior by acquiring per execution context mutex. As a
|
||||||
|
* result the caller might actually get preempted, but no other thread will
|
||||||
|
* execute in this context by the time the caller puts current execution ctx. */
|
||||||
|
unsigned env_get_execution_context(void)
|
||||||
|
{
|
||||||
|
unsigned cpu;
|
||||||
|
|
||||||
|
cpu = sched_getcpu();
|
||||||
|
cpu = (cpu == -1) ? 0 : cpu;
|
||||||
|
|
||||||
|
ENV_BUG_ON(pthread_mutex_lock(&exec_context_mutex[cpu]));
|
||||||
|
|
||||||
|
return cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void env_put_execution_context(unsigned ctx)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&exec_context_mutex[ctx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned env_get_execution_context_count(void)
|
||||||
|
{
|
||||||
|
int num = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
|
||||||
|
return (num == -1) ? 0 : num;
|
||||||
|
}
|
||||||
|
9
env/posix/ocf_env.h
vendored
9
env/posix/ocf_env.h
vendored
@ -455,6 +455,11 @@ static inline void env_spinlock_init(env_spinlock *l)
|
|||||||
ENV_BUG_ON(pthread_spin_init(&l->lock, 0));
|
ENV_BUG_ON(pthread_spin_init(&l->lock, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int env_spinlock_trylock(env_spinlock *l)
|
||||||
|
{
|
||||||
|
return pthread_spin_trylock(&l->lock) ? -OCF_ERR_NO_LOCK : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void env_spinlock_lock(env_spinlock *l)
|
static inline void env_spinlock_lock(env_spinlock *l)
|
||||||
{
|
{
|
||||||
ENV_BUG_ON(pthread_spin_lock(&l->lock));
|
ENV_BUG_ON(pthread_spin_lock(&l->lock));
|
||||||
@ -644,4 +649,8 @@ uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len);
|
|||||||
|
|
||||||
#define ENV_PRIu64 "lu"
|
#define ENV_PRIu64 "lu"
|
||||||
|
|
||||||
|
unsigned env_get_execution_context(void);
|
||||||
|
void env_put_execution_context(unsigned ctx);
|
||||||
|
unsigned env_get_execution_context_count(void);
|
||||||
|
|
||||||
#endif /* __OCF_ENV_H__ */
|
#endif /* __OCF_ENV_H__ */
|
||||||
|
@ -169,7 +169,8 @@ static inline bool ocf_seq_cutoff_is_on(ocf_cache_t cache)
|
|||||||
if (!ocf_cache_is_device_attached(cache))
|
if (!ocf_cache_is_device_attached(cache))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return (cache->device->freelist_part->curr_size <= SEQ_CUTOFF_FULL_MARGIN);
|
return (ocf_freelist_num_free(cache->freelist) <=
|
||||||
|
SEQ_CUTOFF_FULL_MARGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ocf_seq_cutoff_check(ocf_core_t core, uint32_t dir, uint64_t addr,
|
bool ocf_seq_cutoff_check(ocf_core_t core, uint32_t dir, uint64_t addr,
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../ocf_priv.h"
|
#include "../ocf_priv.h"
|
||||||
#include "../ocf_cache_priv.h"
|
#include "../ocf_cache_priv.h"
|
||||||
#include "../ocf_queue_priv.h"
|
#include "../ocf_queue_priv.h"
|
||||||
|
#include "../ocf_freelist.h"
|
||||||
#include "engine_common.h"
|
#include "engine_common.h"
|
||||||
#define OCF_ENGINE_DEBUG_IO_NAME "common"
|
#define OCF_ENGINE_DEBUG_IO_NAME "common"
|
||||||
#include "engine_debug.h"
|
#include "engine_debug.h"
|
||||||
@ -250,19 +251,11 @@ static void ocf_engine_map_cache_line(struct ocf_request *req,
|
|||||||
ocf_part_id_t part_id = req->part_id;
|
ocf_part_id_t part_id = req->part_id;
|
||||||
ocf_cleaning_t clean_policy_type;
|
ocf_cleaning_t clean_policy_type;
|
||||||
|
|
||||||
if (cache->device->freelist_part->curr_size == 0) {
|
if (!ocf_freelist_get_cache_line(cache->freelist, cache_line)) {
|
||||||
req->info.mapping_error = 1;
|
req->info.mapping_error = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*cache_line = cache->device->freelist_part->head;
|
|
||||||
|
|
||||||
/* add_to_collision_list changes .next_col and other fields for entry
|
|
||||||
* so updated last_cache_line_give must be updated before calling it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ocf_metadata_remove_from_free_list(cache, *cache_line);
|
|
||||||
|
|
||||||
ocf_metadata_add_to_partition(cache, part_id, *cache_line);
|
ocf_metadata_add_to_partition(cache, part_id, *cache_line);
|
||||||
|
|
||||||
/* Add the block to the corresponding collision list */
|
/* Add the block to the corresponding collision list */
|
||||||
|
@ -107,11 +107,13 @@ int space_managment_evict_do(struct ocf_cache *cache,
|
|||||||
struct ocf_request *req, uint32_t evict_cline_no)
|
struct ocf_request *req, uint32_t evict_cline_no)
|
||||||
{
|
{
|
||||||
uint32_t evicted;
|
uint32_t evicted;
|
||||||
|
uint32_t free;
|
||||||
|
|
||||||
if (evict_cline_no <= cache->device->freelist_part->curr_size)
|
free = ocf_freelist_num_free(cache->freelist);
|
||||||
|
if (evict_cline_no <= free)
|
||||||
return LOOKUP_MAPPED;
|
return LOOKUP_MAPPED;
|
||||||
|
|
||||||
evict_cline_no -= cache->device->freelist_part->curr_size;
|
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_id);
|
req->part_id);
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ union eviction_policy_meta {
|
|||||||
* set core_id to -2 to purge the whole cache partition
|
* set core_id to -2 to purge the whole cache partition
|
||||||
*/
|
*/
|
||||||
struct eviction_policy_ops {
|
struct eviction_policy_ops {
|
||||||
void (*init_cline)(ocf_cache_t cache,
|
void (*init_cline)(ocf_cache_t cache, ocf_cache_line_t cline);
|
||||||
ocf_cache_line_t cline);
|
|
||||||
void (*rm_cline)(ocf_cache_t cache,
|
void (*rm_cline)(ocf_cache_t cache,
|
||||||
ocf_cache_line_t cline);
|
ocf_cache_line_t cline);
|
||||||
bool (*can_evict)(ocf_cache_t cache);
|
bool (*can_evict)(ocf_cache_t cache);
|
||||||
|
@ -8,8 +8,7 @@
|
|||||||
#include "eviction.h"
|
#include "eviction.h"
|
||||||
#include "lru_structs.h"
|
#include "lru_structs.h"
|
||||||
|
|
||||||
void evp_lru_init_cline(struct ocf_cache *cache,
|
void evp_lru_init_cline(struct ocf_cache *cache, ocf_cache_line_t cline);
|
||||||
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,
|
||||||
|
@ -53,18 +53,18 @@ int ocf_metadata_init_variable_size(struct ocf_cache *cache, uint64_t device_siz
|
|||||||
cache_line_size, layout);
|
cache_line_size, layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_metadata_init_freelist_partition(struct ocf_cache *cache)
|
|
||||||
{
|
|
||||||
OCF_DEBUG_TRACE(cache);
|
|
||||||
cache->metadata.iface.init_freelist(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ocf_metadata_init_hash_table(struct ocf_cache *cache)
|
void ocf_metadata_init_hash_table(struct ocf_cache *cache)
|
||||||
{
|
{
|
||||||
OCF_DEBUG_TRACE(cache);
|
OCF_DEBUG_TRACE(cache);
|
||||||
cache->metadata.iface.init_hash_table(cache);
|
cache->metadata.iface.init_hash_table(cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ocf_metadata_init_collision(struct ocf_cache *cache)
|
||||||
|
{
|
||||||
|
OCF_DEBUG_TRACE(cache);
|
||||||
|
cache->metadata.iface.init_collision(cache);
|
||||||
|
}
|
||||||
|
|
||||||
void ocf_metadata_deinit(struct ocf_cache *cache)
|
void ocf_metadata_deinit(struct ocf_cache *cache)
|
||||||
{
|
{
|
||||||
OCF_DEBUG_TRACE(cache);
|
OCF_DEBUG_TRACE(cache);
|
||||||
|
@ -60,6 +60,13 @@ void ocf_metadata_init_freelist_partition(struct ocf_cache *cache);
|
|||||||
*/
|
*/
|
||||||
void ocf_metadata_init_hash_table(struct ocf_cache *cache);
|
void ocf_metadata_init_hash_table(struct ocf_cache *cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize collision table
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
*/
|
||||||
|
void ocf_metadata_init_collision(struct ocf_cache *cache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief De-Initialize metadata
|
* @brief De-Initialize metadata
|
||||||
*
|
*
|
||||||
@ -207,4 +214,10 @@ typedef void (*ocf_metadata_load_properties_end_t)(void *priv, int error,
|
|||||||
void ocf_metadata_load_properties(ocf_volume_t volume,
|
void ocf_metadata_load_properties(ocf_volume_t volume,
|
||||||
ocf_metadata_load_properties_end_t cmpl, void *priv);
|
ocf_metadata_load_properties_end_t cmpl, void *priv);
|
||||||
|
|
||||||
|
static inline ocf_cache_line_t ocf_metadata_collision_table_entries(
|
||||||
|
struct ocf_cache *cache)
|
||||||
|
{
|
||||||
|
return cache->device->collision_table_entries;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* METADATA_H_ */
|
#endif /* METADATA_H_ */
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "../utils/utils_pipeline.h"
|
#include "../utils/utils_pipeline.h"
|
||||||
#include "../ocf_def_priv.h"
|
#include "../ocf_def_priv.h"
|
||||||
#include "../ocf_priv.h"
|
#include "../ocf_priv.h"
|
||||||
|
#include "../ocf_freelist.h"
|
||||||
|
|
||||||
#define OCF_METADATA_HASH_DEBUG 0
|
#define OCF_METADATA_HASH_DEBUG 0
|
||||||
|
|
||||||
@ -1025,14 +1026,10 @@ finalize:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void _ocf_init_collision_entry(struct ocf_cache *cache,
|
static inline void _ocf_init_collision_entry(struct ocf_cache *cache,
|
||||||
ocf_cache_line_t idx, ocf_cache_line_t next,
|
ocf_cache_line_t idx)
|
||||||
ocf_cache_line_t prev)
|
|
||||||
{
|
{
|
||||||
ocf_cache_line_t invalid_idx = cache->device->collision_table_entries;
|
ocf_cache_line_t invalid_idx = cache->device->collision_table_entries;
|
||||||
ocf_part_id_t invalid_part_id = PARTITION_INVALID;
|
|
||||||
|
|
||||||
ocf_metadata_set_partition_info(cache, idx,
|
|
||||||
invalid_part_id, next, prev);
|
|
||||||
ocf_metadata_set_collision_info(cache, idx, invalid_idx, invalid_idx);
|
ocf_metadata_set_collision_info(cache, idx, invalid_idx, invalid_idx);
|
||||||
ocf_metadata_set_core_info(cache, idx,
|
ocf_metadata_set_core_info(cache, idx,
|
||||||
OCF_CORE_MAX, ULONG_MAX);
|
OCF_CORE_MAX, ULONG_MAX);
|
||||||
@ -1040,36 +1037,17 @@ static inline void _ocf_init_collision_entry(struct ocf_cache *cache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modified initialization of freelist partition
|
* Initialize collision table
|
||||||
*/
|
*/
|
||||||
static void ocf_metadata_hash_init_freelist(struct ocf_cache *cache)
|
static void ocf_metadata_hash_init_collision(struct ocf_cache *cache)
|
||||||
{
|
{
|
||||||
uint32_t step = 0;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
ocf_cache_line_t prev, next;
|
|
||||||
ocf_cache_line_t idx;
|
|
||||||
ocf_cache_line_t collision_table_entries =
|
|
||||||
cache->device->collision_table_entries;
|
|
||||||
|
|
||||||
prev = collision_table_entries;
|
for (i = 0; i < cache->device->collision_table_entries; i++) {
|
||||||
idx = 0;
|
_ocf_init_collision_entry(cache, i);
|
||||||
for (i = 0; i < cache->device->collision_table_entries - 1; i++) {
|
|
||||||
next = ocf_metadata_map_phy2lg(cache, i + 1);
|
|
||||||
_ocf_init_collision_entry(cache, idx, next, prev);
|
|
||||||
prev = idx;
|
|
||||||
idx = next;
|
|
||||||
OCF_COND_RESCHED_DEFAULT(step);
|
|
||||||
}
|
}
|
||||||
_ocf_init_collision_entry(cache, idx, collision_table_entries, prev);
|
|
||||||
|
|
||||||
/* Initialize freelist partition */
|
|
||||||
cache->device->freelist_part->head = 0;
|
|
||||||
cache->device->freelist_part->tail = idx;
|
|
||||||
cache->device->freelist_part->curr_size = cache->device->
|
|
||||||
collision_table_entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize hash table
|
* Initialize hash table
|
||||||
*/
|
*/
|
||||||
@ -1850,8 +1828,6 @@ static void _recovery_rebuild_cline_metadata(ocf_cache_t cache,
|
|||||||
|
|
||||||
part_id = PARTITION_DEFAULT;
|
part_id = PARTITION_DEFAULT;
|
||||||
|
|
||||||
ocf_metadata_remove_from_free_list(cache, cache_line);
|
|
||||||
|
|
||||||
ocf_metadata_add_to_partition(cache, part_id, cache_line);
|
ocf_metadata_add_to_partition(cache, part_id, cache_line);
|
||||||
|
|
||||||
hash_index = ocf_metadata_hash_func(cache, core_line, core_id);
|
hash_index = ocf_metadata_hash_func(cache, core_line, core_id);
|
||||||
@ -1917,10 +1893,12 @@ static void _recovery_rebuild_metadata(ocf_pipeline_t pipeline,
|
|||||||
ocf_core_id_t core_id;
|
ocf_core_id_t core_id;
|
||||||
uint64_t core_line;
|
uint64_t core_line;
|
||||||
unsigned char step = 0;
|
unsigned char step = 0;
|
||||||
|
const uint64_t collision_table_entries =
|
||||||
|
ocf_metadata_collision_table_entries(cache);
|
||||||
|
|
||||||
OCF_METADATA_LOCK_WR();
|
OCF_METADATA_LOCK_WR();
|
||||||
|
|
||||||
for (cline = 0; cline < cache->device->collision_table_entries; cline++) {
|
for (cline = 0; cline < collision_table_entries; cline++) {
|
||||||
ocf_metadata_get_core_info(cache, cline, &core_id, &core_line);
|
ocf_metadata_get_core_info(cache, cline, &core_id, &core_line);
|
||||||
if (core_id != OCF_CORE_MAX &&
|
if (core_id != OCF_CORE_MAX &&
|
||||||
(!dirty_only || metadata_test_dirty(cache,
|
(!dirty_only || metadata_test_dirty(cache,
|
||||||
@ -2648,7 +2626,7 @@ static const struct ocf_metadata_iface metadata_hash_iface = {
|
|||||||
.init_variable_size = ocf_metadata_hash_init_variable_size,
|
.init_variable_size = ocf_metadata_hash_init_variable_size,
|
||||||
.deinit_variable_size = ocf_metadata_hash_deinit_variable_size,
|
.deinit_variable_size = ocf_metadata_hash_deinit_variable_size,
|
||||||
.init_hash_table = ocf_metadata_hash_init_hash_table,
|
.init_hash_table = ocf_metadata_hash_init_hash_table,
|
||||||
.init_freelist = ocf_metadata_hash_init_freelist,
|
.init_collision = ocf_metadata_hash_init_collision,
|
||||||
|
|
||||||
.layout_iface = NULL,
|
.layout_iface = NULL,
|
||||||
.pages = ocf_metadata_hash_pages,
|
.pages = ocf_metadata_hash_pages,
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "ocf/ocf.h"
|
#include "ocf/ocf.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
|
#include "../ocf_freelist.h"
|
||||||
#include "../utils/utils_cache_line.h"
|
#include "../utils/utils_cache_line.h"
|
||||||
|
|
||||||
static bool _is_cache_line_acting(struct ocf_cache *cache,
|
static bool _is_cache_line_acting(struct ocf_cache *cache,
|
||||||
@ -100,7 +101,7 @@ void ocf_metadata_sparse_cache_line(struct ocf_cache *cache,
|
|||||||
|
|
||||||
ocf_metadata_remove_from_partition(cache, partition_id, cache_line);
|
ocf_metadata_remove_from_partition(cache, partition_id, cache_line);
|
||||||
|
|
||||||
ocf_metadata_add_to_free_list(cache, cache_line);
|
ocf_freelist_put_cache_line(cache->freelist, cache_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _ocf_metadata_sparse_cache_line(struct ocf_cache *cache,
|
static void _ocf_metadata_sparse_cache_line(struct ocf_cache *cache,
|
||||||
|
@ -16,99 +16,6 @@ static void update_partition_head(struct ocf_cache *cache,
|
|||||||
part->runtime->head = line;
|
part->runtime->head = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_metadata_remove_from_free_list(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t cline)
|
|
||||||
{
|
|
||||||
struct ocf_part *free_list = cache->device->freelist_part;
|
|
||||||
int is_head, is_tail;
|
|
||||||
ocf_part_id_t invalid_part_id = PARTITION_INVALID;
|
|
||||||
ocf_cache_line_t prev, next;
|
|
||||||
ocf_cache_line_t line_entries = cache->device->collision_table_entries;
|
|
||||||
|
|
||||||
ENV_BUG_ON(cline >= line_entries);
|
|
||||||
|
|
||||||
/* Get Partition info */
|
|
||||||
ocf_metadata_get_partition_info(cache, cline, NULL, &next, &prev);
|
|
||||||
|
|
||||||
/* Find out if this node is Partition _head_ */
|
|
||||||
is_head = (prev == line_entries);
|
|
||||||
is_tail = (next == line_entries);
|
|
||||||
|
|
||||||
/* Case 1: If we are head and there is only one node. So unlink node
|
|
||||||
* and set that there is no node left in the list.
|
|
||||||
*/
|
|
||||||
if (is_head && (free_list->curr_size == 1)) {
|
|
||||||
ocf_metadata_set_partition_info(cache, cline, invalid_part_id,
|
|
||||||
line_entries, line_entries);
|
|
||||||
free_list->head = line_entries;
|
|
||||||
free_list->tail = line_entries;
|
|
||||||
} else if (is_head) {
|
|
||||||
/* Case 2: else if this collision_index is partition list head,
|
|
||||||
* but many nodes, update head and return
|
|
||||||
*/
|
|
||||||
ENV_BUG_ON(next >= line_entries);
|
|
||||||
|
|
||||||
free_list->head = next;
|
|
||||||
ocf_metadata_set_partition_prev(cache, next, line_entries);
|
|
||||||
ocf_metadata_set_partition_next(cache, cline, line_entries);
|
|
||||||
} else if (is_tail) {
|
|
||||||
/* Case 3: else if this cline is partition list tail */
|
|
||||||
ENV_BUG_ON(prev >= line_entries);
|
|
||||||
|
|
||||||
free_list->tail = prev;
|
|
||||||
ocf_metadata_set_partition_prev(cache, cline, line_entries);
|
|
||||||
ocf_metadata_set_partition_next(cache, prev, line_entries);
|
|
||||||
} else {
|
|
||||||
/* Case 4: else this collision_index is a middle node.
|
|
||||||
* There is no change to the head and the tail pointers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ENV_BUG_ON(next >= line_entries || prev >= line_entries);
|
|
||||||
|
|
||||||
/* Update prev and next nodes */
|
|
||||||
ocf_metadata_set_partition_prev(cache, next, prev);
|
|
||||||
ocf_metadata_set_partition_next(cache, prev, next);
|
|
||||||
|
|
||||||
/* Update the given node */
|
|
||||||
ocf_metadata_set_partition_info(cache, cline, invalid_part_id,
|
|
||||||
line_entries, line_entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
free_list->curr_size--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ocf_metadata_add_to_free_list(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t line)
|
|
||||||
{
|
|
||||||
struct ocf_part *free_list = cache->device->freelist_part;
|
|
||||||
ocf_cache_line_t tail;
|
|
||||||
ocf_cache_line_t line_entries = cache->device->collision_table_entries;
|
|
||||||
ocf_part_id_t invalid_part_id = PARTITION_INVALID;
|
|
||||||
|
|
||||||
ENV_BUG_ON(line >= line_entries);
|
|
||||||
|
|
||||||
if (free_list->curr_size == 0) {
|
|
||||||
free_list->head = line;
|
|
||||||
free_list->tail = line;
|
|
||||||
|
|
||||||
ocf_metadata_set_partition_info(cache, line, invalid_part_id,
|
|
||||||
line_entries, line_entries);
|
|
||||||
} else {
|
|
||||||
tail = free_list->tail;
|
|
||||||
|
|
||||||
ENV_BUG_ON(tail >= line_entries);
|
|
||||||
|
|
||||||
ocf_metadata_set_partition_info(cache, line, invalid_part_id,
|
|
||||||
line_entries, tail);
|
|
||||||
ocf_metadata_set_partition_next(cache, tail, line);
|
|
||||||
|
|
||||||
free_list->tail = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_list->curr_size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Adds the given collision_index to the _head_ of the Partition list */
|
/* Adds the given collision_index to the _head_ of the Partition list */
|
||||||
void ocf_metadata_add_to_partition(struct ocf_cache *cache,
|
void ocf_metadata_add_to_partition(struct ocf_cache *cache,
|
||||||
ocf_part_id_t part_id, ocf_cache_line_t line)
|
ocf_part_id_t part_id, ocf_cache_line_t line)
|
||||||
|
@ -75,12 +75,6 @@ static inline void ocf_metadata_set_partition_info(
|
|||||||
next_line, prev_line);
|
next_line, prev_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ocf_metadata_add_to_free_list(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t cline);
|
|
||||||
|
|
||||||
void ocf_metadata_remove_from_free_list(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t cline);
|
|
||||||
|
|
||||||
void ocf_metadata_add_to_partition(struct ocf_cache *cache,
|
void ocf_metadata_add_to_partition(struct ocf_cache *cache,
|
||||||
ocf_part_id_t part_id, ocf_cache_line_t line);
|
ocf_part_id_t part_id, ocf_cache_line_t line);
|
||||||
|
|
||||||
|
@ -10,12 +10,6 @@
|
|||||||
#include "../cleaning/cleaning.h"
|
#include "../cleaning/cleaning.h"
|
||||||
#include "../eviction/eviction.h"
|
#include "../eviction/eviction.h"
|
||||||
|
|
||||||
struct ocf_part {
|
|
||||||
ocf_cache_line_t head;
|
|
||||||
ocf_cache_line_t tail;
|
|
||||||
uint32_t curr_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ocf_user_part_config {
|
struct ocf_user_part_config {
|
||||||
char name[OCF_IO_CLASS_NAME_MAX];
|
char name[OCF_IO_CLASS_NAME_MAX];
|
||||||
uint32_t min_size;
|
uint32_t min_size;
|
||||||
|
@ -124,13 +124,6 @@ struct ocf_metadata_iface {
|
|||||||
struct ocf_volume_uuid *uuid, uint32_t count,
|
struct ocf_volume_uuid *uuid, uint32_t count,
|
||||||
ocf_metadata_query_cores_end_t cmpl, void *priv);
|
ocf_metadata_query_cores_end_t cmpl, void *priv);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize freelist partition
|
|
||||||
*
|
|
||||||
* @param cache - Cache instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
void (*init_freelist)(struct ocf_cache *cache);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Metadata cache line location on pages interface
|
* @brief Metadata cache line location on pages interface
|
||||||
@ -144,6 +137,13 @@ struct ocf_metadata_iface {
|
|||||||
*/
|
*/
|
||||||
void (*init_hash_table)(struct ocf_cache *cache);
|
void (*init_hash_table)(struct ocf_cache *cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize collision table
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
*/
|
||||||
|
void (*init_collision)(struct ocf_cache *cache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief De-Initialize metadata
|
* @brief De-Initialize metadata
|
||||||
*
|
*
|
||||||
|
@ -59,8 +59,6 @@ struct ocf_superblock_config {
|
|||||||
* @brief OCF cache metadata runtime superblock
|
* @brief OCF cache metadata runtime superblock
|
||||||
*/
|
*/
|
||||||
struct ocf_superblock_runtime {
|
struct ocf_superblock_runtime {
|
||||||
struct ocf_part freelist_part;
|
|
||||||
|
|
||||||
uint32_t cleaning_thread_access;
|
uint32_t cleaning_thread_access;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "../concurrency/ocf_concurrency.h"
|
#include "../concurrency/ocf_concurrency.h"
|
||||||
#include "../eviction/ops.h"
|
#include "../eviction/ops.h"
|
||||||
#include "../ocf_ctx_priv.h"
|
#include "../ocf_ctx_priv.h"
|
||||||
|
#include "../ocf_freelist.h"
|
||||||
#include "../cleaning/cleaning.h"
|
#include "../cleaning/cleaning.h"
|
||||||
|
|
||||||
#define OCF_ASSERT_PLUGGED(cache) ENV_BUG_ON(!(cache)->device)
|
#define OCF_ASSERT_PLUGGED(cache) ENV_BUG_ON(!(cache)->device)
|
||||||
@ -117,6 +118,8 @@ struct ocf_cache_attach_context {
|
|||||||
* load or recovery
|
* load or recovery
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
bool freelist_inited : 1;
|
||||||
|
|
||||||
bool concurrency_inited : 1;
|
bool concurrency_inited : 1;
|
||||||
} flags;
|
} flags;
|
||||||
|
|
||||||
@ -156,18 +159,6 @@ struct ocf_cache_attach_context {
|
|||||||
ocf_pipeline_t pipeline;
|
ocf_pipeline_t pipeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init_hash_table(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
/* Initialize hash table*/
|
|
||||||
ocf_metadata_init_hash_table(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init_freelist(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
/* Initialize free list partition*/
|
|
||||||
ocf_metadata_init_freelist_partition(cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init_partitions(ocf_cache_t cache)
|
static void __init_partitions(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
ocf_part_id_t i_part;
|
ocf_part_id_t i_part;
|
||||||
@ -204,6 +195,14 @@ static void __init_partitions_attached(ocf_cache_t cache)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __init_freelist(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
uint64_t free_clines = ocf_metadata_collision_table_entries(cache) -
|
||||||
|
ocf_get_cache_occupancy(cache);
|
||||||
|
|
||||||
|
ocf_freelist_populate(cache->freelist, free_clines);
|
||||||
|
}
|
||||||
|
|
||||||
static ocf_error_t __init_cleaning_policy(ocf_cache_t cache)
|
static ocf_error_t __init_cleaning_policy(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
ocf_cleaning_t cleaning_policy = ocf_cleaning_default;
|
ocf_cleaning_t cleaning_policy = ocf_cleaning_default;
|
||||||
@ -295,9 +294,10 @@ static ocf_error_t init_attached_data_structures(ocf_cache_t cache,
|
|||||||
/* Lock to ensure consistency */
|
/* Lock to ensure consistency */
|
||||||
OCF_METADATA_LOCK_WR();
|
OCF_METADATA_LOCK_WR();
|
||||||
|
|
||||||
__init_hash_table(cache);
|
ocf_metadata_init_hash_table(cache);
|
||||||
__init_freelist(cache);
|
ocf_metadata_init_collision(cache);
|
||||||
__init_partitions_attached(cache);
|
__init_partitions_attached(cache);
|
||||||
|
__init_freelist(cache);
|
||||||
|
|
||||||
result = __init_cleaning_policy(cache);
|
result = __init_cleaning_policy(cache);
|
||||||
if (result) {
|
if (result) {
|
||||||
@ -325,8 +325,8 @@ static ocf_error_t init_attached_data_structures(ocf_cache_t cache,
|
|||||||
static void init_attached_data_structures_recovery(ocf_cache_t cache)
|
static void init_attached_data_structures_recovery(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
OCF_METADATA_LOCK_WR();
|
OCF_METADATA_LOCK_WR();
|
||||||
__init_hash_table(cache);
|
ocf_metadata_init_hash_table(cache);
|
||||||
__init_freelist(cache);
|
ocf_metadata_init_collision(cache);
|
||||||
__init_partitions_attached(cache);
|
__init_partitions_attached(cache);
|
||||||
__reset_stats(cache);
|
__reset_stats(cache);
|
||||||
__init_metadata_version(cache);
|
__init_metadata_version(cache);
|
||||||
@ -469,6 +469,8 @@ void _ocf_mngt_init_instance_load_complete(void *priv, int error)
|
|||||||
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__init_freelist(cache);
|
||||||
|
|
||||||
result = __init_promotion_policy(cache);
|
result = __init_promotion_policy(cache);
|
||||||
if (result) {
|
if (result) {
|
||||||
ocf_cache_log(cache, log_err,
|
ocf_cache_log(cache, log_err,
|
||||||
@ -985,8 +987,10 @@ static void _ocf_mngt_attach_prepare_metadata(ocf_pipeline_t pipeline,
|
|||||||
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cache->freelist = ocf_freelist_init(cache);
|
||||||
cache->device->freelist_part = &cache->device->runtime_meta->freelist_part;
|
if (!cache->freelist)
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||||
|
context->flags.freelist_inited = true;
|
||||||
|
|
||||||
ret = ocf_concurrency_init(cache);
|
ret = ocf_concurrency_init(cache);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1143,6 +1147,9 @@ static void _ocf_mngt_attach_handle_error(
|
|||||||
if (context->flags.concurrency_inited)
|
if (context->flags.concurrency_inited)
|
||||||
ocf_concurrency_deinit(cache);
|
ocf_concurrency_deinit(cache);
|
||||||
|
|
||||||
|
if (context->flags.freelist_inited)
|
||||||
|
ocf_freelist_deinit(cache->freelist);
|
||||||
|
|
||||||
if (context->flags.volume_inited)
|
if (context->flags.volume_inited)
|
||||||
ocf_volume_deinit(&cache->device->volume);
|
ocf_volume_deinit(&cache->device->volume);
|
||||||
|
|
||||||
@ -1725,6 +1732,7 @@ static void _ocf_mngt_cache_unplug_complete(void *priv, int error)
|
|||||||
|
|
||||||
ocf_metadata_deinit_variable_size(cache);
|
ocf_metadata_deinit_variable_size(cache);
|
||||||
ocf_concurrency_deinit(cache);
|
ocf_concurrency_deinit(cache);
|
||||||
|
ocf_freelist_deinit(cache->freelist);
|
||||||
|
|
||||||
ocf_volume_deinit(&cache->device->volume);
|
ocf_volume_deinit(&cache->device->volume);
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "ocf_logger_priv.h"
|
#include "ocf_logger_priv.h"
|
||||||
#include "ocf/ocf_trace.h"
|
#include "ocf/ocf_trace.h"
|
||||||
#include "promotion/promotion.h"
|
#include "promotion/promotion.h"
|
||||||
|
#include "ocf_freelist.h"
|
||||||
|
|
||||||
#define DIRTY_FLUSHED 1
|
#define DIRTY_FLUSHED 1
|
||||||
#define DIRTY_NOT_FLUSHED 0
|
#define DIRTY_NOT_FLUSHED 0
|
||||||
@ -82,8 +83,6 @@ struct ocf_cache_device {
|
|||||||
|
|
||||||
uint64_t metadata_offset;
|
uint64_t metadata_offset;
|
||||||
|
|
||||||
struct ocf_part *freelist_part;
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct ocf_cache_line_concurrency *cache_line;
|
struct ocf_cache_line_concurrency *cache_line;
|
||||||
} concurrency;
|
} concurrency;
|
||||||
@ -110,6 +109,8 @@ struct ocf_cache {
|
|||||||
|
|
||||||
struct ocf_metadata metadata;
|
struct ocf_metadata metadata;
|
||||||
|
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
|
||||||
ocf_eviction_t eviction_policy_init;
|
ocf_eviction_t eviction_policy_init;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -199,4 +200,16 @@ static inline ocf_core_t ocf_cache_get_core(ocf_cache_t cache,
|
|||||||
#define ocf_cache_log_rl(cache) \
|
#define ocf_cache_log_rl(cache) \
|
||||||
ocf_log_rl(ocf_cache_get_ctx(cache))
|
ocf_log_rl(ocf_cache_get_ctx(cache))
|
||||||
|
|
||||||
|
static inline uint64_t ocf_get_cache_occupancy(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
uint64_t result = 0;
|
||||||
|
ocf_core_t core;
|
||||||
|
ocf_core_id_t core_id;
|
||||||
|
|
||||||
|
for_each_core(cache, core, core_id)
|
||||||
|
result += env_atomic_read(&core->runtime_meta->cached_clines);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __OCF_CACHE_PRIV_H__ */
|
#endif /* __OCF_CACHE_PRIV_H__ */
|
||||||
|
420
src/ocf_freelist.c
Normal file
420
src/ocf_freelist.c
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
/*
|
||||||
|
* Copyright(c) 2019-2019 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ocf/ocf.h"
|
||||||
|
#include "metadata/metadata.h"
|
||||||
|
|
||||||
|
struct ocf_part {
|
||||||
|
ocf_cache_line_t head;
|
||||||
|
ocf_cache_line_t tail;
|
||||||
|
env_atomic64 curr_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ocf_freelist {
|
||||||
|
/* parent cache */
|
||||||
|
struct ocf_cache *cache;
|
||||||
|
|
||||||
|
/* partition list array */
|
||||||
|
struct ocf_part *part;
|
||||||
|
|
||||||
|
/* freelist lock array */
|
||||||
|
env_spinlock *lock;
|
||||||
|
|
||||||
|
/* number of free lists */
|
||||||
|
uint32_t count;
|
||||||
|
|
||||||
|
/* next slowpath victim idx */
|
||||||
|
env_atomic slowpath_victim_idx;
|
||||||
|
|
||||||
|
/* total number of free lines */
|
||||||
|
env_atomic64 total_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ocf_freelist_lock(ocf_freelist_t freelist, uint32_t ctx)
|
||||||
|
{
|
||||||
|
env_spinlock_lock(&freelist->lock[ctx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ocf_freelist_trylock(ocf_freelist_t freelist, uint32_t ctx)
|
||||||
|
{
|
||||||
|
return env_spinlock_trylock(&freelist->lock[ctx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_unlock(ocf_freelist_t freelist, uint32_t ctx)
|
||||||
|
{
|
||||||
|
env_spinlock_unlock(&freelist->lock[ctx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets the given collision_index as the new _head_ of the Partition list. */
|
||||||
|
static void _ocf_freelist_remove_cache_line(ocf_freelist_t freelist,
|
||||||
|
uint32_t ctx, ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
struct ocf_cache *cache = freelist->cache;
|
||||||
|
struct ocf_part *freelist_part = &freelist->part[ctx];
|
||||||
|
int is_head, is_tail;
|
||||||
|
ocf_part_id_t invalid_part_id = PARTITION_INVALID;
|
||||||
|
ocf_cache_line_t prev, next;
|
||||||
|
ocf_cache_line_t line_entries = ocf_metadata_collision_table_entries(
|
||||||
|
freelist->cache);
|
||||||
|
uint32_t free;
|
||||||
|
|
||||||
|
ENV_BUG_ON(cline >= line_entries);
|
||||||
|
|
||||||
|
/* Get Partition info */
|
||||||
|
ocf_metadata_get_partition_info(cache, cline, NULL, &next, &prev);
|
||||||
|
|
||||||
|
/* Find out if this node is Partition _head_ */
|
||||||
|
is_head = (prev == line_entries);
|
||||||
|
is_tail = (next == line_entries);
|
||||||
|
|
||||||
|
free = env_atomic64_read(&freelist_part->curr_size);
|
||||||
|
|
||||||
|
/* Case 1: If we are head and there is only one node. So unlink node
|
||||||
|
* and set that there is no node left in the list.
|
||||||
|
*/
|
||||||
|
if (is_head && free == 1) {
|
||||||
|
ocf_metadata_set_partition_info(cache, cline, invalid_part_id,
|
||||||
|
line_entries, line_entries);
|
||||||
|
freelist_part->head = line_entries;
|
||||||
|
freelist_part->tail = line_entries;
|
||||||
|
} else if (is_head) {
|
||||||
|
/* Case 2: else if this collision_index is partition list head,
|
||||||
|
* but many nodes, update head and return
|
||||||
|
*/
|
||||||
|
ENV_BUG_ON(next >= line_entries);
|
||||||
|
|
||||||
|
freelist_part->head = next;
|
||||||
|
ocf_metadata_set_partition_prev(cache, next, line_entries);
|
||||||
|
ocf_metadata_set_partition_next(cache, cline, line_entries);
|
||||||
|
} else if (is_tail) {
|
||||||
|
/* Case 3: else if this cline is partition list tail */
|
||||||
|
ENV_BUG_ON(prev >= line_entries);
|
||||||
|
|
||||||
|
freelist_part->tail = prev;
|
||||||
|
ocf_metadata_set_partition_prev(cache, cline, line_entries);
|
||||||
|
ocf_metadata_set_partition_next(cache, prev, line_entries);
|
||||||
|
} else {
|
||||||
|
/* Case 4: else this collision_index is a middle node.
|
||||||
|
* There is no change to the head and the tail pointers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ENV_BUG_ON(next >= line_entries || prev >= line_entries);
|
||||||
|
|
||||||
|
/* Update prev and next nodes */
|
||||||
|
ocf_metadata_set_partition_prev(cache, next, prev);
|
||||||
|
ocf_metadata_set_partition_next(cache, prev, next);
|
||||||
|
|
||||||
|
/* Update the given node */
|
||||||
|
ocf_metadata_set_partition_info(cache, cline, invalid_part_id,
|
||||||
|
line_entries, line_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic64_dec(&freelist_part->curr_size);
|
||||||
|
env_atomic64_dec(&freelist->total_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ocf_cache_line_t next_phys_invalid(ocf_cache_t cache,
|
||||||
|
ocf_cache_line_t phys)
|
||||||
|
{
|
||||||
|
ocf_cache_line_t lg;
|
||||||
|
ocf_cache_line_t collision_table_entries =
|
||||||
|
ocf_metadata_collision_table_entries(cache);
|
||||||
|
|
||||||
|
if (phys == collision_table_entries)
|
||||||
|
return collision_table_entries;
|
||||||
|
|
||||||
|
lg = ocf_metadata_map_phy2lg(cache, phys);
|
||||||
|
while (metadata_test_valid_any(cache, lg)) {
|
||||||
|
++phys;
|
||||||
|
|
||||||
|
if (phys == collision_table_entries)
|
||||||
|
break;
|
||||||
|
|
||||||
|
lg = ocf_metadata_map_phy2lg(cache, phys);
|
||||||
|
}
|
||||||
|
|
||||||
|
return phys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign unused cachelines to freelist */
|
||||||
|
void ocf_freelist_populate(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t num_free_clines)
|
||||||
|
{
|
||||||
|
unsigned step = 0;
|
||||||
|
ocf_cache_t cache = freelist->cache;
|
||||||
|
unsigned num_freelists = freelist->count;
|
||||||
|
ocf_cache_line_t prev, next, idx;
|
||||||
|
ocf_cache_line_t phys;
|
||||||
|
ocf_cache_line_t collision_table_entries =
|
||||||
|
ocf_metadata_collision_table_entries(cache);
|
||||||
|
unsigned freelist_idx;
|
||||||
|
uint64_t freelist_size;
|
||||||
|
|
||||||
|
phys = 0;
|
||||||
|
for (freelist_idx = 0; freelist_idx < num_freelists; freelist_idx++)
|
||||||
|
{
|
||||||
|
/* calculate current freelist size */
|
||||||
|
freelist_size = num_free_clines / num_freelists;
|
||||||
|
if (freelist_idx < (num_free_clines % num_freelists))
|
||||||
|
++freelist_size;
|
||||||
|
|
||||||
|
env_atomic64_set(&freelist->part[freelist_idx].curr_size,
|
||||||
|
freelist_size);
|
||||||
|
|
||||||
|
if (!freelist_size) {
|
||||||
|
/* init empty freelist and move to next one */
|
||||||
|
freelist->part[freelist_idx].head =
|
||||||
|
collision_table_entries;
|
||||||
|
freelist->part[freelist_idx].tail =
|
||||||
|
collision_table_entries;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find first invalid cacheline */
|
||||||
|
phys = next_phys_invalid(cache, phys);
|
||||||
|
ENV_BUG_ON(phys == collision_table_entries);
|
||||||
|
idx = ocf_metadata_map_phy2lg(cache, phys);
|
||||||
|
++phys;
|
||||||
|
|
||||||
|
/* store freelist head */
|
||||||
|
freelist->part[freelist_idx].head = idx;
|
||||||
|
|
||||||
|
/* link freelist elements using partition list */
|
||||||
|
prev = collision_table_entries;
|
||||||
|
while (--freelist_size) {
|
||||||
|
phys = next_phys_invalid(cache, phys);
|
||||||
|
ENV_BUG_ON(phys == collision_table_entries);
|
||||||
|
next = ocf_metadata_map_phy2lg(cache, phys);
|
||||||
|
++phys;
|
||||||
|
|
||||||
|
ocf_metadata_set_partition_info(cache, idx,
|
||||||
|
PARTITION_INVALID, next, prev);
|
||||||
|
|
||||||
|
prev = idx;
|
||||||
|
idx = next;
|
||||||
|
|
||||||
|
OCF_COND_RESCHED_DEFAULT(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* terminate partition list */
|
||||||
|
ocf_metadata_set_partition_info(cache, idx, PARTITION_INVALID,
|
||||||
|
collision_table_entries, prev);
|
||||||
|
|
||||||
|
/* store freelist tail */
|
||||||
|
freelist->part[freelist_idx].tail = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we should have reached the last invalid cache line */
|
||||||
|
phys = next_phys_invalid(cache, phys);
|
||||||
|
ENV_BUG_ON(phys != collision_table_entries);
|
||||||
|
|
||||||
|
env_atomic64_set(&freelist->total_free, num_free_clines);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_add_cache_line(ocf_freelist_t freelist,
|
||||||
|
uint32_t ctx, ocf_cache_line_t line)
|
||||||
|
{
|
||||||
|
struct ocf_cache *cache = freelist->cache;
|
||||||
|
struct ocf_part *freelist_part = &freelist->part[ctx];
|
||||||
|
ocf_cache_line_t tail;
|
||||||
|
ocf_cache_line_t line_entries = ocf_metadata_collision_table_entries(
|
||||||
|
freelist->cache);
|
||||||
|
ocf_part_id_t invalid_part_id = PARTITION_INVALID;
|
||||||
|
|
||||||
|
ENV_BUG_ON(line >= line_entries);
|
||||||
|
|
||||||
|
if (env_atomic64_read(&freelist_part->curr_size) == 0) {
|
||||||
|
freelist_part->head = line;
|
||||||
|
freelist_part->tail = line;
|
||||||
|
|
||||||
|
ocf_metadata_set_partition_info(cache, line, invalid_part_id,
|
||||||
|
line_entries, line_entries);
|
||||||
|
} else {
|
||||||
|
tail = freelist_part->tail;
|
||||||
|
|
||||||
|
ENV_BUG_ON(tail >= line_entries);
|
||||||
|
|
||||||
|
ocf_metadata_set_partition_info(cache, line, invalid_part_id,
|
||||||
|
line_entries, tail);
|
||||||
|
ocf_metadata_set_partition_next(cache, tail, line);
|
||||||
|
|
||||||
|
freelist_part->tail = line;
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic64_inc(&freelist_part->curr_size);
|
||||||
|
env_atomic64_inc(&freelist->total_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OCF_FREELIST_ERR_NOLOCK = 1,
|
||||||
|
OCF_FREELIST_ERR_LIST_EMPTY,
|
||||||
|
} ocf_freelist_get_err_t;
|
||||||
|
|
||||||
|
static ocf_freelist_get_err_t ocf_freelist_get_cache_line_ctx(
|
||||||
|
ocf_freelist_t freelist, uint32_t ctx, bool can_wait,
|
||||||
|
ocf_cache_line_t *cline)
|
||||||
|
{
|
||||||
|
if (env_atomic64_read(&freelist->part[ctx].curr_size) == 0)
|
||||||
|
return -OCF_FREELIST_ERR_LIST_EMPTY;
|
||||||
|
|
||||||
|
if (!can_wait && ocf_freelist_trylock(freelist, ctx))
|
||||||
|
return -OCF_FREELIST_ERR_NOLOCK;
|
||||||
|
|
||||||
|
if (can_wait)
|
||||||
|
ocf_freelist_lock(freelist, ctx);
|
||||||
|
|
||||||
|
if (env_atomic64_read(&freelist->part[ctx].curr_size) == 0) {
|
||||||
|
ocf_freelist_unlock(freelist, ctx);
|
||||||
|
return -OCF_FREELIST_ERR_LIST_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cline = freelist->part[ctx].head;
|
||||||
|
_ocf_freelist_remove_cache_line(freelist, ctx, *cline);
|
||||||
|
|
||||||
|
ocf_freelist_unlock(freelist, ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_victim_freelist(ocf_freelist_t freelist)
|
||||||
|
{
|
||||||
|
int ctx, next;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ctx = env_atomic_read(&freelist->slowpath_victim_idx);
|
||||||
|
next = (ctx + 1) % freelist->count;
|
||||||
|
} while (ctx != env_atomic_cmpxchg(&freelist->slowpath_victim_idx, ctx,
|
||||||
|
next));
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ocf_freelist_get_cache_line_slow(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t *cline)
|
||||||
|
{
|
||||||
|
int i, ctx;
|
||||||
|
int err;
|
||||||
|
bool lock_err;
|
||||||
|
|
||||||
|
/* try slowpath without waiting on lock */
|
||||||
|
lock_err = false;
|
||||||
|
for (i = 0; i < freelist->count; i++) {
|
||||||
|
ctx = get_next_victim_freelist(freelist);
|
||||||
|
err = ocf_freelist_get_cache_line_ctx(freelist, ctx, false,
|
||||||
|
cline);
|
||||||
|
if (!err)
|
||||||
|
return true;
|
||||||
|
if (err == -OCF_FREELIST_ERR_NOLOCK)
|
||||||
|
lock_err = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lock_err) {
|
||||||
|
/* Slowpath failed due to empty freelists - no point in
|
||||||
|
* iterating through contexts to attempt slowpath with full
|
||||||
|
* lock */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* slow path with waiting on lock */
|
||||||
|
for (i = 0; i < freelist->count; i++) {
|
||||||
|
ctx = get_next_victim_freelist(freelist);
|
||||||
|
if (!ocf_freelist_get_cache_line_ctx(freelist, ctx, true,
|
||||||
|
cline)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ocf_freelist_get_cache_line_fast(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t *cline)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
uint32_t ctx = env_get_execution_context();
|
||||||
|
|
||||||
|
ret = !ocf_freelist_get_cache_line_ctx(freelist, ctx, false, cline);
|
||||||
|
|
||||||
|
env_put_execution_context(ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ocf_freelist_get_cache_line(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t *cline)
|
||||||
|
{
|
||||||
|
if (env_atomic64_read(&freelist->total_free) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ocf_freelist_get_cache_line_fast(freelist, cline))
|
||||||
|
return ocf_freelist_get_cache_line_slow(freelist, cline);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_freelist_put_cache_line(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
uint32_t ctx = env_get_execution_context();
|
||||||
|
|
||||||
|
ocf_freelist_lock(freelist, ctx);
|
||||||
|
ocf_freelist_add_cache_line(freelist, ctx, cline);
|
||||||
|
ocf_freelist_unlock(freelist, ctx);
|
||||||
|
env_put_execution_context(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_freelist_t ocf_freelist_init(struct ocf_cache *cache)
|
||||||
|
{
|
||||||
|
uint32_t num;
|
||||||
|
int i;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
ocf_cache_line_t line_entries = ocf_metadata_collision_table_entries(
|
||||||
|
cache);
|
||||||
|
|
||||||
|
freelist = env_vzalloc(sizeof(*freelist));
|
||||||
|
if (!freelist)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
num = env_get_execution_context_count();
|
||||||
|
|
||||||
|
freelist->cache = cache;
|
||||||
|
freelist->count = num;
|
||||||
|
env_atomic64_set(&freelist->total_free, 0);
|
||||||
|
freelist->lock = env_vzalloc(sizeof(freelist->lock[0]) * num);
|
||||||
|
freelist->part = env_vzalloc(sizeof(freelist->part[0]) * num);
|
||||||
|
|
||||||
|
if (!freelist->lock || !freelist->part) {
|
||||||
|
env_vfree(freelist->lock);
|
||||||
|
env_vfree(freelist->part);
|
||||||
|
env_vfree(freelist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
env_spinlock_init(&freelist->lock[i]);
|
||||||
|
freelist->part[i].head = line_entries;
|
||||||
|
freelist->part[i].tail = line_entries;
|
||||||
|
env_atomic64_set(&freelist->part[i].curr_size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return freelist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_freelist_deinit(ocf_freelist_t freelist)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < freelist->count; i++)
|
||||||
|
env_spinlock_destroy(&freelist->lock[i]);
|
||||||
|
env_vfree(freelist->lock);
|
||||||
|
env_vfree(freelist->part);
|
||||||
|
env_vfree(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cache_line_t ocf_freelist_num_free(ocf_freelist_t freelist)
|
||||||
|
{
|
||||||
|
return env_atomic64_read(&freelist->total_free);
|
||||||
|
}
|
||||||
|
|
34
src/ocf_freelist.h
Normal file
34
src/ocf_freelist.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright(c) 2019-2019 Intel Corporation
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __OCF_FREELIST_H__
|
||||||
|
#define __OCF_FREELIST_H__
|
||||||
|
|
||||||
|
#include "ocf_cache_priv.h"
|
||||||
|
|
||||||
|
struct ocf_freelist;
|
||||||
|
|
||||||
|
typedef struct ocf_freelist *ocf_freelist_t;
|
||||||
|
|
||||||
|
/* Init / deinit freelist runtime structures */
|
||||||
|
ocf_freelist_t ocf_freelist_init(struct ocf_cache *cache);
|
||||||
|
void ocf_freelist_deinit(ocf_freelist_t freelist);
|
||||||
|
|
||||||
|
/* Assign unused cachelines to freelist */
|
||||||
|
void ocf_freelist_populate(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t num_free_clines);
|
||||||
|
|
||||||
|
/* Get cacheline from freelist */
|
||||||
|
bool ocf_freelist_get_cache_line(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t *cline);
|
||||||
|
|
||||||
|
/* Put cacheline back to freelist */
|
||||||
|
void ocf_freelist_put_cache_line(ocf_freelist_t freelist,
|
||||||
|
ocf_cache_line_t cline);
|
||||||
|
|
||||||
|
/* Return total number of free cachelines */
|
||||||
|
ocf_cache_line_t ocf_freelist_num_free(ocf_freelist_t freelist);
|
||||||
|
|
||||||
|
#endif /* __OCF_FREELIST_H__ */
|
@ -44,18 +44,6 @@ static uint64_t _bytes4k(uint64_t bytes)
|
|||||||
return (bytes + 4095UL) >> 12;
|
return (bytes + 4095UL) >> 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t _get_cache_occupancy(ocf_cache_t cache)
|
|
||||||
{
|
|
||||||
uint64_t result = 0;
|
|
||||||
ocf_core_t core;
|
|
||||||
ocf_core_id_t core_id;
|
|
||||||
|
|
||||||
for_each_core(cache, core, core_id)
|
|
||||||
result += env_atomic_read(&core->runtime_meta->cached_clines);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _set(struct ocf_stat *stat, uint64_t value, uint64_t denominator)
|
static void _set(struct ocf_stat *stat, uint64_t value, uint64_t denominator)
|
||||||
{
|
{
|
||||||
stat->value = value;
|
stat->value = value;
|
||||||
@ -169,7 +157,7 @@ int ocf_stats_collect_core(ocf_core_t core,
|
|||||||
cache = ocf_core_get_cache(core);
|
cache = ocf_core_get_cache(core);
|
||||||
cache_line_size = ocf_cache_get_line_size(cache);
|
cache_line_size = ocf_cache_get_line_size(cache);
|
||||||
cache_size = cache->conf_meta->cachelines;
|
cache_size = cache->conf_meta->cachelines;
|
||||||
cache_occupancy = _get_cache_occupancy(cache);
|
cache_occupancy = ocf_get_cache_occupancy(cache);
|
||||||
|
|
||||||
_ocf_stats_zero(usage);
|
_ocf_stats_zero(usage);
|
||||||
_ocf_stats_zero(req);
|
_ocf_stats_zero(req);
|
||||||
|
@ -181,7 +181,7 @@ bool nhit_req_should_promote(ocf_promotion_policy_t policy,
|
|||||||
uint64_t core_line;
|
uint64_t core_line;
|
||||||
uint64_t occupied_cachelines =
|
uint64_t occupied_cachelines =
|
||||||
ocf_metadata_get_cachelines_count(policy->owner) -
|
ocf_metadata_get_cachelines_count(policy->owner) -
|
||||||
policy->owner->device->freelist_part->curr_size;
|
ocf_freelist_num_free(policy->owner->freelist);
|
||||||
|
|
||||||
if (occupied_cachelines > env_atomic64_read(&ctx->trigger_threshold))
|
if (occupied_cachelines > env_atomic64_read(&ctx->trigger_threshold))
|
||||||
return true;
|
return true;
|
||||||
|
@ -104,7 +104,7 @@ class TestGenerator(object):
|
|||||||
def get_empty_test_function(self):
|
def get_empty_test_function(self):
|
||||||
ret = "static void " + self.get_tested_function_name() + "_test01(void **state)\n"
|
ret = "static void " + self.get_tested_function_name() + "_test01(void **state)\n"
|
||||||
ret += "{\n"
|
ret += "{\n"
|
||||||
ret += "\tprint_test_description(\"Put test description here\");\n"
|
ret += "\tprint_test_description(\"Put test description here\\n\");\n"
|
||||||
ret += "\tassert_int_equal(1,1);\n"
|
ret += "\tassert_int_equal(1,1);\n"
|
||||||
ret += "}\n\n"
|
ret += "}\n\n"
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ class TestGenerator(object):
|
|||||||
ret += "\tconst struct CMUnitTest tests[] = {\n"
|
ret += "\tconst struct CMUnitTest tests[] = {\n"
|
||||||
ret += "\t\tcmocka_unit_test(" + self.get_tested_function_name() + "_test01)\n"
|
ret += "\t\tcmocka_unit_test(" + self.get_tested_function_name() + "_test01)\n"
|
||||||
ret += "\t};\n\n"
|
ret += "\t};\n\n"
|
||||||
ret += "\tprint_message(\"Unit test of " + self.get_tested_file_path() + "\");\n\n"
|
ret += "\tprint_message(\"Unit test for " + self.get_tested_function_name() + "\\n\");\n\n"
|
||||||
ret += "\treturn cmocka_run_group_tests(tests, NULL, NULL);\n"
|
ret += "\treturn cmocka_run_group_tests(tests, NULL, NULL);\n"
|
||||||
ret += "}"
|
ret += "}"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ MAIN_DIRECTORY_OF_UNIT_TESTS = "../tests/"
|
|||||||
# Paths to all directories, in which tests are stored. All paths should be relative to
|
# Paths to all directories, in which tests are stored. All paths should be relative to
|
||||||
# MAIN_DIRECTORY_OF_UNIT_TESTS
|
# MAIN_DIRECTORY_OF_UNIT_TESTS
|
||||||
DIRECTORIES_WITH_TESTS_LIST = ["cleaning/", "metadata/", "mngt/", "concurrency/", "engine/",
|
DIRECTORIES_WITH_TESTS_LIST = ["cleaning/", "metadata/", "mngt/", "concurrency/", "engine/",
|
||||||
"eviction/", "utils/", "promotion/"]
|
"eviction/", "utils/", "promotion/", "ocf_freelist.c/"]
|
||||||
|
|
||||||
# Paths to all directories containing files with sources. All paths should be relative to
|
# Paths to all directories containing files with sources. All paths should be relative to
|
||||||
# MAIN_DIRECTORY_OF_TESTED_PROJECT
|
# MAIN_DIRECTORY_OF_TESTED_PROJECT
|
||||||
|
@ -150,28 +150,25 @@ void env_completion_complete(env_completion *completion)
|
|||||||
|
|
||||||
int env_mutex_init(env_mutex *mutex)
|
int env_mutex_init(env_mutex *mutex)
|
||||||
{
|
{
|
||||||
function_called();
|
return 0;
|
||||||
check_expected_ptr(mutex);
|
}
|
||||||
return mock();
|
|
||||||
|
int env_mutex_destroy(env_mutex *mutex)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_mutex_lock(env_mutex *mutex)
|
void env_mutex_lock(env_mutex *mutex)
|
||||||
{
|
{
|
||||||
function_called();
|
|
||||||
check_expected_ptr(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int env_mutex_lock_interruptible(env_mutex *mutex)
|
int env_mutex_lock_interruptible(env_mutex *mutex)
|
||||||
{
|
{
|
||||||
function_called();
|
return 0;
|
||||||
check_expected_ptr(mutex);
|
|
||||||
return mock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_mutex_unlock(env_mutex *mutex)
|
void env_mutex_unlock(env_mutex *mutex)
|
||||||
{
|
{
|
||||||
function_called();
|
|
||||||
check_expected_ptr(mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int env_rmutex_init(env_rmutex *rmutex)
|
int env_rmutex_init(env_rmutex *rmutex)
|
||||||
@ -361,22 +358,27 @@ long env_atomic64_cmpxchg(env_atomic64 *a, long old, long new)
|
|||||||
return oldval;
|
return oldval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_spinlock_init(env_spinlock *l)
|
int env_spinlock_init(env_spinlock *l)
|
||||||
{
|
{
|
||||||
function_called();
|
return 0;
|
||||||
check_expected_ptr(l);
|
}
|
||||||
|
|
||||||
|
int env_spinlock_destroy(env_spinlock *l)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_spinlock_lock(env_spinlock *l)
|
void env_spinlock_lock(env_spinlock *l)
|
||||||
{
|
{
|
||||||
function_called();
|
}
|
||||||
check_expected_ptr(l);
|
|
||||||
|
int env_spinlock_trylock(env_spinlock *l)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_spinlock_unlock(env_spinlock *l)
|
void env_spinlock_unlock(env_spinlock *l)
|
||||||
{
|
{
|
||||||
function_called();
|
|
||||||
check_expected_ptr(l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void env_rwlock_init(env_rwlock *l)
|
void env_rwlock_init(env_rwlock *l)
|
||||||
@ -535,3 +537,7 @@ uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len)
|
|||||||
check_expected_ptr(data);
|
check_expected_ptr(data);
|
||||||
return mock();
|
return mock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void env_cond_resched(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -71,7 +71,13 @@ typedef uint64_t sector_t;
|
|||||||
abort(); \
|
abort(); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#define ENV_BUG_ON(cond) bug_on((int)cond);
|
#define ENV_BUG_ON(cond) ({ \
|
||||||
|
int eval = cond; \
|
||||||
|
if (eval) { \
|
||||||
|
print_message("%s:%u BUG: %s\n", __FILE__, __LINE__, #cond); \
|
||||||
|
bug_on(eval); \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
#define container_of(ptr, type, member) ({ \
|
||||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||||
@ -128,6 +134,8 @@ typedef struct {
|
|||||||
|
|
||||||
int env_mutex_init(env_mutex *mutex);
|
int env_mutex_init(env_mutex *mutex);
|
||||||
|
|
||||||
|
int env_mutex_destroy(env_mutex *mutex);
|
||||||
|
|
||||||
void env_mutex_lock(env_mutex *mutex);
|
void env_mutex_lock(env_mutex *mutex);
|
||||||
|
|
||||||
int env_mutex_lock_interruptible(env_mutex *mutex);
|
int env_mutex_lock_interruptible(env_mutex *mutex);
|
||||||
@ -231,10 +239,14 @@ void env_completion_complete(env_completion *completion);
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
} env_spinlock;
|
} env_spinlock;
|
||||||
|
|
||||||
void env_spinlock_init(env_spinlock *l);
|
int env_spinlock_init(env_spinlock *l);
|
||||||
|
|
||||||
|
int env_spinlock_destroy(env_spinlock *l);
|
||||||
|
|
||||||
void env_spinlock_lock(env_spinlock *l);
|
void env_spinlock_lock(env_spinlock *l);
|
||||||
|
|
||||||
|
int env_spinlock_trylock(env_spinlock *l);
|
||||||
|
|
||||||
void env_spinlock_unlock(env_spinlock *l);
|
void env_spinlock_unlock(env_spinlock *l);
|
||||||
|
|
||||||
#define env_spinlock_lock_irqsave(l, flags) \
|
#define env_spinlock_lock_irqsave(l, flags) \
|
||||||
@ -327,4 +339,6 @@ void env_msleep(uint64_t n);
|
|||||||
|
|
||||||
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len);
|
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t len);
|
||||||
|
|
||||||
|
void env_cond_resched(void);
|
||||||
|
|
||||||
#endif /* __OCF_ENV_H__ */
|
#endif /* __OCF_ENV_H__ */
|
||||||
|
382
tests/unit/tests/ocf_freelist.c/ocf_freelist_get_put.c
Normal file
382
tests/unit/tests/ocf_freelist.c/ocf_freelist_get_put.c
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/ocf_freelist.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_freelist_get_cache_line</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_freelist_init
|
||||||
|
* ocf_freelist_deinit
|
||||||
|
* ocf_freelist_populate
|
||||||
|
* next_phys_invalid
|
||||||
|
* ocf_freelist_lock
|
||||||
|
* ocf_freelist_trylock
|
||||||
|
* ocf_freelist_unlock
|
||||||
|
* _ocf_freelist_remove_cache_line
|
||||||
|
* ocf_freelist_get_cache_line_fast
|
||||||
|
* ocf_freelist_get_cache_line_slow
|
||||||
|
* ocf_freelist_add_cache_line
|
||||||
|
* ocf_freelist_get_cache_line_ctx
|
||||||
|
* get_next_victim_freelist
|
||||||
|
* ocf_freelist_put_cache_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 "metadata/metadata.h"
|
||||||
|
|
||||||
|
#include "ocf_freelist.c/ocf_freelist_get_put_generated_warps.c"
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_collision_table_entries(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __wrap_env_get_execution_context_count(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __wrap_env_get_execution_context(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_env_put_execution_context(unsigned ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simulate no striping */
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_map_phy2lg(ocf_cache_t cache, ocf_cache_line_t phy)
|
||||||
|
{
|
||||||
|
return phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __wrap_metadata_test_valid_any(ocf_cache_t cache, ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* metadata partition info interface mock: */
|
||||||
|
|
||||||
|
#define max_clines 100
|
||||||
|
|
||||||
|
struct {
|
||||||
|
ocf_cache_line_t prev;
|
||||||
|
ocf_cache_line_t next;
|
||||||
|
} partition_list[max_clines];
|
||||||
|
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_info(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_part_id_t part_id,
|
||||||
|
ocf_cache_line_t next_line, ocf_cache_line_t prev_line)
|
||||||
|
{
|
||||||
|
assert_int_equal(part_id, PARTITION_INVALID);
|
||||||
|
partition_list[line].prev = prev_line;
|
||||||
|
partition_list[line].next = next_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_get_partition_info(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_part_id_t *part_id,
|
||||||
|
ocf_cache_line_t *next_line, ocf_cache_line_t *prev_line)
|
||||||
|
{
|
||||||
|
if (part_id)
|
||||||
|
*part_id = PARTITION_INVALID;
|
||||||
|
if (prev_line)
|
||||||
|
*prev_line = partition_list[line].prev;
|
||||||
|
if (next_line)
|
||||||
|
*next_line = partition_list[line].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_prev(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_cache_line_t prev_line)
|
||||||
|
{
|
||||||
|
partition_list[line].prev = prev_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_next(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_cache_line_t next_line)
|
||||||
|
{
|
||||||
|
partition_list[line].next = next_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_get_cache_line_get_fast(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 8;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
ocf_cache_line_t line;
|
||||||
|
|
||||||
|
print_test_description("Verify get free cache line get fast path");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
will_return_maybe(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, num_cls);
|
||||||
|
|
||||||
|
/* now there are following cachelines on per-context lists:
|
||||||
|
* ctx 0: 0, 1, 2
|
||||||
|
* ctx 1: 3, 4, 5
|
||||||
|
* ctx 2: 6, 7
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* get cline from context 1 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 3);
|
||||||
|
|
||||||
|
/* ctx 0: 0, 1, 2
|
||||||
|
* ctx 1: _, 4, 5
|
||||||
|
* ctx 2: 6, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 2 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 2);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 6);
|
||||||
|
|
||||||
|
/* ctx 0: 0, 1, 2
|
||||||
|
* ctx 1: _, 4, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 1 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 4);
|
||||||
|
|
||||||
|
/* ctx 0: 0, 1, 2
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 0 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 0);
|
||||||
|
|
||||||
|
/* ctx 0: _, 1, 2
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 0 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 1);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, 2
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 0 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 2);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _,
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
/* get cline from context 2 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 2);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 7);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _,
|
||||||
|
* ctx 1: _, _, _5
|
||||||
|
* ctx 2: _, _ */
|
||||||
|
|
||||||
|
/* get cline from context 1 */
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 5);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _,
|
||||||
|
* ctx 1: _, _, _
|
||||||
|
* ctx 2: _, _ */
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_get_cache_line_get_slow(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 8;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
ocf_cache_line_t line;
|
||||||
|
|
||||||
|
print_test_description("Verify get free cache line get slow path");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
will_return_maybe(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
/* always return exec ctx 0 */
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context, 0);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, num_cls);
|
||||||
|
|
||||||
|
/* now there are following cachelines on per-context lists:
|
||||||
|
* ctx 0: 0, 1, 2
|
||||||
|
* ctx 1: 3, 4, 5
|
||||||
|
* ctx 2: 6, 7
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 0);
|
||||||
|
|
||||||
|
/* ctx 0: _, 1, 2
|
||||||
|
* ctx 1: 3, 4, 5
|
||||||
|
* ctx 2: 6, 7 */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 1);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, 2
|
||||||
|
* ctx 1: 3, 4, 5
|
||||||
|
* ctx 2: 6, 7 */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 2);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _
|
||||||
|
* ctx 1: 3, 4, 5
|
||||||
|
* ctx 2: 6, 7 */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 3);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _
|
||||||
|
* ctx 1: _, 4, 5
|
||||||
|
* ctx 2: 6, 7 */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 6);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _
|
||||||
|
* ctx 1: _, 4, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 4);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, 7 */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 7);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _
|
||||||
|
* ctx 1: _, _, 5
|
||||||
|
* ctx 2: _, _ */
|
||||||
|
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 5);
|
||||||
|
|
||||||
|
/* ctx 0: _, _, _,
|
||||||
|
* ctx 1: _, _, _
|
||||||
|
* ctx 2: _, _ */
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_get_cache_line_put(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 8;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
ocf_cache_line_t line;
|
||||||
|
|
||||||
|
print_test_description("Verify freelist cacheline put");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
will_return_maybe(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, num_cls);
|
||||||
|
|
||||||
|
/* get some clines from the freelists */
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
will_return(__wrap_env_get_execution_context, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
|
||||||
|
/* ctx 0:
|
||||||
|
* ctx 1: 4, 5
|
||||||
|
* ctx 2: 7 */
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
ocf_freelist_put_cache_line(freelist, 0);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
ocf_freelist_put_cache_line(freelist, 2);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 2);
|
||||||
|
ocf_freelist_put_cache_line(freelist, 3);
|
||||||
|
|
||||||
|
/* ctx 0:
|
||||||
|
* ctx 1: 4, 5, 0, 2
|
||||||
|
* ctx 2: 7, 3*/
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 4);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 5);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 0);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 1);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 2);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 2);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 7);
|
||||||
|
|
||||||
|
will_return(__wrap_env_get_execution_context, 2);
|
||||||
|
assert(ocf_freelist_get_cache_line(freelist, &line));
|
||||||
|
assert_int_equal(line, 3);
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_freelist_get_cache_line_get_fast),
|
||||||
|
cmocka_unit_test(ocf_freelist_get_cache_line_get_slow),
|
||||||
|
cmocka_unit_test(ocf_freelist_get_cache_line_put)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test for ocf_freelist_get_cache_line\n");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
68
tests/unit/tests/ocf_freelist.c/ocf_freelist_init.c
Normal file
68
tests/unit/tests/ocf_freelist.c/ocf_freelist_init.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/ocf_freelist.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_freelist_populate</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_freelist_init
|
||||||
|
* ocf_freelist_deinit
|
||||||
|
* </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 "metadata/metadata.h"
|
||||||
|
|
||||||
|
#include "ocf_freelist.c/ocf_freelist_init_generated_warps.c"
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_collision_table_entries(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_env_get_execution_context_count(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_init_test01(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 9;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
ocf_cache_t cache = 0x1234;
|
||||||
|
|
||||||
|
print_test_description("Freelist initialization test");
|
||||||
|
|
||||||
|
expect_function_call(__wrap_ocf_metadata_collision_table_entries);
|
||||||
|
will_return(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
|
||||||
|
expect_function_call(__wrap_env_get_execution_context_count);
|
||||||
|
will_return(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(cache);
|
||||||
|
assert(freelist != NULL);
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_freelist_init_test01)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of ocf_freelist_init\n");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
213
tests/unit/tests/ocf_freelist.c/ocf_freelist_locks.c
Normal file
213
tests/unit/tests/ocf_freelist.c/ocf_freelist_locks.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/ocf_freelist.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_freelist_get_cache_line</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_freelist_init
|
||||||
|
* ocf_freelist_deinit
|
||||||
|
* ocf_freelist_populate
|
||||||
|
* next_phys_invalid
|
||||||
|
* ocf_freelist_unlock
|
||||||
|
* _ocf_freelist_remove_cache_line
|
||||||
|
* ocf_freelist_get_cache_line_fast
|
||||||
|
* ocf_freelist_get_cache_line_slow
|
||||||
|
* ocf_freelist_add_cache_line
|
||||||
|
* ocf_freelist_get_cache_line_ctx
|
||||||
|
* get_next_victim_freelist
|
||||||
|
* ocf_freelist_put_cache_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 "metadata/metadata.h"
|
||||||
|
|
||||||
|
#include "ocf_freelist.c/ocf_freelist_get_put_generated_warps.c"
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_collision_table_entries(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __wrap_env_get_execution_context_count(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __wrap_env_get_execution_context(void)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_env_put_execution_context(unsigned ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simulate no striping */
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_map_phy2lg(ocf_cache_t cache, ocf_cache_line_t phy)
|
||||||
|
{
|
||||||
|
return phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __wrap_metadata_test_valid_any(ocf_cache_t cache, ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_freelist_lock(ocf_freelist_t freelist, uint32_t ctx)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
check_expected(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __wrap_ocf_freelist_trylock(ocf_freelist_t freelist, uint32_t ctx)
|
||||||
|
{
|
||||||
|
function_called();
|
||||||
|
check_expected(ctx);
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* metadata partition info interface mock: */
|
||||||
|
|
||||||
|
#define max_clines 100
|
||||||
|
|
||||||
|
struct {
|
||||||
|
ocf_cache_line_t prev;
|
||||||
|
ocf_cache_line_t next;
|
||||||
|
} partition_list[max_clines];
|
||||||
|
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_info(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_part_id_t part_id,
|
||||||
|
ocf_cache_line_t next_line, ocf_cache_line_t prev_line)
|
||||||
|
{
|
||||||
|
assert_int_equal(part_id, PARTITION_INVALID);
|
||||||
|
partition_list[line].prev = prev_line;
|
||||||
|
partition_list[line].next = next_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_get_partition_info(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_part_id_t *part_id,
|
||||||
|
ocf_cache_line_t *next_line, ocf_cache_line_t *prev_line)
|
||||||
|
{
|
||||||
|
if (part_id)
|
||||||
|
*part_id = PARTITION_INVALID;
|
||||||
|
if (prev_line)
|
||||||
|
*prev_line = partition_list[line].prev;
|
||||||
|
if (next_line)
|
||||||
|
*next_line = partition_list[line].next;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_prev(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_cache_line_t prev_line)
|
||||||
|
{
|
||||||
|
partition_list[line].prev = prev_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_next(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_cache_line_t next_line)
|
||||||
|
{
|
||||||
|
partition_list[line].next = next_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_get_put_locks(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 4;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
ocf_cache_line_t line;
|
||||||
|
|
||||||
|
print_test_description("Verify lock/trylock sequence in get free cacheline");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
will_return_maybe(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
/* simulate context 1 for the entire test duration */
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context, 1);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, num_cls);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* verify fast path locking - scucessfull trylock */
|
||||||
|
|
||||||
|
/* ctx 0: 0, 3
|
||||||
|
* ctx 1: 1
|
||||||
|
* ctx 2: 2
|
||||||
|
* slowpath next victim: 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
expect_value(__wrap_ocf_freelist_trylock, ctx, 1);
|
||||||
|
expect_function_call(__wrap_ocf_freelist_trylock);
|
||||||
|
will_return(__wrap_ocf_freelist_trylock, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* verify fast path locking - scucessfull trylock in slowpath */
|
||||||
|
|
||||||
|
/* ctx 0: 0, 3
|
||||||
|
* ctx 1:
|
||||||
|
* ctx 2: 2
|
||||||
|
* slowpath next victim: 0 */
|
||||||
|
|
||||||
|
/* we expect trylock for context 0, since context 1 has empty list */
|
||||||
|
expect_value(__wrap_ocf_freelist_trylock, ctx, 0);
|
||||||
|
expect_function_call(__wrap_ocf_freelist_trylock);
|
||||||
|
will_return(__wrap_ocf_freelist_trylock, 0);
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* verify fast path locking - trylock failure in slowpath */
|
||||||
|
|
||||||
|
/* ctx 0: 3
|
||||||
|
* ctx 1:
|
||||||
|
* ctx 2: 2
|
||||||
|
* slowpath next victim: 1 */
|
||||||
|
|
||||||
|
/* fastpath will fail immediately - context 1 list is empty */
|
||||||
|
/* next slowpath victim context (1) is empty - will move to ctx 2 */
|
||||||
|
/* so now we expect trylock for context no 2 - injecting error here*/
|
||||||
|
expect_value(__wrap_ocf_freelist_trylock, ctx, 2);
|
||||||
|
expect_function_call(__wrap_ocf_freelist_trylock);
|
||||||
|
will_return(__wrap_ocf_freelist_trylock, 1);
|
||||||
|
|
||||||
|
/* slowpath will attempt to trylock next non-empty context - 0
|
||||||
|
* - injecting error here as well */
|
||||||
|
expect_value(__wrap_ocf_freelist_trylock, ctx, 0);
|
||||||
|
expect_function_call(__wrap_ocf_freelist_trylock);
|
||||||
|
will_return(__wrap_ocf_freelist_trylock, 1);
|
||||||
|
|
||||||
|
/* slowpath trylock loop failed - expecting full lock */
|
||||||
|
expect_value(__wrap_ocf_freelist_lock, ctx, 2);
|
||||||
|
expect_function_call(__wrap_ocf_freelist_lock);
|
||||||
|
|
||||||
|
/* execute freelist_get_cache_line */
|
||||||
|
ocf_freelist_get_cache_line(freelist, &line);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_freelist_get_put_locks)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test for ocf_freelist_get_cache_line locking\n");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
138
tests/unit/tests/ocf_freelist.c/ocf_freelist_populate.c
Normal file
138
tests/unit/tests/ocf_freelist.c/ocf_freelist_populate.c
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* <tested_file_path>src/ocf_freelist.c</tested_file_path>
|
||||||
|
* <tested_function>ocf_freelist_populate</tested_function>
|
||||||
|
* <functions_to_leave>
|
||||||
|
* ocf_freelist_init
|
||||||
|
* ocf_freelist_deinit
|
||||||
|
* ocf_freelist_populate
|
||||||
|
* next_phys_invalid
|
||||||
|
* </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 "metadata/metadata.h"
|
||||||
|
|
||||||
|
#include "ocf_freelist.c/ocf_freelist_populate_generated_warps.c"
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_collision_table_entries(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_cache_line_t __wrap_env_get_execution_context_count(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* simulate no striping */
|
||||||
|
ocf_cache_line_t __wrap_ocf_metadata_map_phy2lg(ocf_cache_t cache, ocf_cache_line_t phy)
|
||||||
|
{
|
||||||
|
return phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __wrap_metadata_test_valid_any(ocf_cache_t cache, ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
return mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __wrap_ocf_metadata_set_partition_info(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t line, ocf_part_id_t part_id,
|
||||||
|
ocf_cache_line_t next_line, ocf_cache_line_t prev_line)
|
||||||
|
{
|
||||||
|
print_message("%s %u %u %u\n", __func__, prev_line, line, next_line);
|
||||||
|
check_expected(line);
|
||||||
|
check_expected(part_id);
|
||||||
|
check_expected(next_line);
|
||||||
|
check_expected(prev_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define expect_set_info(curr, part, next, prev) \
|
||||||
|
expect_value(__wrap_ocf_metadata_set_partition_info, line, curr); \
|
||||||
|
expect_value(__wrap_ocf_metadata_set_partition_info, part_id, part); \
|
||||||
|
expect_value(__wrap_ocf_metadata_set_partition_info, next_line, next); \
|
||||||
|
expect_value(__wrap_ocf_metadata_set_partition_info, prev_line, prev);
|
||||||
|
|
||||||
|
static void ocf_freelist_populate_test01(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 8;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
|
||||||
|
print_test_description("Verify proper set_partition_info order and arguments - empty cache");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
will_return_maybe(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
expect_set_info(0, PARTITION_INVALID, 1 , num_cls);
|
||||||
|
expect_set_info(1, PARTITION_INVALID, 2 , 0);
|
||||||
|
expect_set_info(2, PARTITION_INVALID, num_cls, 1);
|
||||||
|
expect_set_info(3, PARTITION_INVALID, 4 , num_cls);
|
||||||
|
expect_set_info(4, PARTITION_INVALID, 5 , 3);
|
||||||
|
expect_set_info(5, PARTITION_INVALID, num_cls, 4);
|
||||||
|
expect_set_info(6, PARTITION_INVALID, 7 , num_cls);
|
||||||
|
expect_set_info(7, PARTITION_INVALID, num_cls, 6);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, num_cls);
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_freelist_populate_test02(void **state)
|
||||||
|
{
|
||||||
|
unsigned num_cls = 8;
|
||||||
|
unsigned num_ctxts = 3;
|
||||||
|
ocf_freelist_t freelist;
|
||||||
|
unsigned ctx_iter, cl_iter;
|
||||||
|
|
||||||
|
print_test_description("Verify proper set_partition_info order and arguments - some valid clines");
|
||||||
|
|
||||||
|
will_return_maybe(__wrap_ocf_metadata_collision_table_entries, num_cls);
|
||||||
|
will_return_maybe(__wrap_env_get_execution_context_count, num_ctxts);
|
||||||
|
|
||||||
|
freelist = ocf_freelist_init(NULL);
|
||||||
|
|
||||||
|
/* simulate only cachelines 2, 3, 4, 7 invalid */
|
||||||
|
will_return(__wrap_metadata_test_valid_any, true);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, true);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, false);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, false);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, false);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, true);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, true);
|
||||||
|
will_return(__wrap_metadata_test_valid_any, false);
|
||||||
|
|
||||||
|
expect_set_info(2, PARTITION_INVALID, 3 , num_cls);
|
||||||
|
expect_set_info(3, PARTITION_INVALID, num_cls, 2);
|
||||||
|
expect_set_info(4, PARTITION_INVALID, num_cls, num_cls);
|
||||||
|
expect_set_info(7, PARTITION_INVALID, num_cls, num_cls);
|
||||||
|
|
||||||
|
ocf_freelist_populate(freelist, 4);
|
||||||
|
|
||||||
|
ocf_freelist_deinit(freelist);
|
||||||
|
}
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(ocf_freelist_populate_test01),
|
||||||
|
cmocka_unit_test(ocf_freelist_populate_test02)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_message("Unit test of src/ocf_freelist.c\n");
|
||||||
|
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user