Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/mngt/ocf_mngt_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ static void _init_parts_attached(ocf_pipeline_t pipeline, void *priv,
static ocf_error_t __init_cleaning_policy(ocf_cache_t cache)
{
int result;
int i;

OCF_ASSERT_PLUGGED(cache);

Expand All @@ -247,9 +246,6 @@ static ocf_error_t __init_cleaning_policy(ocf_cache_t cache)
if (result)
return result;

for (i = 0; i < ocf_cleaning_max; i++)
ocf_cleaning_setup(cache, i);

result = ocf_cleaning_initialize(cache, cache->cleaner.policy);
if (result)
env_refcnt_deinit(&cache->cleaner.refcnt);
Expand All @@ -263,6 +259,14 @@ static void __deinit_cleaning_policy(ocf_cache_t cache)
env_refcnt_deinit(&cache->cleaner.refcnt);
}

static void __setup_cleaning_policy(ocf_cache_t cache)
{
int i;

for (i = 0; i < ocf_cleaning_max; i++)
ocf_cleaning_setup(cache, i);
}

static void __setup_promotion_policy(ocf_cache_t cache)
{
int i;
Expand Down Expand Up @@ -1512,8 +1516,6 @@ static void _ocf_mngt_attach_init_services(ocf_pipeline_t pipeline,
ocf_cache_t cache = context->cache;
ocf_error_t result;

__setup_promotion_policy(cache);

if (context->metadata.cleaner_disabled)
__set_cleaning_policy(cache, ocf_cleaning_nop);

Expand Down Expand Up @@ -1615,6 +1617,8 @@ static void _ocf_mngt_cache_init(ocf_cache_t cache,
cache->conf_meta->promotion_policy_type = params->metadata.promotion_policy;
cache->conf_meta->prefetch_mask = OCF_PF_MASK_DEFAULT;
ocf_prefetch_setup(cache);
__setup_cleaning_policy(cache);
__setup_promotion_policy(cache);
__set_cleaning_policy(cache, ocf_cleaning_default);

/* Init Partitions */
Expand Down
56 changes: 41 additions & 15 deletions tests/functional/pyocf/types/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
OcfCompletion,
SeqCutOffPolicy,
)
from ..utils import Size, struct_to_dict
from ..utils import Size, struct_to_dict, range_inclusive
from .core import Core
from .queue import Queue
from .stats.cache import CacheInfo
Expand Down Expand Up @@ -134,24 +134,26 @@ class CacheStandbyActivateConfig(Structure):


class ConfValidValues:
promotion_nhit_insertion_threshold_range = range(2, 1000)
promotion_nhit_trigger_threshold_range = range(0, 100)
promotion_nhit_insertion_threshold_range = range_inclusive(2, 1000)
promotion_nhit_trigger_threshold_range = range_inclusive(0, 100)

cleaning_alru_wake_up_time_range = range(0, 3600)
cleaning_alru_staleness_time_range = range(1, 3600)
cleaning_alru_flush_max_buffers_range = range(1, 10000)
cleaning_alru_activity_threshold_range = range(0, 1000000)
cleaning_alru_wake_up_time_range = range_inclusive(0, 3600)
cleaning_alru_staleness_time_range = range_inclusive(1, 3600)
cleaning_alru_flush_max_buffers_range = range_inclusive(1, 10000)
cleaning_alru_activity_threshold_range = range_inclusive(0, 1000000)
cleaning_alru_dirty_ratio_threshold_range = range_inclusive(0, 100)
cleaning_alru_dirty_ratio_inertia_range = range_inclusive(0, 2**32 - 1)

cleaning_acp_wake_up_time_range = range(0, 10000)
cleaning_acp_flush_max_buffers_range = range(1, 10000)
cleaning_acp_wake_up_time_range = range_inclusive(0, 10000)
cleaning_acp_flush_max_buffers_range = range_inclusive(1, 10000)

seq_cutoff_threshold_rage = range(1, 4294841344)
seq_detect_promotion_count_range = range(1, 65535)
seq_cutoff_threshold_rage = range_inclusive(1, 4294841344)
seq_detect_promotion_count_range = range_inclusive(1, 65535)

ioclass_id_range = range(0, 32)
ioclass_priority_range = range(-1, 255)
ioclass_min_size_range = range(0, 100)
ioclass_max_size_range = range(0, 100)
ioclass_id_range = range_inclusive(0, 33)
ioclass_priority_range = range_inclusive(-1, 255)
ioclass_min_size_range = range_inclusive(0, 100)
ioclass_max_size_range = range_inclusive(0, 100)


CACHE_MODE_NONE = -1
Expand Down Expand Up @@ -225,6 +227,8 @@ class AlruParams(IntEnum):
STALE_BUFFER_TIME = 1
FLUSH_MAX_BUFFERS = 2
ACTIVITY_THRESHOLD = 3
DIRTY_RATIO_THRESHOLD = 4
DIRTY_RATIO_INERTIA = 5

def __str__(self):
return self.name
Expand Down Expand Up @@ -425,6 +429,21 @@ def set_cleaning_policy_param(self, cleaning_policy: CleaningPolicy, param_id, p
if status:
raise OcfError("Error setting cleaning policy param", status)

def get_cleaning_policy_param(self, cleaning_policy: CleaningPolicy, param_id):
self.read_lock()

param_value = c_uint32()

status = self.owner.lib.ocf_mngt_cache_cleaning_get_param(
self.cache_handle, cleaning_policy, param_id, byref(param_value)
)

self.read_unlock()
if status:
raise OcfError("Error getting cleaning policy param", status)

return param_value.value

def set_promotion_policy(self, promotion_policy: PromotionPolicy):
self.write_lock()

Expand Down Expand Up @@ -1282,6 +1301,13 @@ def get_by_name(cache_name, owner=None):
c_uint32,
]
lib.ocf_mngt_cache_cleaning_set_param.restype = c_int
lib.ocf_mngt_cache_cleaning_get_param.argtypes = [
c_void_p,
c_uint32,
c_uint32,
POINTER(c_uint32),
]
lib.ocf_mngt_cache_cleaning_get_param.restype = c_int
lib.ocf_mngt_cache_prefetch_set_policy.argtypes = [c_void_p, c_uint8]
lib.ocf_mngt_cache_prefetch_set_policy.restype = c_int
lib.ocf_mngt_cache_prefetch_get_policy.argtypes = [c_void_p, POINTER(c_uint8)]
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/pyocf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ def print_buffer(
print_fcn("<'0x{:02X}' until end>".format(ignore))


def range_inclusive(start, stop):
return range(start, stop + 1)


class Size:
_KiB = 1024
_MiB = _KiB * 1024
Expand Down
89 changes: 89 additions & 0 deletions tests/functional/tests/cleaning/test_alru.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def cleaner_core_wr(stats):
return stats["block"]["cleaner_core_wr"]["value"]


def cache_lines(stats):
return int(stats["conf"]["size"])


# -- cache setup helpers --

def setup_cache(pyocf_ctx, cls=CacheLineSize.DEFAULT):
Expand Down Expand Up @@ -257,3 +261,88 @@ def test_alru_activity_threshold(pyocf_ctx, manual_cleaner, activity_threshold):
manual_cleaner.run_until_idle(cache)

assert dirty_blocks(cache.get_stats()) == 0


def setup_dirty_ratio(cache, threshold, inertia, flush_max):
"""Configure ALRU so that only the dirty ratio can trigger cleaning:
data never gets stale and I/O activity is always recent, as the test
does not advance time."""
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.WAKE_UP_TIME, 1
)
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.STALE_BUFFER_TIME, 3600
)
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.ACTIVITY_THRESHOLD, 1000000
)
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.FLUSH_MAX_BUFFERS, flush_max
)
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.DIRTY_RATIO_THRESHOLD, threshold
)
cache.set_cleaning_policy_param(
CleaningPolicy.ALRU, AlruParams.DIRTY_RATIO_INERTIA, inertia
)
cache.set_cleaning_policy(CleaningPolicy.ALRU)


