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 16, 2024
1 parent 8a68039 commit 19f027c
Showing 1 changed file with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions tests/functional/tests/engine/test_partial_hit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#
# 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 WriteMode, 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, 0, 0)
core_device.sync_io(queue, CL // 2, data, IoDir.WRITE, 0, 0)

# 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_4k(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, 0, 0)
core_device.sync_io(queue, CL // 2, data, IoDir.WRITE, 0, 0)

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

data1 = core_volume.read_sync_4k(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, 0, 0)

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_4k(queue, 0, CL)

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


def test_partial_hit_backfill(pyocf_ctx):
"""Reproducing bug when skiping hit clines on backfill,
before adding req-status LOOKUP_HIT_INVALID,
The case is:
|4I|4I|C>3C|I<3I|4I|4I
>|4I|4I|4C|4I|4I|4I<
|4I|4I|C>3C|4I<|4I|4I
"""
cache_device = RamVolume(Size.from_MiB(50))
core_device = RamVolume(Size.from_MiB(50))

cache = Cache.start_on_device(
cache_device, cache_line_size=CacheLineSize.LINE_16KiB
)
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()

# Fill core with data
CL = cache.cache_line_size
data1 = Data(CL)
for i in range(CL // Size._SECTOR_SIZE):
data1.seek(DataSeek.BEGIN, i * Size._SECTOR_SIZE)
data1.write(b"I\x00\x00\x00\x00", 5)
core_device.sync_io(queue, 0, data1, IoDir.WRITE, 0, 0)
core_device.sync_io(queue, CL, data1, IoDir.WRITE, 0, 0)

data2 = Data(CL)
for i in range(CL // Size._SECTOR_SIZE):
data2.seek(DataSeek.BEGIN, i * Size._SECTOR_SIZE)
data2.write(b"C\x00\x00\x00\x00", 5)
core_volume.sync_io(queue, CL * 2, data2, IoDir.WRITE, 0, 0)

core_device.sync_io(queue, CL * 3, data1, IoDir.WRITE, 0, 0)
core_device.sync_io(queue, CL * 4, data1, IoDir.WRITE, 0, 0)
core_device.sync_io(queue, CL * 5, data1, IoDir.WRITE, 0, 0)

assert_device(cache_device, 0, 1)
assert_device(core_device, 0, 6)

# Do the reads
data = core_volume.read_sync_4k(queue, int(2.25 * CL), CL)

for j in range(3):
assert chr(data[j * Size._SECTOR_SIZE] == "C")
assert chr(data[3 * Size._SECTOR_SIZE] == "I")

data = core_volume.read_sync_4k(queue, 0, 6 * CL)

for i in range(6):
for j in range(CL // Size._SECTOR_SIZE):
c = chr(data[i * CL + j * Size._SECTOR_SIZE])
if i != 2:
assert c == "I"
else:
assert c == "C"

data = core_volume.read_sync_4k(queue, int(2.25 * CL), int(1.75 * CL))
for j in range(3):
assert chr(data[j * Size._SECTOR_SIZE]) == "C"
for j in range(4):
c = chr(data[int(0.75 * CL) + j * Size._SECTOR_SIZE])
assert c == "I", f"j={j}, actual: {c}, expected: I"

0 comments on commit 19f027c

Please sign in to comment.