blob: 04dfb91fccbceec7779cbb992624464839909784 [file] [log] [blame]
#!/usr/bin/env python3
"""
fiotestcommon.py
This contains constant definitions, helpers, and a Requirements class that can
be used to help with running fio tests.
"""
import os
import locale
import logging
import platform
import subprocess
import multiprocessing
SUCCESS_DEFAULT = {
'zero_return': True,
'stderr_empty': True,
'timeout': 600,
}
SUCCESS_LONG = {
'zero_return': True,
'stderr_empty': True,
'timeout': 3600,
}
SUCCESS_NONZERO = {
'zero_return': False,
'stderr_empty': False,
'timeout': 600,
}
SUCCESS_STDERR = {
'zero_return': True,
'stderr_empty': False,
'timeout': 600,
}
def get_file(filename):
"""Safely read a file."""
file_data = ''
success = True
try:
with open(filename, "r", encoding=locale.getpreferredencoding()) as output_file:
file_data = output_file.read()
except OSError:
success = False
return file_data, success
class Requirements():
"""Requirements consists of multiple run environment characteristics.
These are to determine if a particular test can be run"""
_linux = False
_libaio = False
_io_uring = False
_zbd = False
_root = False
_zoned_nullb = False
_not_macos = False
_not_windows = False
_unittests = False
_cpucount4 = False
_nvmecdev = False
def __init__(self, fio_root, args):
Requirements._not_macos = platform.system() != "Darwin"
Requirements._not_windows = platform.system() != "Windows"
Requirements._linux = platform.system() == "Linux"
if Requirements._linux:
config_file = os.path.join(fio_root, "config-host.h")
contents, success = get_file(config_file)
if not success:
print(f"Unable to open {config_file} to check requirements")
Requirements._zbd = True
else:
Requirements._zbd = "CONFIG_HAS_BLKZONED" in contents
Requirements._libaio = "CONFIG_LIBAIO" in contents
contents, success = get_file("/proc/kallsyms")
if not success:
print("Unable to open '/proc/kallsyms' to probe for io_uring support")
else:
Requirements._io_uring = "io_uring_setup" in contents
Requirements._root = os.geteuid() == 0
if Requirements._zbd and Requirements._root:
try:
subprocess.run(["modprobe", "null_blk"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if os.path.exists("/sys/module/null_blk/parameters/zoned"):
Requirements._zoned_nullb = True
except Exception:
pass
if platform.system() == "Windows":
utest_exe = "unittest.exe"
else:
utest_exe = "unittest"
unittest_path = os.path.join(fio_root, "unittests", utest_exe)
Requirements._unittests = os.path.exists(unittest_path)
Requirements._cpucount4 = multiprocessing.cpu_count() >= 4
Requirements._nvmecdev = args.nvmecdev if hasattr(args, 'nvmecdev') else False
req_list = [
Requirements.linux,
Requirements.libaio,
Requirements.io_uring,
Requirements.zbd,
Requirements.root,
Requirements.zoned_nullb,
Requirements.not_macos,
Requirements.not_windows,
Requirements.unittests,
Requirements.cpucount4,
Requirements.nvmecdev,
]
for req in req_list:
value, desc = req()
logging.debug("Requirements: Requirement '%s' met? %s", desc, value)
@classmethod
def linux(cls):
"""Are we running on Linux?"""
return Requirements._linux, "Linux required"
@classmethod
def libaio(cls):
"""Is libaio available?"""
return Requirements._libaio, "libaio required"
@classmethod
def io_uring(cls):
"""Is io_uring available?"""
return Requirements._io_uring, "io_uring required"
@classmethod
def zbd(cls):
"""Is ZBD support available?"""
return Requirements._zbd, "Zoned block device support required"
@classmethod
def root(cls):
"""Are we running as root?"""
return Requirements._root, "root required"
@classmethod
def zoned_nullb(cls):
"""Are zoned null block devices available?"""
return Requirements._zoned_nullb, "Zoned null block device support required"
@classmethod
def not_macos(cls):
"""Are we running on a platform other than macOS?"""
return Requirements._not_macos, "platform other than macOS required"
@classmethod
def not_windows(cls):
"""Are we running on a platform other than Windws?"""
return Requirements._not_windows, "platform other than Windows required"
@classmethod
def unittests(cls):
"""Were unittests built?"""
return Requirements._unittests, "Unittests support required"
@classmethod
def cpucount4(cls):
"""Do we have at least 4 CPUs?"""
return Requirements._cpucount4, "4+ CPUs required"
@classmethod
def nvmecdev(cls):
"""Do we have an NVMe character device to test?"""
return Requirements._nvmecdev, "NVMe character device test target required"