Basic test for multistream seq cutoff
Signed-off-by: Jan Musial <jan.musial@intel.com> Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
parent
93a0d9554c
commit
9a8eb7ed90
142
tests/functional/tests/engine/test_seq_cutoff.py
Normal file
142
tests/functional/tests/engine/test_seq_cutoff.py
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#
|
||||||
|
# Copyright(c) 2020 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
|
#
|
||||||
|
|
||||||
|
from ctypes import c_int
|
||||||
|
from random import shuffle, choice
|
||||||
|
from time import sleep
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
|
from pyocf.types.core import Core
|
||||||
|
from pyocf.types.volume import Volume
|
||||||
|
from pyocf.types.data import Data
|
||||||
|
from pyocf.types.io import IoDir
|
||||||
|
from pyocf.utils import Size
|
||||||
|
from pyocf.types.shared import OcfCompletion, SeqCutOffPolicy
|
||||||
|
|
||||||
|
|
||||||
|
class Stream:
|
||||||
|
def __init__(self, last, length, direction):
|
||||||
|
self.last = last
|
||||||
|
self.length = length
|
||||||
|
self.direction = direction
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.last} {self.length} {self.direction}"
|
||||||
|
|
||||||
|
|
||||||
|
def _io(core, addr, size, direction, context):
|
||||||
|
comp = OcfCompletion([("error", c_int)], context=context)
|
||||||
|
data = Data(size)
|
||||||
|
|
||||||
|
io = core.new_io(core.cache.get_default_queue(), addr, size, direction, 0, 0)
|
||||||
|
io.set_data(data)
|
||||||
|
io.callback = comp.callback
|
||||||
|
io.submit()
|
||||||
|
|
||||||
|
return comp
|
||||||
|
|
||||||
|
|
||||||
|
def io_to_streams(core, streams, io_size):
|
||||||
|
completions = []
|
||||||
|
for stream in streams:
|
||||||
|
completions.append(
|
||||||
|
_io(core, stream.last, io_size, stream.direction, context=(io_size, stream))
|
||||||
|
)
|
||||||
|
|
||||||
|
for c in completions:
|
||||||
|
c.wait()
|
||||||
|
io_size, stream = c.context
|
||||||
|
|
||||||
|
stream.last += io_size
|
||||||
|
stream.length += io_size
|
||||||
|
|
||||||
|
assert not c.results["error"], "No IO should fail"
|
||||||
|
|
||||||
|
|
||||||
|
def test_seq_cutoff_max_streams(pyocf_ctx):
|
||||||
|
"""
|
||||||
|
Test number of sequential streams tracked by OCF.
|
||||||
|
|
||||||
|
MAX_STREAMS is the maximal amount of streams which OCF is able to track.
|
||||||
|
|
||||||
|
1. Issue MAX_STREAMS requests (write or reads) to cache, 1 sector shorter than
|
||||||
|
seq cutoff threshold
|
||||||
|
2. Issue MAX_STREAMS-1 requests continuing the streams from 1. to surpass the threshold and
|
||||||
|
check if cutoff was triggered (requests used PT engine)
|
||||||
|
3. Issue single request to stream not used in 1. or 2. and check if it's been handled by cache
|
||||||
|
4. Issue single request to stream least recently used in 1. and 2. and check if it's been
|
||||||
|
handled by cache. It should no longer be tracked by OCF, because of request in step 3. which
|
||||||
|
overflowed the OCF handling structure)
|
||||||
|
"""
|
||||||
|
MAX_STREAMS = 256
|
||||||
|
TEST_STREAMS = MAX_STREAMS + 1 # Number of streams used by test - one more than OCF can track
|
||||||
|
core_size = Size.from_MiB(200)
|
||||||
|
threshold = Size.from_KiB(4)
|
||||||
|
|
||||||
|
streams = [
|
||||||
|
Stream(
|
||||||
|
last=Size((stream_no * int(core_size) // TEST_STREAMS), sector_aligned=True),
|
||||||
|
length=Size(0),
|
||||||
|
direction=choice(list(IoDir)),
|
||||||
|
)
|
||||||
|
for stream_no in range(TEST_STREAMS)
|
||||||
|
] # Generate MAX_STREAMS + 1 non-overlapping streams
|
||||||
|
|
||||||
|
# Remove one stream - this is the one we are going to use to overflow OCF tracking structure
|
||||||
|
# in step 3
|
||||||
|
non_active_stream = choice(streams)
|
||||||
|
streams.remove(non_active_stream)
|
||||||
|
|
||||||
|
cache = Cache.start_on_device(Volume(Size.from_MiB(200)), cache_mode=CacheMode.WT)
|
||||||
|
core = Core.using_device(Volume(core_size))
|
||||||
|
|
||||||
|
cache.add_core(core)
|
||||||
|
|
||||||
|
cache.set_seq_cut_off_policy(SeqCutOffPolicy.ALWAYS)
|
||||||
|
cache.set_seq_cut_off_threshold(threshold)
|
||||||
|
|
||||||
|
# STEP 1
|
||||||
|
shuffle(streams)
|
||||||
|
io_size = threshold - Size.from_sector(1)
|
||||||
|
io_to_streams(core, streams, io_size)
|
||||||
|
|
||||||
|
stats = cache.get_stats()
|
||||||
|
assert (
|
||||||
|
stats["req"]["serviced"]["value"] == stats["req"]["total"]["value"] == len(streams)
|
||||||
|
), "All request should be serviced - no cutoff"
|
||||||
|
|
||||||
|
old_serviced = len(streams)
|
||||||
|
|
||||||
|
# STEP 2
|
||||||
|
lru_stream = streams[0]
|
||||||
|
streams.remove(lru_stream)
|
||||||
|
|
||||||
|
shuffle(streams)
|
||||||
|
io_to_streams(core, streams, Size.from_sector(1))
|
||||||
|
|
||||||
|
stats = cache.get_stats()
|
||||||
|
assert (
|
||||||
|
stats["req"]["serviced"]["value"] == old_serviced
|
||||||
|
), "Serviced requests stat should not increase - cutoff engaged for all"
|
||||||
|
assert stats["req"]["wr_pt"]["value"] + stats["req"]["rd_pt"]["value"] == len(
|
||||||
|
streams
|
||||||
|
), "All streams should be handled in PT - cutoff engaged for all streams"
|
||||||
|
|
||||||
|
# STEP 3
|
||||||
|
io_to_streams(core, [non_active_stream], Size.from_sector(1))
|
||||||
|
|
||||||
|
stats = cache.get_stats()
|
||||||
|
assert (
|
||||||
|
stats["req"]["serviced"]["value"] == old_serviced + 1
|
||||||
|
), "This request should be serviced by cache - no cutoff for inactive stream"
|
||||||
|
|
||||||
|
# STEP 4
|
||||||
|
io_to_streams(core, [lru_stream], Size.from_sector(1))
|
||||||
|
|
||||||
|
stats = cache.get_stats()
|
||||||
|
assert (
|
||||||
|
stats["req"]["serviced"]["value"] == old_serviced + 2
|
||||||
|
), "This request should be serviced by cache - lru_stream should be no longer tracked"
|
Loading…
Reference in New Issue
Block a user