Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ uv.lock
.coverage
pytest-coverage.xml
imgtests.egg-info

# External
vdbench.tar.gz
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@
path = layers/meta-cloud-services
url = https://github.com/ni/meta-cloud-services
branch = nilrt/master/next
[submodule "layers/meta-openjdk-temurin"]
path = layers/meta-openjdk-temurin
url = https://github.com/lucimber/meta-openjdk-temurin.git
branch = scarthgap
1 change: 1 addition & 0 deletions conf/added_packages.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ IMAGE_INSTALL:append = " \
fwts \
iperf3 \
lvm2 \
openjdk-25-jre \
perf \
phoronix-test-suite \
ptest-runner \
Expand Down
1 change: 1 addition & 0 deletions conf/packages.conf
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,5 @@ IMAGE_INSTALL:append = " \
zip \
zlib \
zstd \
vdbench \
"
7 changes: 7 additions & 0 deletions layers/meta-image-tests/recipes-vdbench/vdbench/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
To make the recipe work, you will need to attach an archive (with name vdbench.tar.gz) containing the following files:

- binary tool files;

- linux x64 file and config script;

- recipe license.
19 changes: 19 additions & 0 deletions layers/meta-image-tests/recipes-vdbench/vdbench/vdbench.bb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
SUMMARY = "Vdbench"
# License must be withing the archive and md5sum should be updated.
LICENSE = "GPL-2.0-only"
Comment thread
Artanias marked this conversation as resolved.
LIC_FILES_CHKSUM = "file://LICENSE;md5=8a1984b6adf89397460816c68c05c616"

FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI += "file://vdbench.tar.gz"

S = "${WORKDIR}/vdbench"

RDEPENDS:${PN} += "bash"

do_install() {
install -d ${D}${sbindir}/vdbench

cp -r ${S}/* ${D}${sbindir}/vdbench/
}

FILES:${PN} = "${sbindir}/vdbench"
Empty file.
1 change: 1 addition & 0 deletions layers/meta-openjdk-temurin
Submodule meta-openjdk-temurin added at 5804d9
3 changes: 3 additions & 0 deletions scripts/add-layers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ LAYERS=(
"meta-security"
"meta-virtualization"
"meta-cloud-services"
"meta-openjdk-temurin"
)

for layer in "${LAYERS[@]}"; do
Expand All @@ -39,3 +40,5 @@ for layer in "${LAYERS[@]}"; do
echo "Warning: Layer $layer not found!"
fi
done

rm -rf /home/user/poky/meta-openjdk-temurin/recipes-java/helloworld-java
1 change: 1 addition & 0 deletions src/imgtests/exec/loaders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@
from .pts import PhoronixTestSuite as PhoronixTestSuite
from .stress_ng import StressNg as StressNg
from .stress_ng import StressNgParamVerValidationError as StressNgParamVerValidationError
from .vdbench import Vdbench as Vdbench
105 changes: 105 additions & 0 deletions src/imgtests/exec/loaders/vdbench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import logging
from pathlib import Path
from typing import Final

from imgtests.constant import LIB_NAME
from imgtests.exec.base_util import GenericUtil
from imgtests.exec.exec import ExecResult, SSHClient, common_run_command
from imgtests.exec.utils import create_opt

logger = logging.getLogger(__name__)

VDBENCH_NAME: Final = "vdbench"
VDBENCH_DIR: Final = Path("/usr/sbin") / VDBENCH_NAME


class Vdbench(GenericUtil):
def __init__(self, ssh_client: SSHClient | None = None) -> None:
super().__init__(VDBENCH_NAME, ssh_client)
self.path = VDBENCH_DIR / VDBENCH_NAME

def validate_setup(self) -> ExecResult:
result = common_run_command(["ls", str(self.path)], self.ssh_client)
if result.returncode:
return ExecResult(
cmd=result.cmd,
stderr=f"Failed to locate '{self.name}'.",
returncode=1,
)
return result

def configure_params(
self,
config_file: Path,
timeout_sec: int = 60,
block_size: int = 4096,
read_percentage: int = 70,
iorate: int = 1000,
) -> ExecResult:
configuration = (
f"sd=sd1,lun=storage.img,size=1024m\n"
f"wd=wd1,sd=sd1,xfersize={block_size},readpct={read_percentage},seekpct=100\n"
f"rd=run1,wd=wd1,iorate={iorate},elapsed={timeout_sec},interval=1"
)
result = self.__provide_folder(config_file.parent)
if result.returncode:
return result
return common_run_command(
[
"echo",
"-e",
f"'{configuration}'",
">",
str(config_file),
],
self.ssh_client,
)

def run(
self,
timeout_sec: int,
block_size: int = 4096,
read_percentage: int = 70,
iorate: int = 1000,
) -> tuple[ExecResult, Path | None]:
"""Runs the vdbench.

Args:
timeout_sec (int): Execution time of the vdbench in seconds.
block_size (int): Block size in bytes for IO operations.
read_percentage (int): Percentage of read operations.
iorate (int): IO operations per second.
"""
result = self.validate_setup()
if result.returncode:
return result, None
result = common_run_command(["echo", "$HOME"], self.ssh_client)
home_dir = result.stdout.strip()
if result.returncode or not home_dir:
return result, None

config_file: Final = Path(home_dir) / LIB_NAME / VDBENCH_NAME / f"{VDBENCH_NAME}-config"
self.configure_params(
config_file=config_file,
timeout_sec=timeout_sec,
block_size=block_size,
read_percentage=read_percentage,
iorate=iorate,
)

output_dir = Path(home_dir) / LIB_NAME / VDBENCH_NAME / f"{VDBENCH_NAME}-output"
result = self.__provide_folder(output_dir)
if result.returncode:
return result, None
opts = [
*create_opt("f", config_file, use_one_dash=True),
*create_opt("o", output_dir, use_one_dash=True),
]
result = self(opts)
return result, output_dir

def __provide_folder(self, folder: Path) -> ExecResult:
result = common_run_command(["test", "-d", str(folder)], self.ssh_client)
if result.returncode:
return common_run_command(["mkdir", "--parents", str(folder)], self.ssh_client)
return result
46 changes: 46 additions & 0 deletions src/imgtests/suites/drive/vdbench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from datetime import UTC, datetime
from typing import TYPE_CHECKING

from imgtests.exec.loaders import Vdbench
from imgtests.planning.base import AbstractRunnableTimeLimitedTest
from imgtests.types import Subsystem, TestResult, TestStatus

if TYPE_CHECKING:
from collections.abc import Iterable
from concurrent.futures import ThreadPoolExecutor

from imgtests.exec.exec import SSHClient


class VdbenchTest(AbstractRunnableTimeLimitedTest):
"""Test that runs vdbench on a disk."""

def __init__(self, timeout: int) -> None:
super().__init__(
"Load drives with vdbench.",
frozenset({Subsystem.FILE}),
timeout=timeout,
)

def _run(
self,
executor: ThreadPoolExecutor,
client: SSHClient | None,
timeout: int,
) -> Iterable[TestResult]:
vdbench = Vdbench(client)
started_at = datetime.now(UTC)
future = executor.submit(
vdbench.run,
timeout_sec=timeout,
block_size=4096,
read_percentage=70,
iorate=1000,
)
result, output_dir = future.result()
yield TestResult(
metrics={"output_dir": output_dir},
command=" ".join(result.cmd),
started_at=started_at,
status=TestStatus.PASSED if not result.returncode else TestStatus.FAILED,
)
Loading