Skip to content

Commit

Permalink
pyocf: Tests for partial hits
Browse files Browse the repository at this point in the history
Signed-off-by: Sara Merzel <sara.merzel@huawei.com>
Signed-off-by: Roel Apfelbaum <roel.apfelbaum@huawei.com>
Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
  • Loading branch information
SaraMerzel authored and mmichal10 committed Sep 17, 2024
1 parent 97477d4 commit ee7b835
Showing 1 changed file with 181 additions and 0 deletions.
181 changes: 181 additions & 0 deletions tests/functional/tests/engine/test_partial_hit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#
# Copyright(c) 2024 Huawei Technologies
# SPDX-License-Identifier: BSD-3-Clause
#

import pytest


from pyocf.types.data import Data, DataSeek
from pyocf.types.cache import Cache, CacheMode
from pyocf.types.core import Core
from pyocf.types.shared import CacheLineSize
from pyocf.types.volume import RamVolume, Volume
from pyocf.types.volume_core import CoreVolume
from pyocf.utils import Size
from pyocf.types.io import IoDir


def assert_device(device: Volume, reads, writes):
stats = device.get_stats()
if reads is not None:
assert (
stats[IoDir.READ] == reads
), f"actual reads: {stats[IoDir.READ]}, expected reads: {reads}"
if writes is not None:
assert (
stats[IoDir.WRITE] == writes
), f"actual writes: {stats[IoDir.WRITE]}, expected writes: {writes}"


@pytest.mark.parametrize("cacheline_size", CacheLineSize)
@pytest.mark.parametrize("cache_mode", CacheMode)
def test_partial_hit_write(pyocf_ctx, cacheline_size, cache_mode):
cache_device = RamVolume(Size.from_MiB(50))
core_device = RamVolume(Size.from_MiB(50))

cache = Cache.start_on_device(
cache_device, cache_line_size=cacheline_size, cache_mode=cache_mode
)
core = Core.using_device(core_device)

queue = cache.get_default_queue()

cache.add_core(core)
core_volume = CoreVolume(core)
core_volume.open()

# Fill core with data
CL = cache.cache_line_size
data = Data(CL // 2)
data.seek(DataSeek.BEGIN, 0)
data.write(b"A\x00\x00\x00\x00", 5)
core_device.sync_io(queue, 0, data, IoDir.WRITE)
core_device.sync_io(queue, CL // 2, data, IoDir.WRITE)

# Write 0.5 CL
data.seek(DataSeek.BEGIN, 0)
data.write(b"B\x00\x00\x00\x00", 5)
core_volume.sync_io(queue, 0, data, IoDir.WRITE)

data1 = core_volume.read_sync(queue, 0, CL)

assert chr(data1[0]) == "B"
assert chr(data1[CL // 2]) == "A"


@pytest.mark.parametrize("cacheline_size", CacheLineSize)
@pytest.mark.parametrize("cache_mode", CacheMode)
def test_partial_hit_read(pyocf_ctx, cacheline_size, cache_mode):
cache_device = RamVolume(Size.from_MiB(50))
core_device = RamVolume(Size.from_MiB(50))

cache = Cache.start_on_device(
cache_device, cache_line_size=cacheline_size, cache_mode=cache_mode
)
core = Core.using_device(core_device)

queue = cache.get_default_queue()

cache.add_core(core)
core_volume = CoreVolume(core)
core_volume.open()

# Fill core with data
CL = cache.cache_line_size
data = Data(CL // 2)
data.seek(DataSeek.BEGIN, 0)
data.write(b"A\x00\x00\x00\x00", 5)
core_device.sync_io(queue, 0, data, IoDir.WRITE)
core_device.sync_io(queue, CL // 2, data, IoDir.WRITE)

data_read = Data(CL // 2)
core_volume.sync_io(queue, 0, data_read, IoDir.READ)

data1 = core_volume.read_sync(queue, 0, CL)

assert chr(data1[0]) == "A"
assert chr(data1[CL // 2]) == "A"


@pytest.mark.parametrize("cacheline_size", CacheLineSize)
@pytest.mark.parametrize("cache_mode", [CacheMode.WB, CacheMode.WO])
def test_read_partial_hit_partial_invalidate_dirty(pyocf_ctx, cacheline_size, cache_mode):
cache_device = RamVolume(Size.from_MiB(50))
core_device = RamVolume(Size.from_MiB(50))

cache = Cache.start_on_device(
cache_device, cache_line_size=cacheline_size, cache_mode=cache_mode
)
core = Core.using_device(core_device)

queue = cache.get_default_queue()

cache.add_core(core)
core_volume = CoreVolume(core)
core_volume.open()

CL = cache.cache_line_size
data = Data(CL)
data.seek(DataSeek.BEGIN, 0)
data.write(b"A" * CL, CL)
core_volume.sync_io(queue, 0, data, IoDir.WRITE)

data.seek(DataSeek.BEGIN, 0)
data.write(b"B" * 512, 512)
core_volume.sync_io(queue, 512, data, IoDir.WRITE)

data1 = core_volume.read_sync(queue, 0, CL)

assert chr(data1[0]) == "A"
assert chr(data1[512]) == "B"
assert chr(data1[1023]) == "B"
assert chr(data1[1024]) == "A"


@pytest.mark.parametrize("cacheline_size", CacheLineSize)
def test_partial_hit_backfill(pyocf_ctx, cacheline_size):
cache_device = RamVolume(Size.from_MiB(50))
core_device = RamVolume(Size.from_MiB(50))

cache = Cache.start_on_device(cache_device, cache_line_size=cacheline_size)
core = Core.using_device(core_device)

queue = cache.get_default_queue()

cache.add_core(core)
core_volume = CoreVolume(core)
core_volume.open()

cache_device.reset_stats()
core_device.reset_stats()

CL = cache.cache_line_size
# Populate core backend volume
invalid_sectors = list(range(0, 6 * CL, Size._SECTOR_SIZE))
prefill_data = Data(Size._SECTOR_SIZE)
prefill_data.write(b"I\x00\x00\x00\x00", 5)
for addr in invalid_sectors:
core_device.sync_io(queue, addr, prefill_data, IoDir.WRITE)

# Write data to the core
core_data_addr = 2 * CL + CL // 2
core_data_size = CL
valid_sectors = list(range(core_data_addr, core_data_addr + core_data_size, Size._SECTOR_SIZE))
vaild_data = Data(CL)
for addr in range(0, CL, Size._SECTOR_SIZE):
vaild_data.seek(DataSeek.BEGIN, addr)
vaild_data.write(b"C\x00\x00\x00\x00", 5)
core_volume.sync_io(queue, core_data_addr, vaild_data, IoDir.WRITE)

invalid_sectors = [s for s in invalid_sectors if s not in valid_sectors]

stats = core_volume.get_stats()
stats[IoDir.WRITE] == 1

read_data = core_volume.read_sync(queue, 0, 6 * CL)
for addr in invalid_sectors:
assert chr(read_data[addr]) == "I", f"data offset {addr}"

for addr in valid_sectors:
assert chr(read_data[addr]) == "C", f"data offset {addr}"

0 comments on commit ee7b835

Please sign in to comment.