|
1 | 1 | # |
2 | 2 | # Copyright(c) 2020-2021 Intel Corporation |
3 | | -# Copyright(c) 2024 Huawei Technologies Co., Ltd. |
| 3 | +# Copyright(c) 2024-2025 Huawei Technologies Co., Ltd. |
4 | 4 | # SPDX-License-Identifier: BSD-3-Clause |
5 | 5 | # |
6 | 6 |
|
|
10 | 10 | from datetime import timedelta |
11 | 11 |
|
12 | 12 | from api.cas import casadm |
13 | | -from api.cas.cache_config import CacheMode, CleaningPolicy, FlushParametersAlru, SeqCutOffPolicy |
| 13 | +from api.cas.cache_config import ( |
| 14 | + CacheMode, |
| 15 | + CleaningPolicy, |
| 16 | + FlushParametersAlru, |
| 17 | + SeqCutOffPolicy, |
| 18 | + CacheLineSize, |
| 19 | +) |
14 | 20 | from core.test_run import TestRun |
15 | 21 | from storage_devices.disk import DiskType, DiskTypeSet, DiskTypeLowerThan |
16 | 22 | from test_tools.fio.fio import Fio |
17 | 23 | from test_tools.fio.fio_param import ReadWrite, IoEngine |
18 | | -from test_tools.os_tools import kill_all_io |
| 24 | +from test_tools.os_tools import kill_all_io, sync |
19 | 25 | from test_tools.udev import Udev |
20 | 26 | from type_def.size import Size, Unit |
21 | 27 | from type_def.time import Time |
@@ -118,3 +124,86 @@ def prepare(): |
118 | 124 | ) |
119 | 125 |
|
120 | 126 | return cache, core |
| 127 | + |
| 128 | + |
| 129 | +@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand])) |
| 130 | +@pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) |
| 131 | +@pytest.mark.parametrize("inertia", [Size.zero(), Size(1500, Unit.MiB)]) |
| 132 | +@pytest.mark.parametrizex( |
| 133 | + "cache_line_size", |
| 134 | + [CacheLineSize.LINE_4KiB, CacheLineSize.LINE_64KiB], |
| 135 | +) |
| 136 | +def test_alru_dirty_ratio_inertia_no_cleaning_below_threshold(cache_line_size, inertia): |
| 137 | + """ |
| 138 | + title: Test ALRU dirty ratio inertia — no cleaning below threshold |
| 139 | + description: | |
| 140 | + Verify that with ALRU cleaning and a dirty ratio threshold of 90%, the cache does not |
| 141 | + perform cleaning while dirty data stays below the threshold when inertia is specified in MiB. |
| 142 | + Configure long ALRU wake-up, staleness, and activity thresholds to avoid periodic cleaning. |
| 143 | + Generate about 2 GiB of dirty data (~66% of a 3 GiB cache), then idle; Dirty cache lines are not flushed. |
| 144 | + Run with inertia values 0 MiB and 1500 MiB. |
| 145 | + pass_criteria: |
| 146 | + - The cleaning is not triggered when dirty data doesn't exceed the specified threshold. |
| 147 | + """ |
| 148 | + with TestRun.step("Prepare 3GiB cache and 10GiB core, start cache WB, add core, set ALRU"): |
| 149 | + cache_dev = TestRun.disks["cache"] |
| 150 | + core_dev = TestRun.disks["core"] |
| 151 | + |
| 152 | + cache_dev.create_partitions([Size(3, Unit.GiB)]) |
| 153 | + core_dev.create_partitions([Size(10, Unit.GiB)]) |
| 154 | + |
| 155 | + Udev.disable() |
| 156 | + cache = casadm.start_cache( |
| 157 | + cache_dev.partitions[0], |
| 158 | + cache_line_size=cache_line_size, |
| 159 | + force=True, |
| 160 | + cache_mode=CacheMode.WB, |
| 161 | + ) |
| 162 | + core = cache.add_core(core_dev.partitions[0]) |
| 163 | + |
| 164 | + cache.set_seq_cutoff_policy(SeqCutOffPolicy.never) |
| 165 | + cache.set_cleaning_policy(CleaningPolicy.alru) |
| 166 | + |
| 167 | + with TestRun.step( |
| 168 | + f"Set threshold=90%, inertia={inertia}. Staleness=3600s to avoid accidental cleaning, wake_up=1s to ensure the cleaning thread has been woken up" |
| 169 | + ): |
| 170 | + dirty_ratio_threshold = 90 |
| 171 | + casadm.set_param_cleaning_alru( |
| 172 | + cache_id=cache.cache_id, |
| 173 | + wake_up=1, |
| 174 | + flush_max_buffers=100, |
| 175 | + staleness_time=3600, |
| 176 | + activity_threshold=1000, |
| 177 | + dirty_ratio_threshold=dirty_ratio_threshold, |
| 178 | + dirty_ratio_inertia=inertia, |
| 179 | + ) |
| 180 | + |
| 181 | + with TestRun.step("Run write workload to reach ~2GiB (≈66% of 3GiB) dirty data"): |
| 182 | + ( |
| 183 | + Fio() |
| 184 | + .create_command() |
| 185 | + .io_engine(IoEngine.libaio) |
| 186 | + .size(Size(2, Unit.GiB)) |
| 187 | + .block_size(Size(4, Unit.KiB)) |
| 188 | + .target(core) |
| 189 | + .direct() |
| 190 | + .read_write(ReadWrite.randwrite) |
| 191 | + .run() |
| 192 | + ) |
| 193 | + sync() |
| 194 | + |
| 195 | + with TestRun.step("Capture baseline dirty usage after I/O settles"): |
| 196 | + time.sleep(2) |
| 197 | + dirty_before = cache.get_statistics().usage_stats.dirty |
| 198 | + |
| 199 | + with TestRun.step("Idle and verify dirty cache lines do not change and remain below threshold"): |
| 200 | + time.sleep(30) |
| 201 | + dirty_after = cache.get_statistics().usage_stats.dirty |
| 202 | + |
| 203 | + if dirty_after < dirty_after: |
| 204 | + TestRun.fail( |
| 205 | + f"No flushing shall occur when dirty < threshold (dirty before={dirty_before}, dirty after={dirty_after}, threshold={dirty_ratio_threshold}%)" |
| 206 | + ) |
| 207 | + |
| 208 | + with TestRun.step("Stop cache"): |
| 209 | + casadm.stop_cache(cache.cache_id) |
0 commit comments