Merge pull request #245 from imjfckm/switching-pp

Switching mechanism for promotion policies
This commit is contained in:
Robert Bałdyga 2019-08-30 11:35:16 +02:00 committed by GitHub
commit 5fd239d2bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 288 additions and 63 deletions

View File

@ -24,6 +24,7 @@
#include "ocf_cleaner.h"
#include "cleaning/alru.h"
#include "cleaning/acp.h"
#include "promotion/nhit.h"
#include "ocf_metadata.h"
#include "ocf_metadata_updater.h"
#include "ocf_io_class.h"

View File

@ -778,7 +778,7 @@ int ocf_mngt_cache_cleaning_set_param(ocf_cache_t cache, ocf_cleaning_t type,
* @param[in] cache Cache handle
* @param[in] type Cleaning policy type
* @param[in] param_id Cleaning policy parameter id
* @param[in] param_value Variable to store parameter value
* @param[out] param_value Variable to store parameter value
*
* @retval 0 Parameter has been get successfully
* @retval Non-zero Error occurred and parameter has not been get
@ -786,6 +786,55 @@ int ocf_mngt_cache_cleaning_set_param(ocf_cache_t cache, ocf_cleaning_t type,
int ocf_mngt_cache_cleaning_get_param(ocf_cache_t cache,ocf_cleaning_t type,
uint32_t param_id, uint32_t *param_value);
/**
* @brief Set promotion policy in given cache
*
* @attention This changes only runtime state. To make changes persistent
* use function ocf_mngt_cache_save().
*
* @param[in] cache Cache handle
* @param[in] type Promotion policy type
*
* @retval 0 Policy has been set successfully
* @retval Non-zero Error occurred and policy has not been set
*/
int ocf_mngt_cache_promotion_set_policy(ocf_cache_t cache, ocf_promotion_t type);
/**
* @brief Get promotion policy in given cache
*
* @param[in] cache Cache handle
*
* @retval Currently set promotion policy type
*/
ocf_promotion_t ocf_mngt_cache_promotion_get_policy(ocf_cache_t cache);
/**
* @brief Set promotion policy parameter for given cache
*
* @param[in] cache Cache handle
* @param[in] param_id Promotion policy parameter id
* @param[in] param_value Promotion policy parameter value
*
* @retval 0 Parameter has been set successfully
* @retval Non-zero Error occurred and parameter has not been set
*/
int ocf_mngt_cache_promotion_set_param(ocf_cache_t cache, uint8_t param_id,
uint64_t param_value);
/**
* @brief Get promotion policy parameter for given cache
*
* @param[in] cache Cache handle
* @param[in] param_id Promotion policy parameter id
* @param[out] param_value Variable to store parameter value
*
* @retval 0 Parameter has been retrieved successfully
* @retval Non-zero Error occurred and parameter has not been retrieved
*/
int ocf_mngt_cache_promotion_get_param(ocf_cache_t cache, uint8_t param_id,
uint64_t *param_value);
/**
* @brief IO class configuration
*/

23
inc/promotion/nhit.h Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright(c) 2019 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef __OCF_PROMOTION_NHIT_H__
#define __OCF_PROMOTION_NHIT_H__
enum nhit_param {
nhit_insertion_threshold,
nhit_trigger_threshold,
nhit_param_max
};
#define NHIT_MIN_THRESHOLD 2
#define NHIT_MAX_THRESHOLD 1000
#define NHIT_THRESHOLD_DEFAULT 3
#define NHIT_MIN_TRIGGER 0
#define NHIT_MAX_TRIGGER 100
#define NHIT_TRIGGER_DEFAULT 80
#endif /* __OCF_PROMOTION_NHIT_H__ */

View File

@ -83,8 +83,6 @@ static int _ocf_discard_core(struct ocf_request *req)
ocf_volume_submit_discard(io);
ocf_promotion_req_purge(req->cache->promotion_policy, req);
return 0;
}
@ -186,6 +184,14 @@ int _ocf_discard_step_do(struct ocf_request *req)
OCF_METADATA_UNLOCK_WR(); /*- END Metadata WR access ---------*/
}
OCF_METADATA_LOCK_RD();
/* Even if no cachelines are mapped they could be tracked in promotion
* policy. RD lock suffices. */
ocf_promotion_req_purge(req->cache->promotion_policy, req);
OCF_METADATA_UNLOCK_RD();
OCF_DEBUG_RQ(req, "Discard");
_ocf_discard_step_complete(req, 0);

