From e0ef322d7b51f8440ff54da118531d0aa18fed16 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 16 Oct 2026 16:45:31 +0200 Subject: [PATCH 1/2] pyocf: Settle cache before checking stats Request and block stats are updated after the IO is submitted, and read miss backfill updates metadata after the IO is completed, so stats may not be up to date yet when the IO completion arrives. Queue settle is not enough to cover backfill of prefetch requests, as it doesn't wait for requests pushed to the queue but not yet processed. Use cache settle instead, which waits for all the requests to be finished. Signed-off-by: Robert Baldyga --- tests/functional/tests/engine/test_d2c.py | 3 +++ tests/functional/tests/engine/test_pp.py | 1 + .../functional/tests/engine/test_prefetch_readahead.py | 10 +++++----- tests/functional/tests/eviction/test_eviction.py | 4 ++++ tests/functional/tests/security/test_secure_erase.py | 3 +++ 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/functional/tests/engine/test_d2c.py b/tests/functional/tests/engine/test_d2c.py index f1a0fde5f..5188e3360 100644 --- a/tests/functional/tests/engine/test_d2c.py +++ b/tests/functional/tests/engine/test_d2c.py @@ -1,5 +1,6 @@ # # Copyright(c) 2024 Huawei Technologies +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -68,6 +69,7 @@ def test_d2c_io(pyocf_ctx): c.results["error"], ) + cache.settle() assert cache.get_stats()["req"]["wr_pt"]["value"] == 2 read_io = vol.new_io(queue, 0, CORE_SIZE, IoDir.READ, 0, 0) @@ -76,6 +78,7 @@ def test_d2c_io(pyocf_ctx): read_completion = Sync(read_io).submit() assert int(read_completion.results["err"]) == 0 + cache.settle() assert cache.get_stats()["req"]["rd_full_misses"]["value"] == 1 cache.stop() diff --git a/tests/functional/tests/engine/test_pp.py b/tests/functional/tests/engine/test_pp.py index a01d0de7d..98061e22a 100644 --- a/tests/functional/tests/engine/test_pp.py +++ b/tests/functional/tests/engine/test_pp.py @@ -230,6 +230,7 @@ def test_partial_hit_promotion(pyocf_ctx): # Step 2 r = Rio().readwrite(ReadWrite.READ).bs(Size(512)).size(Size(512)).target(vol).run([queue]) + cache.settle() stats = cache.get_stats() cache_lines = stats["conf"]["size"] assert stats["usage"]["occupancy"]["value"] == 1 diff --git a/tests/functional/tests/engine/test_prefetch_readahead.py b/tests/functional/tests/engine/test_prefetch_readahead.py index 82b1e9daf..1de6d4495 100644 --- a/tests/functional/tests/engine/test_prefetch_readahead.py +++ b/tests/functional/tests/engine/test_prefetch_readahead.py @@ -102,7 +102,7 @@ def test_prefetch_readahead_threshold(pyocf_ctx, threshold, req_size, cls): rio = (Rio().target(vol).bs(req_size).size(below_size) .readwrite(ReadWrite.READ)) rio.run([queue]) - queue.settle() + cache.settle() assert get_prefetch_count(cache) == 0, \ "No prefetch should trigger below threshold" @@ -113,7 +113,7 @@ def test_prefetch_readahead_threshold(pyocf_ctx, threshold, req_size, cls): rio = (Rio().target(vol).bs(req_size).size(req_size).offset(below_size) .readwrite(ReadWrite.READ)) rio.run([queue]) - queue.settle() + cache.settle() assert get_prefetch_count(cache) == 1, \ "Exactly one prefetch request should be generated" @@ -143,7 +143,7 @@ def test_prefetch_readahead_random(pyocf_ctx, cls): rio = (Rio().target(vol).bs(Size.from_KiB(4)).size(Size.from_MiB(20)) .readwrite(ReadWrite.RANDREAD)) rio.run([queue]) - queue.settle() + cache.settle() assert get_prefetch_count(cache) == 0, \ "No prefetch should trigger for random reads" @@ -176,7 +176,7 @@ def test_prefetch_readahead_read_insert(pyocf_ctx, cache_mode, cls): rio = (Rio().target(vol).bs(Size.from_KiB(4)).size(Size.from_MiB(1)) .readwrite(ReadWrite.READ)) rio.run([queue]) - queue.settle() + cache.settle() assert get_prefetch_count(cache) > 0, \ f"Prefetch should trigger in {cache_mode.name} mode" @@ -208,7 +208,7 @@ def test_prefetch_readahead_no_read_insert(pyocf_ctx, cache_mode, cls): rio = (Rio().target(vol).bs(Size.from_KiB(4)).size(Size.from_MiB(1)) .readwrite(ReadWrite.READ)) rio.run([queue]) - queue.settle() + cache.settle() assert get_prefetch_count(cache) == 0, \ f"No prefetch should trigger in {cache_mode.name} mode" diff --git a/tests/functional/tests/eviction/test_eviction.py b/tests/functional/tests/eviction/test_eviction.py index 8b61e20ff..7635ffdd1 100644 --- a/tests/functional/tests/eviction/test_eviction.py +++ b/tests/functional/tests/eviction/test_eviction.py @@ -74,6 +74,7 @@ def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLin test_data = Data(valid_io_size) send_io(vol, test_data) + cache.settle() stats = core.cache.get_stats() first_block_sts = stats["block"] first_usage_sts = stats["usage"] @@ -94,6 +95,7 @@ def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLin if mode is not CacheMode.WT: # Flush first write cache.flush() + cache.settle() stats = core.cache.get_stats() second_block_sts = stats["block"] second_usage_sts = stats["usage"] @@ -146,6 +148,7 @@ def test_eviction_priority_1(pyocf_ctx, cls: CacheLineSize, cache_mode: CacheMod ) def get_ioclass_occupancy(cache, ioclass_id): + cache.settle() return cache.get_ioclass_stats(ioclass_id)["usage"]["occupancy"]["value"] cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) @@ -214,6 +217,7 @@ def test_eviction_priority_2(pyocf_ctx, cls: CacheLineSize, cache_mode: CacheMod ) def get_ioclass_occupancy(cache, ioclass_id): + cache.settle() return cache.get_ioclass_stats(ioclass_id)["usage"]["occupancy"]["value"] cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) diff --git a/tests/functional/tests/security/test_secure_erase.py b/tests/functional/tests/security/test_secure_erase.py index 8624290a7..576bef647 100644 --- a/tests/functional/tests/security/test_secure_erase.py +++ b/tests/functional/tests/security/test_secure_erase.py @@ -1,6 +1,7 @@ # # Copyright(c) 2019-2022 Intel Corporation # Copyright(c) 2024 Huawei Technologies +# Copyright(c) 2026 Unvertical # SPDX-License-Identifier: BSD-3-Clause # @@ -114,6 +115,7 @@ def test_secure_erase_simple_io_read_misses(cache_mode): Sync(io).submit() vol.close() + cache.settle() stats = cache.get_stats() ctx.exit() @@ -171,6 +173,7 @@ def test_secure_erase_simple_io_cleaning(): Sync(io).submit() vol.close() + cache.settle() stats = cache.get_stats() ctx.exit() From fafff463d20503b3703fbbde30aab2867f2705b6 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 16 Oct 2026 18:27:12 +0200 Subject: [PATCH 2/2] github-actions: Use xdist to speed up CI tests Signed-off-by: Robert Baldyga --- .github/workflows/tests-master.yml | 4 ++-- .github/workflows/tests-pr.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests-master.yml b/.github/workflows/tests-master.yml index 4cd56a67c..a71722bb6 100644 --- a/.github/workflows/tests-master.yml +++ b/.github/workflows/tests-master.yml @@ -17,8 +17,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest + pip install pytest pytest-xdist - name: 'Build OCF library' run: cd tests/functional; make -j - name: 'Execute tests' - run: cd tests/functional; python3 -m pytest + run: cd tests/functional; python3 -m pytest -n auto diff --git a/.github/workflows/tests-pr.yml b/.github/workflows/tests-pr.yml index 95f1a492b..4d9350b50 100644 --- a/.github/workflows/tests-pr.yml +++ b/.github/workflows/tests-pr.yml @@ -14,8 +14,8 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest + pip install pytest pytest-xdist - name: 'Build OCF library' run: cd tests/functional; make -j - name: 'Execute tests' - run: cd tests/functional; python3 -m pytest + run: cd tests/functional; python3 -m pytest -n auto