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 *** */
|
||||
|
||||
uint32_t env_crc32(uint32_t crc, uint8_t const *data, size_t 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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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"
|
||||
|
||||
unsigned env_get_execution_context(void);
|
||||
void env_put_execution_context(unsigned ctx);
|
||||
unsigned env_get_execution_context_count(void);
|
||||
|
||||
#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))
|
||||
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,
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "../ocf_priv.h"
|
||||
#include "../ocf_cache_priv.h"
|
||||
#include "../ocf_queue_priv.h"
|
||||
#include "../ocf_freelist.h"
|
||||
#include "engine_common.h"
|
||||
#define OCF_ENGINE_DEBUG_IO_NAME "common"
|
||||
#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_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;
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
|
||||
evict_cline_no -= cache->device->freelist_part->curr_size;
|
||||
evict_cline_no -= free;
|
||||
evicted = ocf_evict_do(cache, req->io_queue, evict_cline_no,
|
||||
req->part_id);
|
||||
|
||||
|
@ -32,8 +32,7 @@ union eviction_policy_meta {
|
||||
* set core_id to -2 to purge the whole cache partition
|
||||
*/
|
||||
struct eviction_policy_ops {
|
||||
void (*init_cline)(ocf_cache_t cache,
|
||||
ocf_cache_line_t cline);
|
||||
void (*init_cline)(ocf_cache_t cache, ocf_cache_line_t cline);
|
||||
void (*rm_cline)(ocf_cache_t cache,
|
||||
ocf_cache_line_t cline);
|
||||
bool (*can_evict)(ocf_cache_t cache);
|
||||
|
@ -8,8 +8,7 @@
|
||||
#include "eviction.h"
|
||||
#include "lru_structs.h"
|
||||
|
||||
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);
|
||||
bool evp_lru_can_evict(struct ocf_cache *cache);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
OCF_DEBUG_TRACE(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)
|
||||
{
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Initialize collision table
|
||||
*
|
||||
* @param cache - Cache instance
|
||||
*/
|
||||
void ocf_metadata_init_collision(struct ocf_cache *cache);
|
||||
|
||||
/**
|
||||
* @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,
|
||||
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_ */
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../utils/utils_pipeline.h"
|
||||
#include "../ocf_def_priv.h"
|
||||
#include "../ocf_priv.h"
|
||||
#include "../ocf_freelist.h"
|
||||
|
||||
#define OCF_METADATA_HASH_DEBUG 0
|
||||
|
||||
@ -1025,14 +1026,10 @@ finalize:
|
||||
}
|
||||
|
||||
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 prev)
|
||||
ocf_cache_line_t idx)
|
||||
{
|
||||
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_core_info(cache, idx,
|
||||
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;
|
||||
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;
|
||||
idx = 0;
|
||||
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);
|
||||
for (i = 0; i < cache->device->collision_table_entries; i++) {
|
||||
_ocf_init_collision_entry(cache, i);
|
||||
}
|
||||
_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
|
||||
*/
|
||||
@ -1850,8 +1828,6 @@ static void _recovery_rebuild_cline_metadata(ocf_cache_t cache,
|
||||
|
||||
part_id = PARTITION_DEFAULT;
|
||||
|
||||
ocf_metadata_remove_from_free_list(cache, cache_line);
|
||||
|
||||
ocf_metadata_add_to_partition(cache, part_id, cache_line);
|
||||
|
||||
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;
|
||||
uint64_t core_line;
|
||||
unsigned char step = 0;
|
||||
const uint64_t collision_table_entries =
|
||||
ocf_metadata_collision_table_entries(cache);
|
||||
|
||||
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);
|
||||
if (core_id != OCF_CORE_MAX &&
|
||||
(!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,
|
||||
.deinit_variable_size = ocf_metadata_hash_deinit_variable_size,
|
||||
.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,
|
||||
.pages = ocf_metadata_hash_pages,
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
#include "metadata.h"
|
||||
#include "../ocf_freelist.h"
|
||||
#include "../utils/utils_cache_line.h"
|
||||
|
||||
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_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,
|
||||
|
@ -16,99 +16,6 @@ static void update_partition_head(struct ocf_cache *cache,
|
||||
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 */
|
||||
void ocf_metadata_add_to_partition(struct ocf_cache *cache,
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
ocf_part_id_t part_id, ocf_cache_line_t line);
|
||||
|
||||
|
@ -10,12 +10,6 @@
|
||||
#include "../cleaning/cleaning.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 {
|
||||
char name[OCF_IO_CLASS_NAME_MAX];
|
||||
uint32_t min_size;
|
||||
|
@ -124,13 +124,6 @@ struct ocf_metadata_iface {
|
||||
struct ocf_volume_uuid *uuid, uint32_t count,
|
||||
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
|
||||
@ -144,6 +137,13 @@ struct ocf_metadata_iface {
|
||||
*/
|
||||
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
|
||||
*
|
||||
|
@ -59,8 +59,6 @@ struct ocf_superblock_config {
|
||||
* @brief OCF cache metadata runtime superblock
|
||||
*/
|
||||
struct ocf_superblock_runtime {
|
||||
struct ocf_part freelist_part;
|
||||
|
||||
uint32_t cleaning_thread_access;
|
||||
};
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../concurrency/ocf_concurrency.h"
|
||||
#include "../eviction/ops.h"
|
||||
#include "../ocf_ctx_priv.h"
|
||||
#include "../ocf_freelist.h"
|
||||
#include "../cleaning/cleaning.h"
|
||||
|
||||
#define OCF_ASSERT_PLUGGED(cache) ENV_BUG_ON(!(cache)->device)
|
||||
@ -117,6 +118,8 @@ struct ocf_cache_attach_context {
|
||||
* load or recovery
|
||||
*/
|
||||
|
||||
bool freelist_inited : 1;
|
||||
|
||||
bool concurrency_inited : 1;
|
||||
} flags;
|
||||
|
||||
@ -156,18 +159,6 @@ struct ocf_cache_attach_context {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
OCF_METADATA_LOCK_WR();
|
||||
|
||||
__init_hash_table(cache);
|
||||
__init_freelist(cache);
|
||||
ocf_metadata_init_hash_table(cache);
|
||||
ocf_metadata_init_collision(cache);
|
||||
__init_partitions_attached(cache);
|
||||
__init_freelist(cache);
|
||||
|
||||
result = __init_cleaning_policy(cache);
|
||||
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)
|
||||
{
|
||||
OCF_METADATA_LOCK_WR();
|
||||
__init_hash_table(cache);
|
||||
__init_freelist(cache);
|
||||
ocf_metadata_init_hash_table(cache);
|
||||
ocf_metadata_init_collision(cache);
|
||||
__init_partitions_attached(cache);
|
||||
__reset_stats(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);
|
||||
}
|
||||
|
||||
__init_freelist(cache);
|
||||
|
||||
result = __init_promotion_policy(cache);
|
||||
if (result) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
cache->device->freelist_part = &cache->device->runtime_meta->freelist_part;
|
||||
cache->freelist = ocf_freelist_init(cache);
|
||||
if (!cache->freelist)
|
||||
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||
context->flags.freelist_inited = true;
|
||||
|
||||
ret = ocf_concurrency_init(cache);
|
||||
if (ret)
|
||||
@ -1143,6 +1147,9 @@ static void _ocf_mngt_attach_handle_error(
|
||||
if (context->flags.concurrency_inited)
|
||||
ocf_concurrency_deinit(cache);
|
||||
|
||||
if (context->flags.freelist_inited)
|
||||
ocf_freelist_deinit(cache->freelist);
|
||||
|
||||
if (context->flags.volume_inited)
|
||||
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_concurrency_deinit(cache);
|
||||
ocf_freelist_deinit(cache->freelist);
|
||||
|
||||
ocf_volume_deinit(&cache->device->volume);
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ocf_logger_priv.h"
|
||||
#include "ocf/ocf_trace.h"
|
||||
#include "promotion/promotion.h"
|
||||
#include "ocf_freelist.h"
|
||||
|
||||
#define DIRTY_FLUSHED 1
|
||||
#define DIRTY_NOT_FLUSHED 0
|
||||
@ -82,8 +83,6 @@ struct ocf_cache_device {
|
||||
|
||||
uint64_t metadata_offset;
|
||||
|
||||
struct ocf_part *freelist_part;
|
||||
|
||||
struct {
|
||||
struct ocf_cache_line_concurrency *cache_line;
|
||||
} concurrency;
|
||||
@ -110,6 +109,8 @@ struct ocf_cache {
|
||||
|
||||
struct ocf_metadata metadata;
|
||||
|
||||
ocf_freelist_t freelist;
|
||||
|
||||
ocf_eviction_t eviction_policy_init;
|
||||
|
||||
struct {
|
||||
@ -199,4 +200,16 @@ static inline ocf_core_t ocf_cache_get_core(ocf_cache_t cache,
|
||||
#define ocf_cache_log_rl(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__ */
|
||||
|
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
stat->value = value;
|
||||
@ -169,7 +157,7 @@ int ocf_stats_collect_core(ocf_core_t core,
|
||||
cache = ocf_core_get_cache(core);
|
||||
cache_line_size = ocf_cache_get_line_size(cache);
|
||||
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(req);
|
||||
|
@ -181,7 +181,7 @@ bool nhit_req_should_promote(ocf_promotion_policy_t policy,
|
||||
uint64_t core_line;
|
||||
uint64_t occupied_cachelines =
|
||||
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))
|
||||
return true;
|
||||
|
@ -104,7 +104,7 @@ class TestGenerator(object):
|
||||
def get_empty_test_function(self):
|
||||
ret = "static void " + self.get_tested_function_name() + "_test01(void **state)\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 += "}\n\n"
|
||||
|
||||
@ -116,7 +116,7 @@ class TestGenerator(object):
|
||||
ret += "\tconst struct CMUnitTest tests[] = {\n"
|
||||
ret += "\t\tcmocka_unit_test(" + self.get_tested_function_name() + "_test01)\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 += "}"
|
||||
|
||||
|
@ -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
|
||||
# MAIN_DIRECTORY_OF_UNIT_TESTS
|
||||
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
|
||||
# MAIN_DIRECTORY_OF_TESTED_PROJECT
|
||||
|
@ -150,28 +150,25 @@ void env_completion_complete(env_completion *completion)
|
||||
|
||||
int env_mutex_init(env_mutex *mutex)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(mutex);
|
||||
return mock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int env_mutex_destroy(env_mutex *mutex)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void env_mutex_lock(env_mutex *mutex)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(mutex);
|
||||
}
|
||||
|
||||
int env_mutex_lock_interruptible(env_mutex *mutex)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(mutex);
|
||||
return mock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void env_mutex_unlock(env_mutex *mutex)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(mutex);
|
||||
}
|
||||
|
||||
int env_rmutex_init(env_rmutex *rmutex)
|
||||
@ -361,22 +358,27 @@ long env_atomic64_cmpxchg(env_atomic64 *a, long old, long new)
|
||||
return oldval;
|
||||
}
|
||||
|
||||
void env_spinlock_init(env_spinlock *l)
|
||||
int env_spinlock_init(env_spinlock *l)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(l);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int env_spinlock_destroy(env_spinlock *l)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
function_called();
|
||||
check_expected_ptr(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);
|
||||
return mock();
|
||||
}
|
||||
|
||||
void env_cond_resched(void)
|
||||
{
|
||||
}
|
||||
|
@ -71,7 +71,13 @@ typedef uint64_t sector_t;
|
||||
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) ({ \
|
||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
@ -128,6 +134,8 @@ typedef struct {
|
||||
|
||||
int env_mutex_init(env_mutex *mutex);
|
||||
|
||||
int env_mutex_destroy(env_mutex *mutex);
|
||||
|
||||
void env_mutex_lock(env_mutex *mutex);
|
||||
|
||||
int env_mutex_lock_interruptible(env_mutex *mutex);
|
||||
@ -231,10 +239,14 @@ void env_completion_complete(env_completion *completion);
|
||||
typedef struct {
|
||||
} 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);
|
||||
|
||||
int env_spinlock_trylock(env_spinlock *l);
|
||||
|
||||
void env_spinlock_unlock(env_spinlock *l);
|
||||
|
||||
#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);
|
||||
|
||||
void env_cond_resched(void);
|
||||
|
||||
#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