@pytest.mark.parametrize("threshold", [10, 30, 50])
def test_alru_dirty_ratio_threshold(pyocf_ctx, manual_cleaner, threshold):
"""Verify cleaning is triggered by exceeding the dirty ratio threshold
regardless of staleness and I/O activity, and that it stops as soon as
the dirty ratio drops below the threshold."""
cache, core, vol, queue = setup_cache(pyocf_ctx)

flush_max = 100
setup_dirty_ratio(cache, threshold, 0, flush_max)

# Default cache line size is 4 KiB, so 4 KiB blocks == cache lines
threshold_cl = cache_lines(cache.get_stats()) // 100 * threshold

# Stay below the threshold - nothing should be cleaned
below = threshold_cl - flush_max
fill_dirty(vol, queue, Size(0), STATS_BLOCK_SIZE * below)

manual_cleaner.run(cache)
assert dirty_blocks(cache.get_stats()) == below, \
"No data should be flushed below dirty ratio threshold"

# Exceed the threshold
above = threshold_cl + 5 * flush_max
fill_dirty(vol, queue, STATS_BLOCK_SIZE * below,
STATS_BLOCK_SIZE * (above - below))
assert dirty_blocks(cache.get_stats()) == above

manual_cleaner.run_until_idle(cache)

dirty = dirty_blocks(cache.get_stats())
assert threshold_cl - flush_max <= dirty < threshold_cl, \
f"Cleaning should stop right below threshold {threshold_cl}, " \
f"dirty: {dirty}"


@pytest.mark.parametrize("inertia", [Size.from_MiB(1), Size.from_MiB(4)])
def test_alru_dirty_ratio_inertia(pyocf_ctx, manual_cleaner, inertia):
"""Verify cleaning triggered by dirty ratio continues until the dirty
ratio drops below (threshold - inertia)."""
cache, core, vol, queue = setup_cache(pyocf_ctx)

