diff --git a/inc/ocf.h b/inc/ocf.h index cfa4ad9..07c98b0 100644 --- a/inc/ocf.h +++ b/inc/ocf.h @@ -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" diff --git a/inc/ocf_mngt.h b/inc/ocf_mngt.h index 7318bd6..cb8ee71 100644 --- a/inc/ocf_mngt.h +++ b/inc/ocf_mngt.h @@ -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 */ diff --git a/inc/promotion/nhit.h b/inc/promotion/nhit.h new file mode 100644 index 0000000..943b437 --- /dev/null +++ b/inc/promotion/nhit.h @@ -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__ */ diff --git a/src/engine/engine_discard.c b/src/engine/engine_discard.c index 4a30daf..cc9c938 100644 --- a/src/engine/engine_discard.c +++ b/src/engine/engine_discard.c @@ -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); diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index ecc638d..52e8e62 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -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); diff --git a/src/promotion/nhit/hash.h b/src/promotion/nhit/hash.h deleted file mode 100644 index 8bec31e..0000000 --- a/src/promotion/nhit/hash.h +++ /dev/null @@ -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_ */ diff --git a/src/promotion/nhit/nhit.c b/src/promotion/nhit/nhit.c index a0d731a..7648768 100644 --- a/src/promotion/nhit/nhit.c +++ b/src/promotion/nhit/nhit.c @@ -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++) { diff --git a/src/promotion/nhit/nhit.h b/src/promotion/nhit/nhit.h index d527ed0..36b1cc5 100644 --- a/src/promotion/nhit/nhit.h +++ b/src/promotion/nhit/nhit.h @@ -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); diff --git a/src/promotion/nhit/hash.c b/src/promotion/nhit/nhit_hash.c similarity index 90% rename from src/promotion/nhit/hash.c rename to src/promotion/nhit/nhit_hash.c index 122b189..cb07c75 100644 --- a/src/promotion/nhit/hash.c +++ b/src/promotion/nhit/nhit_hash.c @@ -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, diff --git a/src/promotion/nhit/nhit_hash.h b/src/promotion/nhit/nhit_hash.h new file mode 100644 index 0000000..407b34c --- /dev/null +++ b/src/promotion/nhit/nhit_hash.h @@ -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_ */ diff --git a/src/promotion/ops.h b/src/promotion/ops.h index 87b2e87..7a6f256 100644 --- a/src/promotion/ops.h +++ b/src/promotion/ops.h @@ -11,6 +11,7 @@ struct ocf_promotion_policy { ocf_cache_t owner; + ocf_promotion_t type; void *ctx; }; diff --git a/src/promotion/promotion.c b/src/promotion/promotion.c index c7bc3be..aa4c8b4 100644 --- a/src/promotion/promotion.c +++ b/src/promotion/promotion.c @@ -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) { diff --git a/src/promotion/promotion.h b/src/promotion/promotion.h index c85bb5f..fe2c2db 100644 --- a/src/promotion/promotion.h +++ b/src/promotion/promotion.h @@ -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 * diff --git a/tests/functional/pyocf/types/cache.py b/tests/functional/pyocf/types/cache.py index d3aa744..c8fcf7c 100644 --- a/tests/functional/pyocf/types/cache.py +++ b/tests/functional/pyocf/types/cache.py @@ -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