Skip to content

Commit

Permalink
fio: Adding fio engine
Browse files Browse the repository at this point in the history
This first commit is adding a first cmdline engine_module to execute a
single fio command line.

This commit is not functional yet but set the base of the logic to parse
the engine.

Signed-off-by: Erwan Velu <[email protected]>
  • Loading branch information
ErwanAliasr1 committed Oct 30, 2024
1 parent bb49d56 commit 725a25e
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 0 deletions.
14 changes: 14 additions & 0 deletions configs/fio.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This configuration will :
# - load all cores with a matrixprod test during 15 sec.
[global]
runtime=15
monitor=all

[randread_cmdline]
engine=fio
engine_module=cmdline
engine_module_parameter_base="--filename=/dev/sdp --direct=1 --rw=randread --bs=4k --ioengine=libaio --iodepth=256 --numjobs=4 --time_based --group_reporting --readonly"
hosting_cpu_cores=all
hosting_cpu_cores_scaling=none
stressor_range=auto

25 changes: 25 additions & 0 deletions hwbench/bench/test_fio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from . import test_benchmarks_common as tbc


class TestFio(tbc.TestCommon):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_mocked_hardware(
cpucores="./tests/parsing/cpu_cores/v2321",
cpuinfo="./tests/parsing/cpu_info/v2321",
numa="./tests/parsing/numa/8domainsllc",
)
self.load_benches("./config/fio.conf")
self.parse_jobs_config()
self.QUADRANT0 = list(range(0, 16)) + list(range(64, 80))
self.QUADRANT1 = list(range(16, 32)) + list(range(80, 96))
self.ALL = list(range(0, 128))

def test_fio(self):
"""Check fio syntax."""
assert self.benches.count_benchmarks() == 1
assert self.benches.count_jobs() == 1
assert self.benches.runtime() == 15
self.assertIsNone(self.benches.benchs[0].validate_parameters())
bench = self.get_bench_parameters(0)
assert bench.get_name() == "randread_cmdline"
14 changes: 14 additions & 0 deletions hwbench/config/fio.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This configuration will :
# - load all cores with a matrixprod test during 15 sec.
[global]
runtime=15
monitor=all

[randread_cmdline]
engine=fio
engine_module=cmdline
engine_module_parameter_base="--filename=/dev/sdp --direct=1 --rw=randread --bs=4k --ioengine=libaio --iodepth=256 --numjobs=4 --time_based --group_reporting --readonly"
hosting_cpu_cores=all
hosting_cpu_cores_scaling=none
stressor_range=auto

27 changes: 27 additions & 0 deletions hwbench/config/test_parse_fio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pathlib

Check failure on line 1 in hwbench/config/test_parse_fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.9)

Ruff (F401)

hwbench/config/test_parse_fio.py:1:8: F401 `pathlib` imported but unused

Check failure on line 1 in hwbench/config/test_parse_fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.10)

Ruff (F401)

hwbench/config/test_parse_fio.py:1:8: F401 `pathlib` imported but unused

Check failure on line 1 in hwbench/config/test_parse_fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.11)

Ruff (F401)

hwbench/config/test_parse_fio.py:1:8: F401 `pathlib` imported but unused

Check failure on line 1 in hwbench/config/test_parse_fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.12)

Ruff (F401)

hwbench/config/test_parse_fio.py:1:8: F401 `pathlib` imported but unused
from unittest.mock import patch
from ..environment.mock import MockHardware
from ..bench import test_benchmarks_common as tbc


class TestParseConfig(tbc.TestCommon):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.hw = MockHardware()
self.load_benches("./config/fio.conf")

def test_sections_name(self):
"""Check if sections names are properly detected."""
sections = self.get_jobs_config().get_sections()
assert sections == [
"randread_cmdline",
]

def test_keywords(self):
"""Check if all keywords are valid."""
try:
with patch("hwbench.utils.helpers.is_binary_available") as iba:
iba.return_value = True
self.get_jobs_config().validate_sections()
except Exception as exc:
assert False, f"'validate_sections' detected a syntax error {exc}"
105 changes: 105 additions & 0 deletions hwbench/engines/fio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from ..bench.parameters import BenchmarkParameters
from ..bench.engine import EngineBase, EngineModuleBase
from ..bench.benchmark import ExternalBench


class EngineModuleCmdline(EngineModuleBase):
"""This class implements the EngineModuleBase for fio"""

