Merge pull request #448 from robertbaldyga/perqueue-seq-cutoff

Per-queue multi-stream sequential cutoff
This commit is contained in:
Michał Mielewczyk 2021-03-05 14:38:21 +01:00 committed by GitHub
commit d2b5de7970
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 360 additions and 62 deletions

View File

@ -112,6 +112,15 @@ uint32_t ocf_core_get_seq_cutoff_threshold(ocf_core_t core);
*/ */
ocf_seq_cutoff_policy ocf_core_get_seq_cutoff_policy(ocf_core_t core); ocf_seq_cutoff_policy ocf_core_get_seq_cutoff_policy(ocf_core_t core);
/**
* @brief Get sequential cutoff stream promotion req count of given core object
*
* @param[in] core Core object
*
* @retval Sequential cutoff stream promotion request count
*/
uint32_t ocf_core_get_seq_cutoff_promotion_count(ocf_core_t core);
/** /**
* @brief Get name of given core object * @brief Get name of given core object
* *

View File

@ -12,7 +12,7 @@ struct ocf_dbg_seq_cutoff_status {
uint64_t bytes; uint64_t bytes;
uint32_t rw : 1; uint32_t rw : 1;
uint32_t active : 1; uint32_t active : 1;
} streams[OCF_SEQ_CUTOFF_MAX_STREAMS]; } streams[OCF_SEQ_CUTOFF_PERCORE_STREAMS];
}; };
void ocf_dbg_get_seq_cutoff_status(ocf_core_t core, void ocf_dbg_get_seq_cutoff_status(ocf_core_t core,

View File

@ -175,9 +175,12 @@ typedef enum {
/*!< Current cache mode of given cache instance */ /*!< Current cache mode of given cache instance */
} ocf_cache_mode_t; } ocf_cache_mode_t;
#define OCF_SEQ_CUTOFF_MAX_STREAMS 256 #define OCF_SEQ_CUTOFF_PERCORE_STREAMS 128
#define OCF_SEQ_CUTOFF_PERQUEUE_STREAMS 64
#define OCF_SEQ_CUTOFF_MIN_THRESHOLD 1 #define OCF_SEQ_CUTOFF_MIN_THRESHOLD 1
#define OCF_SEQ_CUTOFF_MAX_THRESHOLD 4194181 #define OCF_SEQ_CUTOFF_MAX_THRESHOLD 4194181
#define OCF_SEQ_CUTOFF_MIN_PROMOTION_COUNT 1
#define OCF_SEQ_CUTOFF_MAX_PROMOTION_COUNT 65535
typedef enum { typedef enum {
ocf_seq_cutoff_policy_always = 0, ocf_seq_cutoff_policy_always = 0,

View File

@ -42,6 +42,9 @@ struct ocf_mngt_core_config {
uint32_t seq_cutoff_threshold; uint32_t seq_cutoff_threshold;
/*!< Sequential cutoff threshold (in bytes) */ /*!< Sequential cutoff threshold (in bytes) */
uint32_t seq_cutoff_promotion_count;
/*!< Sequential cutoff promotion request count */
struct { struct {
void *data; void *data;
size_t size; size_t size;
@ -61,6 +64,7 @@ static inline void ocf_mngt_core_config_set_default(
{ {
cfg->try_add = false; cfg->try_add = false;
cfg->seq_cutoff_threshold = 1024; cfg->seq_cutoff_threshold = 1024;
cfg->seq_cutoff_promotion_count = 8;
cfg->user_metadata.data = NULL; cfg->user_metadata.data = NULL;
cfg->user_metadata.size = 0; cfg->user_metadata.size = 0;
} }
@ -1010,6 +1014,47 @@ int ocf_mngt_core_set_seq_cutoff_policy_all(ocf_cache_t cache,
int ocf_mngt_core_get_seq_cutoff_policy(ocf_core_t core, int ocf_mngt_core_get_seq_cutoff_policy(ocf_core_t core,
ocf_seq_cutoff_policy *policy); ocf_seq_cutoff_policy *policy);
/**
* @brief Set core sequential cutoff promotion request count
*
* @attention This changes only runtime state. To make changes persistent
* use function ocf_mngt_cache_save().
*
* @param[in] core Core handle
* @param[in] count promotion request count
*
* @retval 0 Sequential cutoff promotion requets count has been set successfully
* @retval Non-zero Error occured and request count hasn't been updated
*/
int ocf_mngt_core_set_seq_cutoff_promotion_count(ocf_core_t core,
uint32_t count);
/**
* @brief Set sequential cutoff promotion request count for all cores in cache
*
* @attention This changes only runtime state. To make changes persistent
* use function ocf_mngt_cache_save().
*
* @param[in] cache Cache handle
* @param[in] count promotion request count
*
* @retval 0 Sequential cutoff promotion request count has been set successfully
* @retval Non-zero Error occured and request count hasn't been updated
*/
int ocf_mngt_core_set_seq_cutoff_promotion_count_all(ocf_cache_t cache,
uint32_t count);
/**
* @brief Get core sequential cutoff promotion threshold
*
* @param[in] core Core handle
* @param[out] count promotion request count
*
* @retval 0 Sequential cutoff promotion request count has been get successfully
* @retval Non-zero Error occured
*/
int ocf_mngt_core_get_seq_cutoff_promotion_count(ocf_core_t core,
uint32_t *count);
/** /**
* @brief Set cache fallback Pass Through error threshold * @brief Set cache fallback Pass Through error threshold
* *

View File

@ -451,6 +451,8 @@ static void ocf_mngt_cache_add_core_insert(ocf_pipeline_t pipeline,
ocf_seq_cutoff_policy_default); ocf_seq_cutoff_policy_default);
env_atomic_set(&core->conf_meta->seq_cutoff_threshold, env_atomic_set(&core->conf_meta->seq_cutoff_threshold,
cfg->seq_cutoff_threshold); cfg->seq_cutoff_threshold);
env_atomic_set(&core->conf_meta->seq_cutoff_promo_count,
cfg->seq_cutoff_promotion_count);
/* Add core sequence number for atomic metadata matching */ /* Add core sequence number for atomic metadata matching */
core_sequence_no = _ocf_mngt_get_core_seq_no(cache); core_sequence_no = _ocf_mngt_get_core_seq_no(cache);
@ -1016,3 +1018,62 @@ int ocf_mngt_core_get_seq_cutoff_policy(ocf_core_t core,
return 0; return 0;
} }
static int _cache_mngt_set_core_seq_cutoff_promo_count(ocf_core_t core,
void *cntx)
{
uint32_t count = *(uint32_t*) cntx;
uint32_t count_old = ocf_core_get_seq_cutoff_promotion_count(core);
if (count < OCF_SEQ_CUTOFF_MIN_PROMOTION_COUNT ||
count > OCF_SEQ_CUTOFF_MAX_PROMOTION_COUNT) {
ocf_core_log(core, log_info,
"Invalid sequential cutoff promotion count!\n");
return -OCF_ERR_INVAL;
}
if (count_old == count) {
ocf_core_log(core, log_info,
"Sequential cutoff promotion count %u "
"bytes is already set\n", count);
return 0;
}
env_atomic_set(&core->conf_meta->seq_cutoff_promo_count, count);
ocf_core_log(core, log_info, "Changing sequential cutoff promotion"
"count from %u to %u bytes successful\n",
count_old, count);
return 0;
}
int ocf_mngt_core_set_seq_cutoff_promotion_count(ocf_core_t core,
uint32_t count)
{
OCF_CHECK_NULL(core);
return _cache_mngt_set_core_seq_cutoff_promo_count(core, &count);
}
int ocf_mngt_core_set_seq_cutoff_promotion_count_all(ocf_cache_t cache,
uint32_t count)
{
OCF_CHECK_NULL(cache);
return ocf_core_visit(cache,
_cache_mngt_set_core_seq_cutoff_promo_count,
&count, true);
}
int ocf_mngt_core_get_seq_cutoff_promotion_count(ocf_core_t core,
uint32_t *count)
{
OCF_CHECK_NULL(core);
OCF_CHECK_NULL(count);
*count = ocf_core_get_seq_cutoff_promotion_count(core);
return 0;
}

View File

@ -11,6 +11,7 @@
#include "utils/utils_part.h" #include "utils/utils_part.h"
#include "ocf_priv.h" #include "ocf_priv.h"
#include "ocf_cache_priv.h" #include "ocf_cache_priv.h"
#include "ocf_queue_priv.h"
#include "utils/utils_stats.h" #include "utils/utils_stats.h"
ocf_volume_t ocf_cache_get_volume(ocf_cache_t cache) ocf_volume_t ocf_cache_get_volume(ocf_cache_t cache)

View File

@ -114,6 +114,11 @@ ocf_seq_cutoff_policy ocf_core_get_seq_cutoff_policy(ocf_core_t core)
return env_atomic_read(&core->conf_meta->seq_cutoff_policy); return env_atomic_read(&core->conf_meta->seq_cutoff_policy);
} }
uint32_t ocf_core_get_seq_cutoff_promotion_count(ocf_core_t core)
{
return env_atomic_read(&core->conf_meta->seq_cutoff_promo_count);
}
int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx, int ocf_core_visit(ocf_cache_t cache, ocf_core_visitor_t visitor, void *cntx,
bool only_opened) bool only_opened)
{ {

View File

@ -44,6 +44,9 @@ struct ocf_core_meta_config {
/* Sequential cutoff policy */ /* Sequential cutoff policy */
env_atomic seq_cutoff_policy; env_atomic seq_cutoff_policy;
/* Sequential cutoff stream promotion request count */
env_atomic seq_cutoff_promo_count;
/* core object size in bytes */ /* core object size in bytes */
uint64_t length; uint64_t length;

View File

@ -44,6 +44,13 @@ int ocf_queue_create(ocf_cache_t cache, ocf_queue_t *queue,
tmp_queue->cache = cache; tmp_queue->cache = cache;
tmp_queue->ops = ops; tmp_queue->ops = ops;
result = ocf_queue_seq_cutoff_init(tmp_queue);
if (result) {
ocf_mngt_cache_put(cache);
env_free(tmp_queue);
return result;
}
list_add(&tmp_queue->list, &cache->io_queues); list_add(&tmp_queue->list, &cache->io_queues);
*queue = tmp_queue; *queue = tmp_queue;
@ -65,6 +72,7 @@ void ocf_queue_put(ocf_queue_t queue)
if (env_atomic_dec_return(&queue->ref_count) == 0) { if (env_atomic_dec_return(&queue->ref_count) == 0) {
list_del(&queue->list); list_del(&queue->list);
queue->ops->stop(queue); queue->ops->stop(queue);
ocf_queue_seq_cutoff_deinit(queue);
ocf_mngt_cache_put(queue->cache); ocf_mngt_cache_put(queue->cache);
env_spinlock_destroy(&queue->io_list_lock); env_spinlock_destroy(&queue->io_list_lock);
env_free(queue); env_free(queue);

View File

@ -34,6 +34,8 @@ struct ocf_queue {
const struct ocf_queue_ops *ops; const struct ocf_queue_ops *ops;
struct ocf_seq_cutoff *seq_cutoff;
void *priv; void *priv;
}; };

View File

@ -187,6 +187,9 @@ struct ocf_request {
uint8_t master_io_req_type : 2; uint8_t master_io_req_type : 2;
/*!< Core device request context type */ /*!< Core device request context type */
uint8_t seq_cutoff_core : 1;
/*!< Sequential cut off stream promoted to core level */
uint8_t seq_cutoff : 1; uint8_t seq_cutoff : 1;
/*!< Sequential cut off set for this request */ /*!< Sequential cut off set for this request */

View File

@ -5,6 +5,8 @@
#include "ocf_seq_cutoff.h" #include "ocf_seq_cutoff.h"
#include "ocf_cache_priv.h" #include "ocf_cache_priv.h"
#include "ocf_core_priv.h"
#include "ocf_queue_priv.h"
#include "ocf_priv.h" #include "ocf_priv.h"
#include "ocf/ocf_debug.h" #include "ocf/ocf_debug.h"
#include "utils/utils_cache_line.h" #include "utils/utils_cache_line.h"
@ -51,50 +53,86 @@ static struct ocf_rb_node *ocf_seq_cutoff_stream_list_find(
struct ocf_rb_node *node; struct ocf_rb_node *node;
node = list_entry(node_list, struct ocf_rb_node, list); node = list_entry(node_list, struct ocf_rb_node, list);
max_stream = container_of(node, struct ocf_seq_cutoff_stream, node); stream = container_of(node, struct ocf_seq_cutoff_stream, node);
if (stream->valid)
max_stream = stream;
list_for_each_entry(node, node_list, list) { list_for_each_entry(node, node_list, list) {
stream = container_of(node, struct ocf_seq_cutoff_stream, node); stream = container_of(node, struct ocf_seq_cutoff_stream, node);
if (!stream->valid)
continue;
if (!max_stream)
max_stream = stream;
if (stream->bytes > max_stream->bytes) if (stream->bytes > max_stream->bytes)
max_stream = stream; max_stream = stream;
} }
return &max_stream->node; return max_stream ? &max_stream->node : NULL;
} }
int ocf_core_seq_cutoff_init(ocf_core_t core) static void ocf_seq_cutoff_base_init(struct ocf_seq_cutoff *base, int nstreams)
{ {
struct ocf_seq_cutoff_stream *stream; struct ocf_seq_cutoff_stream *stream;
int i; int i;
ocf_core_log(core, log_info, "Seqential cutoff init\n"); env_rwlock_init(&base->lock);
ocf_rb_tree_init(&base->tree, ocf_seq_cutoff_stream_cmp,
core->seq_cutoff = env_vmalloc(sizeof(*core->seq_cutoff));
if (!core->seq_cutoff)
return -OCF_ERR_NO_MEM;
env_rwlock_init(&core->seq_cutoff->lock);
ocf_rb_tree_init(&core->seq_cutoff->tree, ocf_seq_cutoff_stream_cmp,
ocf_seq_cutoff_stream_list_find); ocf_seq_cutoff_stream_list_find);
INIT_LIST_HEAD(&core->seq_cutoff->lru); INIT_LIST_HEAD(&base->lru);
for (i = 0; i < OCF_SEQ_CUTOFF_MAX_STREAMS; i++) { for (i = 0; i < nstreams; i++) {
stream = &core->seq_cutoff->streams[i]; stream = &base->streams[i];
stream->last = 4096 * i; stream->last = 4096 * i;
stream->bytes = 0; stream->bytes = 0;
stream->rw = 0; stream->rw = 0;
ocf_rb_tree_insert(&core->seq_cutoff->tree, &stream->node); stream->valid = false;
list_add_tail(&stream->list, &core->seq_cutoff->lru); ocf_rb_tree_insert(&base->tree, &stream->node);
list_add_tail(&stream->list, &base->lru);
} }
}
void ocf_seq_cutoff_base_deinit(struct ocf_seq_cutoff *base)
{
env_rwlock_destroy(&base->lock);
}
int ocf_core_seq_cutoff_init(ocf_core_t core)
{
ocf_core_log(core, log_info, "Seqential cutoff init\n");
core->seq_cutoff = env_vmalloc(sizeof(struct ocf_seq_cutoff_percore));
if (!core->seq_cutoff)
return -OCF_ERR_NO_MEM;
ocf_seq_cutoff_base_init(core->seq_cutoff,
OCF_SEQ_CUTOFF_PERCORE_STREAMS);
return 0; return 0;
} }
void ocf_core_seq_cutoff_deinit(ocf_core_t core) void ocf_core_seq_cutoff_deinit(ocf_core_t core)
{ {
env_rwlock_destroy(&core->seq_cutoff->lock); ocf_seq_cutoff_base_deinit(core->seq_cutoff);
env_vfree(core->seq_cutoff); env_vfree(core->seq_cutoff);
} }
int ocf_queue_seq_cutoff_init(ocf_queue_t queue)
{
queue->seq_cutoff = env_vmalloc(sizeof(struct ocf_seq_cutoff_perqueue));
if (!queue->seq_cutoff)
return -OCF_ERR_NO_MEM;
ocf_seq_cutoff_base_init(queue->seq_cutoff,
OCF_SEQ_CUTOFF_PERQUEUE_STREAMS);
return 0;
}
void ocf_queue_seq_cutoff_deinit(ocf_queue_t queue)
{
ocf_seq_cutoff_base_deinit(queue->seq_cutoff);
env_vfree(queue->seq_cutoff);
}
void ocf_dbg_get_seq_cutoff_status(ocf_core_t core, void ocf_dbg_get_seq_cutoff_status(ocf_core_t core,
struct ocf_dbg_seq_cutoff_status *status) struct ocf_dbg_seq_cutoff_status *status)
{ {
@ -118,17 +156,38 @@ void ocf_dbg_get_seq_cutoff_status(ocf_core_t core,
env_rwlock_read_unlock(&core->seq_cutoff->lock); env_rwlock_read_unlock(&core->seq_cutoff->lock);
} }
static bool ocf_core_seq_cutoff_base_check(struct ocf_seq_cutoff *seq_cutoff,
uint64_t addr, uint32_t len, int rw, uint32_t threshold,
struct ocf_seq_cutoff_stream **out_stream)
{
struct ocf_seq_cutoff_stream item = {
.last = addr, .rw = rw
};
struct ocf_seq_cutoff_stream *stream;
struct ocf_rb_node *node;
bool result = false;
node = ocf_rb_tree_find(&seq_cutoff->tree, &item.node);
if (node) {
stream = container_of(node, struct ocf_seq_cutoff_stream, node);
if (stream->bytes + len >= threshold)
result = true;
if (out_stream)
*out_stream = stream;
}
return result;
}
bool ocf_core_seq_cutoff_check(ocf_core_t core, struct ocf_request *req) bool ocf_core_seq_cutoff_check(ocf_core_t core, struct ocf_request *req)
{ {
ocf_seq_cutoff_policy policy = ocf_core_get_seq_cutoff_policy(core); ocf_seq_cutoff_policy policy = ocf_core_get_seq_cutoff_policy(core);
uint32_t threshold = ocf_core_get_seq_cutoff_threshold(core); uint32_t threshold = ocf_core_get_seq_cutoff_threshold(core);
ocf_cache_t cache = ocf_core_get_cache(core); ocf_cache_t cache = ocf_core_get_cache(core);
struct ocf_seq_cutoff_stream item = { struct ocf_seq_cutoff_stream *queue_stream = NULL;
.last = req->byte_position, .rw = req->rw struct ocf_seq_cutoff_stream *core_stream = NULL;
}; bool result;
struct ocf_seq_cutoff_stream *stream;
struct ocf_rb_node *node;
bool result = false;
switch (policy) { switch (policy) {
case ocf_seq_cutoff_policy_always: case ocf_seq_cutoff_policy_always:
@ -145,55 +204,134 @@ bool ocf_core_seq_cutoff_check(ocf_core_t core, struct ocf_request *req)
return false; return false;
} }
result = ocf_core_seq_cutoff_base_check(req->io_queue->seq_cutoff,
req->byte_position, req->byte_length, req->rw,
threshold, &queue_stream);
if (queue_stream)
return result;
env_rwlock_read_lock(&core->seq_cutoff->lock); env_rwlock_read_lock(&core->seq_cutoff->lock);
node = ocf_rb_tree_find(&core->seq_cutoff->tree, &item.node); result = ocf_core_seq_cutoff_base_check(core->seq_cutoff,
if (node) { req->byte_position, req->byte_length, req->rw,
stream = container_of(node, struct ocf_seq_cutoff_stream, node); threshold, &core_stream);
if (stream->bytes + req->byte_length >= threshold)
result = true;
}
env_rwlock_read_unlock(&core->seq_cutoff->lock); env_rwlock_read_unlock(&core->seq_cutoff->lock);
if (core_stream)
req->seq_cutoff_core = true;
return result; return result;
} }
void ocf_core_seq_cutoff_update(ocf_core_t core, struct ocf_request *req) static struct ocf_seq_cutoff_stream *ocf_core_seq_cutoff_base_update(
struct ocf_seq_cutoff *seq_cutoff,
uint64_t addr, uint32_t len, int rw, bool insert)
{ {
ocf_seq_cutoff_policy policy = ocf_core_get_seq_cutoff_policy(core);
struct ocf_seq_cutoff_stream item = { struct ocf_seq_cutoff_stream item = {
.last = req->byte_position, .rw = req->rw .last = addr, .rw = rw
}; };
struct ocf_seq_cutoff_stream *stream; struct ocf_seq_cutoff_stream *stream;
struct ocf_rb_node *node; struct ocf_rb_node *node;
bool can_update; bool can_update;
node = ocf_rb_tree_find(&seq_cutoff->tree, &item.node);
if (node) {
stream = container_of(node, struct ocf_seq_cutoff_stream, node);
item.last = addr + len;
can_update = ocf_rb_tree_can_update(&seq_cutoff->tree,
node, &item.node);
stream->last = addr + len;
stream->bytes += len;
stream->req_count++;
if (!can_update) {
ocf_rb_tree_remove(&seq_cutoff->tree, node);
ocf_rb_tree_insert(&seq_cutoff->tree, node);
}
list_move_tail(&stream->list, &seq_cutoff->lru);
return stream;
}
if (insert) {
stream = list_first_entry(&seq_cutoff->lru,
struct ocf_seq_cutoff_stream, list);
ocf_rb_tree_remove(&seq_cutoff->tree, &stream->node);
stream->rw = rw;
stream->last = addr + len;
stream->bytes = len;
stream->req_count = 1;
stream->valid = true;
ocf_rb_tree_insert(&seq_cutoff->tree, &stream->node);
list_move_tail(&stream->list, &seq_cutoff->lru);
return stream;
}
return NULL;
}
static void ocf_core_seq_cutoff_base_promote(
struct ocf_seq_cutoff *dst_seq_cutoff,
struct ocf_seq_cutoff *src_seq_cutoff,
struct ocf_seq_cutoff_stream *src_stream)
{
struct ocf_seq_cutoff_stream *dst_stream;
dst_stream = list_first_entry(&dst_seq_cutoff->lru,
struct ocf_seq_cutoff_stream, list);
ocf_rb_tree_remove(&dst_seq_cutoff->tree, &dst_stream->node);
dst_stream->rw = src_stream->rw;
dst_stream->last = src_stream->last;
dst_stream->bytes = src_stream->bytes;
dst_stream->req_count = src_stream->req_count;
dst_stream->valid = true;
ocf_rb_tree_insert(&dst_seq_cutoff->tree, &dst_stream->node);
list_move_tail(&dst_stream->list, &dst_seq_cutoff->lru);
src_stream->valid = false;
list_move(&src_stream->list, &src_seq_cutoff->lru);
}
void ocf_core_seq_cutoff_update(ocf_core_t core, struct ocf_request *req)
{
ocf_seq_cutoff_policy policy = ocf_core_get_seq_cutoff_policy(core);
uint32_t threshold = ocf_core_get_seq_cutoff_threshold(core);
uint32_t promotion_count =
ocf_core_get_seq_cutoff_promotion_count(core);
struct ocf_seq_cutoff_stream *stream;
bool promote = false;
if (policy == ocf_seq_cutoff_policy_never) if (policy == ocf_seq_cutoff_policy_never)
return; return;
/* Update last accessed position and bytes counter */ if (req->byte_length >= threshold)
promote = true;
if (promotion_count == 0)
promote = true;
if (req->seq_cutoff_core || promote) {
env_rwlock_write_lock(&core->seq_cutoff->lock); env_rwlock_write_lock(&core->seq_cutoff->lock);
node = ocf_rb_tree_find(&core->seq_cutoff->tree, &item.node); stream = ocf_core_seq_cutoff_base_update(core->seq_cutoff,
if (node) { req->byte_position, req->byte_length, req->rw,
stream = container_of(node, struct ocf_seq_cutoff_stream, node); promote);
item.last = req->byte_position + req->byte_length; env_rwlock_write_unlock(&core->seq_cutoff->lock);
can_update = ocf_rb_tree_can_update(&core->seq_cutoff->tree,
node, &item.node); if (stream)
stream->last = req->byte_position + req->byte_length; return;
stream->bytes += req->byte_length;
if (!can_update) {
ocf_rb_tree_remove(&core->seq_cutoff->tree, node);
ocf_rb_tree_insert(&core->seq_cutoff->tree, node);
}
list_move_tail(&stream->list, &core->seq_cutoff->lru);
} else {
stream = list_first_entry(&core->seq_cutoff->lru,
struct ocf_seq_cutoff_stream, list);
ocf_rb_tree_remove(&core->seq_cutoff->tree, &stream->node);
stream->rw = req->rw;
stream->last = req->byte_position + req->byte_length;
stream->bytes = req->byte_length;
ocf_rb_tree_insert(&core->seq_cutoff->tree, &stream->node);
list_move_tail(&stream->list, &core->seq_cutoff->lru);
} }
stream = ocf_core_seq_cutoff_base_update(req->io_queue->seq_cutoff,
req->byte_position, req->byte_length, req->rw, true);
if (stream->bytes >= threshold)
promote = true;
if (stream->req_count >= promotion_count)
promote = true;
if (promote) {
env_rwlock_write_lock(&core->seq_cutoff->lock);
ocf_core_seq_cutoff_base_promote(core->seq_cutoff,
req->io_queue->seq_cutoff, stream);
env_rwlock_write_unlock(&core->seq_cutoff->lock); env_rwlock_write_unlock(&core->seq_cutoff->lock);
} }
}

View File

@ -14,6 +14,8 @@ struct ocf_seq_cutoff_stream {
uint64_t last; uint64_t last;
uint64_t bytes; uint64_t bytes;
uint32_t rw : 1; uint32_t rw : 1;
uint32_t valid : 1;
uint32_t req_count : 16;
struct ocf_rb_node node; struct ocf_rb_node node;
struct list_head list; struct list_head list;
}; };
@ -21,15 +23,29 @@ struct ocf_seq_cutoff_stream {
struct ocf_seq_cutoff { struct ocf_seq_cutoff {
ocf_core_t core; ocf_core_t core;
env_rwlock lock; env_rwlock lock;
struct ocf_seq_cutoff_stream streams[OCF_SEQ_CUTOFF_MAX_STREAMS];
struct ocf_rb_tree tree; struct ocf_rb_tree tree;
struct list_head lru; struct list_head lru;
struct ocf_seq_cutoff_stream streams[];
};
struct ocf_seq_cutoff_percore {
struct ocf_seq_cutoff base;
struct ocf_seq_cutoff_stream streams[OCF_SEQ_CUTOFF_PERCORE_STREAMS];
};
struct ocf_seq_cutoff_perqueue {
struct ocf_seq_cutoff base;
struct ocf_seq_cutoff_stream streams[OCF_SEQ_CUTOFF_PERQUEUE_STREAMS];
}; };
int ocf_core_seq_cutoff_init(ocf_core_t core); int ocf_core_seq_cutoff_init(ocf_core_t core);
void ocf_core_seq_cutoff_deinit(ocf_core_t core); void ocf_core_seq_cutoff_deinit(ocf_core_t core);
int ocf_queue_seq_cutoff_init(ocf_queue_t queue);
void ocf_queue_seq_cutoff_deinit(ocf_queue_t queue);
bool ocf_core_seq_cutoff_check(ocf_core_t core, struct ocf_request *req); bool ocf_core_seq_cutoff_check(ocf_core_t core, struct ocf_request *req);
void ocf_core_seq_cutoff_update(ocf_core_t core, struct ocf_request *req); void ocf_core_seq_cutoff_update(ocf_core_t core, struct ocf_request *req);

View File

@ -45,6 +45,7 @@ class CoreConfig(Structure):
("_volume_type", c_uint8), ("_volume_type", c_uint8),
("_try_add", c_bool), ("_try_add", c_bool),
("_seq_cutoff_threshold", c_uint32), ("_seq_cutoff_threshold", c_uint32),
("_seq_cutoff_promotion_count", c_uint32),
("_user_metadata", UserMetadata), ("_user_metadata", UserMetadata),
] ]
@ -52,6 +53,7 @@ class CoreConfig(Structure):
class Core: class Core:
DEFAULT_ID = 4096 DEFAULT_ID = 4096
DEFAULT_SEQ_CUTOFF_THRESHOLD = 1024 * 1024 DEFAULT_SEQ_CUTOFF_THRESHOLD = 1024 * 1024
DEFAULT_SEQ_CUTOFF_PROMOTION_COUNT = 8
def __init__( def __init__(
self, self,
@ -59,6 +61,7 @@ class Core:
try_add: bool, try_add: bool,
name: str = "core", name: str = "core",
seq_cutoff_threshold: int = DEFAULT_SEQ_CUTOFF_THRESHOLD, seq_cutoff_threshold: int = DEFAULT_SEQ_CUTOFF_THRESHOLD,
seq_cutoff_promotion_count: int = DEFAULT_SEQ_CUTOFF_PROMOTION_COUNT,
): ):
self.cache = None self.cache = None
self.device = device self.device = device
@ -76,6 +79,7 @@ class Core:
_volume_type=self.device.type_id, _volume_type=self.device.type_id,
_try_add=try_add, _try_add=try_add,
_seq_cutoff_threshold=seq_cutoff_threshold, _seq_cutoff_threshold=seq_cutoff_threshold,
_seq_cutoff_promotion_count=seq_cutoff_promotion_count,
_user_metadata=UserMetadata(_data=None, _size=0), _user_metadata=UserMetadata(_data=None, _size=0),
) )

View File

@ -71,7 +71,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
handled by cache. It should no longer be tracked by OCF, because of request in step 3. which handled by cache. It should no longer be tracked by OCF, because of request in step 3. which
overflowed the OCF handling structure) overflowed the OCF handling structure)
""" """
MAX_STREAMS = 256 MAX_STREAMS = 128
TEST_STREAMS = MAX_STREAMS + 1 # Number of streams used by test - one more than OCF can track TEST_STREAMS = MAX_STREAMS + 1 # Number of streams used by test - one more than OCF can track
core_size = Size.from_MiB(200) core_size = Size.from_MiB(200)
threshold = Size.from_KiB(4) threshold = Size.from_KiB(4)
@ -91,7 +91,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
streams.remove(non_active_stream) streams.remove(non_active_stream)
cache = Cache.start_on_device(Volume(Size.from_MiB(200)), cache_mode=CacheMode.WT) cache = Cache.start_on_device(Volume(Size.from_MiB(200)), cache_mode=CacheMode.WT)
core = Core.using_device(Volume(core_size)) core = Core.using_device(Volume(core_size), seq_cutoff_promotion_count=1)
cache.add_core(core) cache.add_core(core)