flush_max = 100
threshold = 30
setup_dirty_ratio(cache, threshold, int(inertia), flush_max)

threshold_cl = cache_lines(cache.get_stats()) // 100 * threshold
inertia_cl = inertia // STATS_BLOCK_SIZE
stop_cl = threshold_cl - inertia_cl

above = threshold_cl + flush_max
fill_dirty(vol, queue, Size(0), STATS_BLOCK_SIZE * above)

manual_cleaner.run_until_idle(cache)

dirty = dirty_blocks(cache.get_stats())
assert stop_cl - flush_max <= dirty < stop_cl, \
f"Cleaning should stop right below {stop_cl} " \
f"(threshold {threshold_cl} - inertia {inertia_cl}), dirty: {dirty}"
59 changes: 59 additions & 0 deletions tests/functional/tests/management/test_attach_cache.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#
# Copyright(c) 2019-2022 Intel Corporation
# Copyright(c) 2024-2025 Huawei Technologies
# Copyright(c) 2026 Unvertical
# SPDX-License-Identifier: BSD-3-Clause
#

Expand All @@ -12,6 +13,12 @@
Cache,
CacheMode,
CleaningPolicy,
AlruParams,
AcpParams,
PromotionPolicy,
NhitParams,
Prefetcher,
ReadaheadParams,
)
from pyocf.types.core import Core
from pyocf.types.data import Data
Expand Down Expand Up @@ -128,6 +135,58 @@ def test_detach_cache_zero_superblock(pyocf_ctx):
cache.stop()


def test_reattach_preserves_policy_params(pyocf_ctx):
"""Check if cleaning, promotion and prefetch policy parameters set before
detach are preserved after the cache device is attached again.
"""
cache_device = RamVolume(Size.from_MiB(50))
cache = Cache.start_on_device(cache_device)

# Non-default values of all the parameters
alru_params = {
AlruParams.WAKE_UP_TIME: 30,
AlruParams.STALE_BUFFER_TIME: 60,
AlruParams.FLUSH_MAX_BUFFERS: 50,
AlruParams.ACTIVITY_THRESHOLD: 5000,
AlruParams.DIRTY_RATIO_THRESHOLD: 50,
AlruParams.DIRTY_RATIO_INERTIA: 1024,
}
acp_params = {
AcpParams.WAKE_UP_TIME: 100,
AcpParams.FLUSH_MAX_BUFFERS: 64,
}
nhit_params = {
NhitParams.INSERTION_THRESHOLD: 5,
NhitParams.TRIGGER_THRESHOLD: 50,
}
readahead_params = {
ReadaheadParams.THRESHOLD: 128 * 1024,
}

for param_id, value in alru_params.items():
cache.set_cleaning_policy_param(CleaningPolicy.ALRU, param_id, value)
for param_id, value in acp_params.items():
cache.set_cleaning_policy_param(CleaningPolicy.ACP, param_id, value)
for param_id, value in nhit_params.items():
cache.set_promotion_policy_param(PromotionPolicy.NHIT, param_id, value)
for param_id, value in readahead_params.items():
cache.set_prefetch_param(Prefetcher.READAHEAD, param_id, value)

cache.detach_device()
cache.attach_device(cache_device, force=False)

for param_id, value in alru_params.items():
assert cache.get_cleaning_policy_param(CleaningPolicy.ALRU, param_id) == value
for param_id, value in acp_params.items():
assert cache.get_cleaning_policy_param(CleaningPolicy.ACP, param_id) == value
for param_id, value in nhit_params.items():
assert cache.get_promotion_policy_param(PromotionPolicy.NHIT, param_id).value == value
for param_id, value in readahead_params.items():
assert cache.get_prefetch_param(Prefetcher.READAHEAD, param_id) == value

cache.stop()


@pytest.mark.parametrize("cls", CacheLineSize)
@pytest.mark.parametrize("mode", [CacheMode.WB, CacheMode.WT, CacheMode.WO])
@pytest.mark.parametrize("new_cache_size", [80, 120])
Expand Down
4 changes: 4 additions & 0 deletions tests/functional/tests/security/test_management_fuzzy.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ def get_alru_param_valid_rage(param_id):
return ConfValidValues.cleaning_alru_flush_max_buffers_range
elif param_id == AlruParams.ACTIVITY_THRESHOLD:
return ConfValidValues.cleaning_alru_activity_threshold_range
elif param_id == AlruParams.DIRTY_RATIO_THRESHOLD:
return ConfValidValues.cleaning_alru_dirty_ratio_threshold_range
elif param_id == AlruParams.DIRTY_RATIO_INERTIA:
return ConfValidValues.cleaning_alru_dirty_ratio_inertia_range


@pytest.mark.parametrize("cm", CacheMode)
Expand Down
Loading