Skip to content

Commit fb908b8

Browse files
test: ALRU: clean below (threshold - inertia)
Co-authored-by: aider (gpt-5) <aider@aider.chat> Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
1 parent 70d6ca5 commit fb908b8

File tree

1 file changed

+119
-0
lines changed
  • test/functional/tests/lazy_writes/cleaning_policy

1 file changed

+119
-0
lines changed

test/functional/tests/lazy_writes/cleaning_policy/test_alru.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,122 @@ def test_alru_dirty_ratio_inertia_no_cleaning_if_dirty_below_threshold(cache_lin
211211
f"No flushing shall occur when dirty < threshold (dirty before={dirty_before}, "
212212
f"dirty after={dirty_after}, threshold={dirty_ratio_threshold}%)"
213213
)
214+
215+
216+
@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.optane, DiskType.nand]))
217+
@pytest.mark.require_disk("core", DiskTypeLowerThan("cache"))
218+
@pytest.mark.parametrize("inertia", [Size.zero(), Size(600, Unit.MiB)])
219+
def test_alru_dirty_threshold_cleans_until_threshold_minus_inertia(inertia):
220+
"""
221+
title: Test ALRU threshold cleaning – start > 50%, stop at (threshold - inertia)
222+
description: |
223+
Verify that with ALRU cleaning configured with 50% dirty threshold and specified inertia in MiB,
224+
cleaning starts when dirty exceeds the threshold and stops after reaching (threshold - inertia).
225+
pass_criteria:
226+
- Cleaning starts once dirty exceeds 50%.
227+
- Dirty decreases over time after stopping I/O.
228+
- Cleaning stops at or below (threshold - inertia).
229+
- If dirty does not decrease for 20 consecutive checks, fail the test.
230+
"""
231+
232+
target_dirty_ratio_threshold = 50
233+
# 3 GiB cache -> 50% = 1536 MiB; inertia is in MiB
234+
threshold_size = Size(1536, Unit.MiB)
235+
target_cleaning_threshold = threshold_size - inertia
236+
237+
with TestRun.step("Prepare 3GiB cache and 10GiB core, disable udev, start cache WB, add core"):
238+
cache_dev = TestRun.disks["cache"]
239+
core_dev = TestRun.disks["core"]
240+
241+
cache_dev.create_partitions([Size(3, Unit.GiB)])
242+
core_dev.create_partitions([Size(10, Unit.GiB)])
243+
244+
with TestRun.step("Disable udev"):
245+
Udev.disable()
246+
247+
with TestRun.step("Start cache and add core"):
248+
cache = casadm.start_cache(cache_dev.partitions[0], force=True, cache_mode=CacheMode.WB)
249+
core = cache.add_core(core_dev.partitions[0])
250+
251+
with TestRun.step("Set ALRU and disable sequential cutoff"):
252+
cache.set_seq_cutoff_policy(SeqCutOffPolicy.never)
253+
cache.set_cleaning_policy(CleaningPolicy.alru)
254+
255+
with TestRun.step(
256+
"Configure ALRU: dirty threshold=50%, inertia={inertia}, default wakeup, max staleness_time"
257+
):
258+
cache.set_params_alru(
259+
FlushParametersAlru(
260+
staleness_time=Time(seconds=3600),
261+
dirty_ratio_threshold=target_dirty_ratio_threshold,
262+
dirty_ratio_inertia=inertia,
263+
)
264+
)
265+
266+
with TestRun.step("Start background fio (4 GiB randwrite)"):
267+
(
268+
Fio()
269+
.create_command()
270+
.io_engine(IoEngine.libaio)
271+
.size(Size(4, Unit.GiB))
272+
.block_size(Size(4, Unit.KiB))
273+
.target(core)
274+
.direct()
275+
.read_write(ReadWrite.randwrite)
276+
.run_in_background()
277+
)
278+
279+
with TestRun.step("Wait until cache dirty >= 90%, then stop workload"):
280+
start_ts = time.time()
281+
while True:
282+
time.sleep(2)
283+
dirty_pct = cache.get_statistics(percentage_val=True).usage_stats.dirty
284+
if dirty_pct >= 90:
285+
break
286+
if time.time() - start_ts > 5 * 60:
287+
TestRun.LOGGER.exception(
288+
f"Cache dirty level did not reach 90% within 5 minutes "
289+
f"(current dirty={dirty_pct}%). Aborting test."
290+
)
291+
TestRun.fail(
292+
"TODO: For some reason the TestRun.LOGGER.exception doesn't interrupt the test, "
293+
"but only modifies the test status and continiues the execution. Until fixed, use TestRun.fail"
294+
)
295+
296+
with TestRun.step("Make sure that the all IO has been completed"):
297+
kill_all_io()
298+
sync()
299+
300+
with TestRun.step(
301+
"Observe cleaning: ensure monotonic decrease and stop at (threshold - inertia)"
302+
):
303+
# Initial dirty after IO stop
304+
last_dirty = cache.get_statistics().usage_stats.dirty
305+
306+
not_decreasing = 0
307+
while last_dirty > target_cleaning_threshold:
308+
time.sleep(5)
309+
dirty_now = cache.get_statistics().usage_stats.dirty
310+
311+
if dirty_now < last_dirty:
312+
not_decreasing = 0
313+
else:
314+
not_decreasing += 1
315+
if not_decreasing >= 20:
316+
TestRun.fail(
317+
f"Exception: Dirty amount not decreasing for 20 consecutive checks "
318+
f"(stuck at {dirty_now}, target stop {target_cleaning_threshold})."
319+
)
320+
321+
last_dirty = dirty_now
322+
323+
with TestRun.step(
324+
"Once the dirty cache lines counter reached (threshold - inertia) level, "
325+
"no further cleaning should take place"
326+
):
327+
time.sleep(30)
328+
if last_dirty > target_cleaning_threshold:
329+
TestRun.fail(
330+
f"Cleaning did not stop at expected level "
331+
f"(dirty={last_dirty}, expected <= {target_cleaning_threshold})."
332+
)

0 commit comments

Comments
 (0)