def __init__(self, engine: EngineBase, engine_module_name: str, fake_stdout=None):
super().__init__(engine, engine_module_name)
self.engine_module_name = engine_module_name
self.load_module_parameter(fake_stdout)

def load_module_parameter(self, fake_stdout=None):
# if needed add module parameters to your module
self.add_module_parameter("cmdline")

def validate_module_parameters(self, p: BenchmarkParameters):
msg = super().validate_module_parameters(p)
Fio(self, p).parse_parameters()
return msg

def run_cmd(self, p: BenchmarkParameters):
return Fio(self, p).run_cmd()

def run(self, p: BenchmarkParameters):
return Fio(self, p).run()

def fully_skipped_job(self, p) -> bool:
return Fio(self, p).fully_skipped_job()


class Engine(EngineBase):
"""The main fio class."""

def __init__(self, fake_stdout=None):
super().__init__("fio", "fio")
self.add_module(EngineModuleCmdline(self, "cmdline", fake_stdout))

def run_cmd_version(self) -> list[str]:
return [
self.get_binary(),
"--version",
]

def run_cmd(self) -> list[str]:
return []

def parse_version(self, stdout: bytes, _stderr: bytes) -> bytes:
print(stdout)
self.version = stdout.split(b"-")[1]
return self.version

def version_major(self) -> int:
if self.version:
return int(self.version.split(b".")[0])
return 0

def version_minor(self) -> int:
if self.version:
return int(self.version.split(b".")[1])
return 0

def parse_cmd(self, stdout: bytes, stderr: bytes):
return {}


class Fio(ExternalBench):
"""The Fio stressor."""

def __init__(
self, engine_module: EngineModuleBase, parameters: BenchmarkParameters
):
ExternalBench.__init__(self, engine_module, parameters)
self.parameters = parameters
self.engine_module = engine_module
self.parse_parameters()

def parse_parameters(self):
runtime = self.parameters.runtime

Check failure on line 80 in hwbench/engines/fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.9)

Ruff (F841)

hwbench/engines/fio.py:80:9: F841 Local variable `runtime` is assigned to but never used

Check failure on line 80 in hwbench/engines/fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.10)

Ruff (F841)

hwbench/engines/fio.py:80:9: F841 Local variable `runtime` is assigned to but never used

Check failure on line 80 in hwbench/engines/fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.11)

Ruff (F841)

hwbench/engines/fio.py:80:9: F841 Local variable `runtime` is assigned to but never used

Check failure on line 80 in hwbench/engines/fio.py

View workflow job for this annotation

GitHub Actions / Check if every commit in the PR works (3.12)

Ruff (F841)

hwbench/engines/fio.py:80:9: F841 Local variable `runtime` is assigned to but never used

def run_cmd(self) -> list[str]:
# Let's build the command line to run the tool
args = [
self.engine_module.get_engine().get_binary(),
str(self.parameters.get_runtime()),
]

return self.get_taskset(args)

def parse_cmd(self, stdout: bytes, stderr: bytes):
# Add the score to the global output
return self.parameters.get_result_format() | {
"bogo ops/s": self.parameters.get_runtime()
}

@property
def name(self) -> str:
return self.engine_module.get_engine().get_name()

def run_cmd_version(self) -> list[str]:
return self.engine_module.get_engine().run_cmd_version()

def parse_version(self, stdout: bytes, _stderr: bytes) -> bytes:
return self.engine_module.get_engine().parse_version(stdout, _stderr)
26 changes: 26 additions & 0 deletions hwbench/engines/test_parse_fio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pathlib
import unittest
from unittest.mock import patch

from .fio import Engine as Fio


def mock_engine() -> Fio:
with patch("hwbench.utils.helpers.is_binary_available") as iba:
iba.return_value = True
return Fio()


class TestParse(unittest.TestCase):
def test_engine_parsing_version(self):
test_dir = pathlib.Path("./tests/parsing/fio")
for d in test_dir.iterdir():
test_target = mock_engine()
if not d.is_dir():
continue
ver_stdout = (d / "version-stdout").read_bytes()
ver_stderr = (d / "version-stderr").read_bytes()
version = test_target.parse_version(ver_stdout, ver_stderr)
assert version == (d / "version").read_bytes().strip()
assert test_target.version_major() == 3
assert test_target.version_minor() == 19
1 change: 1 addition & 0 deletions hwbench/tests/parsing/fio/v319/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.19
Empty file.
1 change: 1 addition & 0 deletions hwbench/tests/parsing/fio/v319/version-stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fio-3.19

0 comments on commit 725a25e

Please sign in to comment.