View File

@ -2224,6 +2224,62 @@ int ocf_mngt_cache_set_mode(ocf_cache_t cache, ocf_cache_mode_t mode)
return result;
}
int ocf_mngt_cache_promotion_set_policy(ocf_cache_t cache, ocf_promotion_t type)
{
int result;
OCF_METADATA_LOCK_WR();
result = ocf_promotion_set_policy(cache->promotion_policy, type);
OCF_METADATA_UNLOCK_WR();
return result;
}
ocf_promotion_t ocf_mngt_cache_promotion_get_policy(ocf_cache_t cache)
{
ocf_promotion_t result;
OCF_METADATA_LOCK_RD();
result = cache->conf_meta->promotion_policy_type;
OCF_METADATA_UNLOCK_RD();
return result;
}
int ocf_mngt_cache_promotion_get_param(ocf_cache_t cache, uint8_t param_id,
uint64_t *param_value)
{
int result;
OCF_METADATA_LOCK_RD();
result = ocf_promotion_get_param(cache->promotion_policy, param_id,
param_value);
OCF_METADATA_UNLOCK_RD();
return result;
}
int ocf_mngt_cache_promotion_set_param(ocf_cache_t cache, uint8_t param_id,
uint64_t param_value)
{
int result;
OCF_METADATA_LOCK_RD();
result = ocf_promotion_set_param(cache->promotion_policy, param_id,
param_value);
OCF_METADATA_UNLOCK_RD();
return result;
}
int ocf_mngt_cache_reset_fallback_pt_error_counter(ocf_cache_t cache)
{
OCF_CHECK_NULL(cache);

View File

@ -1,25 +0,0 @@
/*
* Copyright(c) 2019 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef NHIT_HASH_H_
#define NHIT_HASH_H_
#include "ocf/ocf.h"
typedef struct nhit_hash *nhit_hash_t;
ocf_error_t hash_init(uint64_t hash_size, nhit_hash_t *ctx);
void hash_deinit(nhit_hash_t ctx);
void hash_insert(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba);
bool hash_query(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba,
int32_t *counter);
void hash_set_occurences(nhit_hash_t ctx, ocf_core_id_t core_id,
uint64_t core_lba, int32_t occurences);
#endif /* NHIT_HASH_H_ */

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "hash.h"
#include "nhit_hash.h"
#include "../../metadata/metadata.h"
#include "../../ocf_priv.h"
#include "../../engine/engine_common.h"
@ -13,15 +13,12 @@
#define NHIT_MAPPING_RATIO 2
#define NHIT_MIN_THRESHOLD 1
#define NHIT_MAX_THRESHOLD 1000
#define NHIT_THRESHOLD_DEFAULT 3
struct nhit_policy_context {
nhit_hash_t hash_map;
/* Configurable parameters */
env_atomic insertion_threshold;
env_atomic64 trigger_threshold;
};
ocf_error_t nhit_init(ocf_cache_t cache, ocf_promotion_policy_t policy)
@ -35,12 +32,15 @@ ocf_error_t nhit_init(ocf_cache_t cache, ocf_promotion_policy_t policy)
goto exit;
}
result = hash_init(ocf_metadata_get_cachelines_count(cache) *
result = nhit_hash_init(ocf_metadata_get_cachelines_count(cache) *
NHIT_MAPPING_RATIO, &ctx->hash_map);
if (result)
goto dealloc_ctx;
env_atomic_set(&ctx->insertion_threshold, NHIT_THRESHOLD_DEFAULT);
env_atomic64_set(&ctx->trigger_threshold,
OCF_DIV_ROUND_UP((NHIT_TRIGGER_DEFAULT *
ocf_metadata_get_cachelines_count(cache)), 100));
policy->ctx = ctx;
@ -57,7 +57,7 @@ void nhit_deinit(ocf_promotion_policy_t policy)
{
struct nhit_policy_context *ctx = policy->ctx;
hash_deinit(ctx->hash_map);
nhit_hash_deinit(ctx->hash_map);
env_vfree(ctx);
policy->ctx = NULL;
@ -71,7 +71,7 @@ ocf_error_t nhit_set_param(ocf_promotion_policy_t policy, uint8_t param_id,
switch (param_id) {
case nhit_insertion_threshold:
if (param_value > NHIT_MIN_THRESHOLD &&
if (param_value >= NHIT_MIN_THRESHOLD &&
param_value < NHIT_MAX_THRESHOLD) {
env_atomic_set(&ctx->insertion_threshold, param_value);
} else {
@ -81,6 +81,22 @@ ocf_error_t nhit_set_param(ocf_promotion_policy_t policy, uint8_t param_id,
}
break;
case nhit_trigger_threshold:
if (param_value >= NHIT_MIN_TRIGGER &&
param_value < NHIT_MAX_TRIGGER) {
env_atomic64_set(&ctx->trigger_threshold,
OCF_DIV_ROUND_UP((param_value *
ocf_metadata_get_cachelines_count(policy->owner)),
100));
} else {
ocf_cache_log(policy->owner, log_err, "Invalid nhit "
"promotion policy insertion trigger "
"threshold!\n");
result = -OCF_ERR_INVAL;
}
break;
default:
ocf_cache_log(policy->owner, log_err, "Invalid nhit "
"promotion policy parameter (%u)!\n",
@ -121,7 +137,7 @@ ocf_error_t nhit_get_param(ocf_promotion_policy_t policy, uint8_t param_id,
static void core_line_purge(struct nhit_policy_context *ctx, ocf_core_id_t core_id,
uint64_t core_lba)
{
hash_set_occurences(ctx->hash_map, core_id, core_lba, 0);
nhit_hash_set_occurences(ctx->hash_map, core_id, core_lba, 0);
}
void nhit_req_purge(ocf_promotion_policy_t policy,
@ -145,13 +161,13 @@ static bool core_line_should_promote(struct nhit_policy_context *ctx,
bool hit;
int32_t counter;
hit = hash_query(ctx->hash_map, core_id, core_lba, &counter);
hit = nhit_hash_query(ctx->hash_map, core_id, core_lba, &counter);
if (hit) {
/* we have a hit, return now */
return env_atomic_read(&ctx->insertion_threshold) <= counter;
}
hash_insert(ctx->hash_map, core_id, core_lba);
nhit_hash_insert(ctx->hash_map, core_id, core_lba);
return false;
}
@ -163,6 +179,12 @@ bool nhit_req_should_promote(ocf_promotion_policy_t policy,
bool result = true;
uint32_t i;
uint64_t core_line;
uint64_t occupied_cachelines =
ocf_metadata_get_cachelines_count(policy->owner) -
policy->owner->device->freelist_part->curr_size;
if (occupied_cachelines > env_atomic64_read(&ctx->trigger_threshold))
return true;
for (i = 0, core_line = req->core_line_first;
core_line <= req->core_line_last; core_line++, i++) {

View File

@ -10,11 +10,6 @@
#include "../../ocf_request.h"
#include "../promotion.h"
enum nhit_param {
nhit_insertion_threshold,
nhit_param_max
};
ocf_error_t nhit_init(ocf_cache_t cache, ocf_promotion_policy_t policy);
void nhit_deinit(ocf_promotion_policy_t policy);

View File

@ -5,7 +5,7 @@
#include "../../ocf_priv.h"
#include "hash.h"
#include "nhit_hash.h"
/* Implementation of hashmap-ish structure for tracking core lines in nhit
* promotion policy. It consists of two arrays:
@ -17,6 +17,9 @@
* and insert elements from the beggining. So lifetime of a core line varies
* depending on insertion and removal rate.
*
* and rb_pointer which is index to ring_buffer element that is going to be used
* for next insertion.
*
* Operations:
* - query(core_id, core_lba):
* Check if core line is present in structure, bump up counter and
@ -55,9 +58,10 @@
* | ^ | ^
* |________| |________|
*
* Since rb_pointer is pointing to occupied rb slot we need to write-lock hash
* bucket I associated with this slot and remove it from collision list.
* We've gained an empty slot and we use slot X for new hash H entry.
* We will attempt to insert new element at rb_pointer. Since rb_pointer is
* pointing to occupied rb slot we need to write-lock hash bucket I associated
* with this slot and remove it from collision list. We've gained an empty slot
* and we use slot X for new hash H entry.
*
* +--+--+--+--+--+--+--+--+--+--+
* | | |I | | | | | |H | | hash_map
@ -105,11 +109,12 @@ struct nhit_hash {
env_spinlock rb_pointer_lock;
};
ocf_error_t hash_init(uint64_t hash_size, nhit_hash_t *ctx)
ocf_error_t nhit_hash_init(uint64_t hash_size, nhit_hash_t *ctx)
{
int result = 0;
struct nhit_hash *new_ctx;
uint64_t i;
uint32_t i;
int64_t i_locks;
new_ctx = env_vzalloc(sizeof(*new_ctx));
if (!new_ctx) {
@ -138,9 +143,10 @@ ocf_error_t hash_init(uint64_t hash_size, nhit_hash_t *ctx)
goto dealloc_hash;
}
for (i = 0; i < new_ctx->hash_entries; i++) {
if (env_rwsem_init(&new_ctx->hash_locks[i])) {
for (i_locks = 0; i_locks < new_ctx->hash_entries; i_locks++) {
if (env_rwsem_init(&new_ctx->hash_locks[i_locks])) {
result = -OCF_ERR_UNKNOWN;
i_locks--;
goto dealloc_locks;
}
}
@ -164,8 +170,8 @@ ocf_error_t hash_init(uint64_t hash_size, nhit_hash_t *ctx)
return 0;
dealloc_locks:
for (i = 0; i < new_ctx->hash_entries; i++)
ENV_BUG_ON(env_rwsem_destroy(&new_ctx->hash_locks[i]));
for (; i_locks >= 0; i_locks--)
ENV_BUG_ON(env_rwsem_destroy(&new_ctx->hash_locks[i_locks]));
env_vfree(new_ctx->hash_locks);
dealloc_hash:
env_vfree(new_ctx->hash_map);
@ -175,7 +181,7 @@ exit:
return result;
}
void hash_deinit(nhit_hash_t ctx)
void nhit_hash_deinit(nhit_hash_t ctx)
{
ocf_cache_line_t i;
@ -323,7 +329,7 @@ static inline void write_unlock_hashes(nhit_hash_t ctx, ocf_core_id_t core_id1,
env_rwsem_up_write(&ctx->hash_locks[hash2]);
}
void hash_insert(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba)
void nhit_hash_insert(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba)
{
uint64_t slot_id;
struct nhit_list_elem *slot;
@ -347,15 +353,15 @@ void hash_insert(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba)
commit_rb_slot(ctx, slot_id);
}
bool hash_query(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba,
bool nhit_hash_query(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba,
int32_t *counter)
{
OCF_CHECK_NULL(counter);
ocf_cache_line_t hash = hash_function(core_id, core_lba,
ctx->hash_entries);
uint64_t rb_idx;
OCF_CHECK_NULL(counter);
env_rwsem_down_read(&ctx->hash_locks[hash]);
rb_idx = core_line_lookup(ctx, core_id, core_lba);
@ -371,7 +377,7 @@ bool hash_query(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba,
return true;
}
void hash_set_occurences(nhit_hash_t ctx, ocf_core_id_t core_id,
void nhit_hash_set_occurences(nhit_hash_t ctx, ocf_core_id_t core_id,
uint64_t core_lba, int32_t occurences)
{
ocf_cache_line_t hash = hash_function(core_id, core_lba,

View File

@ -0,0 +1,24 @@
/*
* Copyright(c) 2019 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef NHIT_HASH_H_
#define NHIT_HASH_H_
#include "ocf/ocf.h"
typedef struct nhit_hash *nhit_hash_t;
ocf_error_t nhit_hash_init(uint64_t hash_size, nhit_hash_t *ctx);
void nhit_hash_deinit(nhit_hash_t ctx);
void nhit_hash_insert(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba);
bool nhit_hash_query(nhit_hash_t ctx, ocf_core_id_t core_id, uint64_t core_lba,
int32_t *counter);
void nhit_hash_set_occurences(nhit_hash_t ctx, ocf_core_id_t core_id,
uint64_t core_lba, int32_t occurences);
#endif /* NHIT_HASH_H_ */

View File

@ -11,6 +11,7 @@
struct ocf_promotion_policy {
ocf_cache_t owner;
ocf_promotion_t type;
void *ctx;
};

View File

@ -55,6 +55,35 @@ void ocf_promotion_deinit(ocf_promotion_policy_t policy)
env_vfree(policy);
}
ocf_error_t ocf_promotion_set_policy(ocf_promotion_policy_t policy,
ocf_promotion_t type)
{
ocf_error_t result = 0;
ocf_cache_t cache = policy->owner;
ocf_promotion_t prev_policy;
prev_policy = cache->conf_meta->promotion_policy_type;
if (ocf_promotion_policies[prev_policy].deinit)
ocf_promotion_policies[prev_policy].deinit(policy);
cache->conf_meta->promotion_policy_type = type;
if (ocf_promotion_policies[type].init)
result = ocf_promotion_policies[type].init(cache, policy);
if (result) {
ocf_cache_log(cache, log_err,
"Error switching to new promotion policy\n");
ocf_cache_log(cache, log_err,
"Falling back to 'always' promotion policy\n");
cache->conf_meta->promotion_policy_type = ocf_promotion_always;
policy->type = ocf_promotion_always;
}
return result;
}
ocf_error_t ocf_promotion_set_param(ocf_promotion_policy_t policy,
uint8_t param_id, uint64_t param_value)
{

View File

@ -31,6 +31,16 @@ ocf_error_t ocf_promotion_init(ocf_cache_t cache, ocf_promotion_policy_t *policy
*/
void ocf_promotion_deinit(ocf_promotion_policy_t policy);
/**
* @brief Switch promotion policy to type. On failure will fall back to 'always'
*
* @param[in] policy promotion policy handle
* @param[in] type promotion policy target type
*
* @retval ocf_error_t
*/
ocf_error_t ocf_promotion_set_policy(ocf_promotion_policy_t policy,
ocf_promotion_t type);
/**
* @brief Set promotion policy parameter
*

View File

@ -95,9 +95,9 @@ class EvictionPolicy(IntEnum):
class PromotionPolicy(IntEnum):
NOP = 0
ALWAYS = 0
NHIT = 1
DEFAULT = NOP
DEFAULT = ALWAYS
class CleaningPolicy(IntEnum):
@ -240,6 +240,28 @@ class Cache:
if status:
raise OcfError("Error setting cleaning policy param", status)
def set_promotion_policy(self, promotion_policy: PromotionPolicy):
self.write_lock()
status = self.owner.lib.ocf_mngt_cache_promotion_set_policy(
self.cache_handle, promotion_policy
)
self.write_unlock()
if status:
raise OcfError("Error setting promotion policy", status)
def set_promotion_policy_param(self, param_id, param_value):
self.write_lock()
status = self.owner.lib.ocf_mngt_cache_promotion_set_param(
self.cache_handle, param_id, param_value
)
self.write_unlock()
if status:
raise OcfError("Error setting promotion policy parameter", status)
def set_seq_cut_off_policy(self, policy: SeqCutOffPolicy):
self.write_lock()
@ -558,7 +580,13 @@ lib.ocf_mngt_cache_cleaning_set_policy.argtypes = [c_void_p, c_uint32]
lib.ocf_mngt_cache_cleaning_set_policy.restype = c_int
lib.ocf_mngt_core_set_seq_cutoff_policy_all.argtypes = [c_void_p, c_uint32]
lib.ocf_mngt_core_set_seq_cutoff_policy_all.restype = c_int
lib.ocf_stats_collect_cache.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c_void_p]
lib.ocf_stats_collect_cache.argtypes = [
c_void_p,
c_void_p,
c_void_p,
c_void_p,
c_void_p,
]
lib.ocf_stats_collect_cache.restype = c_int
lib.ocf_cache_get_info.argtypes = [c_void_p, c_void_p]
lib.ocf_cache_get_info.restype = c_int