Skip to content
Open
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
35 changes: 35 additions & 0 deletions src/imgtests/exec/loaders/stress_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class StressNGMetrics(NamedTuple):
bogo_ops_s_usr_sys_time: float
cpu_used_per_instance: float
rss_max_kb: int | None = None
stats: dict[str, int] | None = None
top10_slowest: tuple[StressNGSyscallTiming, ...] | None = None


Expand All @@ -57,6 +58,7 @@ class StressNGResult(NamedTuple):
SPF_RE: Final = re.compile(r"^(skipped|passed|failed):\s*(\d+)(?::\s*([^\s()]+))?", re.IGNORECASE)
METRICS_UNTRUSTY_RE: Final = re.compile(r"metrics untrustworthy:\s*(\d+)", re.IGNORECASE)
CLEAN_LINE_RE: Final = re.compile(r"stress-ng: (?:info|metrc):\s+\[\d+\]\s*")
SUBSYSTEM_RE: Final = re.compile(r"^(\w+):\s*$")
METRICS_RE: Final = re.compile(
r"^(\S+)\s+" # stressor name
r"(\d+)\s+" # bogo ops
Expand All @@ -68,6 +70,7 @@ class StressNGResult(NamedTuple):
r"([\d.]+)" # CPU used per instance
r"(?:\s+([\d]+))?$", # RSS Max
)
STATS_RE: Final = re.compile(r"^([\d,]+)\s+(.+)\s+([\d.]+)\s+(.+)$")


class StressNg(PkgMgrMixin, GenericUtil):
Expand Down Expand Up @@ -406,6 +409,7 @@ def run( # noqa: PLR0913
*create_opt("pipeherd", pipeherd),
*create_opt("sigq", sigq),
*add_flag("metrics"),
*add_flag("perf"),
]
if syscall is not None:
opts.extend(create_opt("syscall-top", 0))
Expand Down Expand Up @@ -441,6 +445,11 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901
if not clean_line:
continue

m_subsystem = SUBSYSTEM_RE.match(clean_line)
if m_subsystem is not None:
current_stressor = m_subsystem.group(1)
continue

m = METRICS_RE.match(clean_line)
if m is not None:
try:
Expand Down Expand Up @@ -472,6 +481,7 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901
"bogo_ops_s_usr_sys_time": 0.0,
"cpu_used_per_instance": 0.0,
"rss_max_kb": None,
"stats": {},
"syscall_calls": [],
},
)
Expand Down Expand Up @@ -511,6 +521,7 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901
"bogo_ops_s_usr_sys_time": 0.0,
"cpu_used_per_instance": 0.0,
"rss_max_kb": None,
"stats": {},
"syscall_calls": [],
},
)
Expand Down Expand Up @@ -540,6 +551,29 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901
m_untrusty = StressNg.__parse_untrusty(clean_line)
if m_untrusty:
summary_untrusty = m_untrusty
continue

stats = STATS_RE.match(clean_line)
if stats:
stat_counter = stats.group(1).replace(",", "")
stat_name = stats.group(2).strip().replace(" ", "_").replace("-", "_").lower()
target = current_stressor or "stress-ng"
metrics_map.setdefault(
target,
{
"bogo_ops": 0,
"real_time_secs": 0.0,
"usr_time_secs": 0.0,
"sys_time_secs": 0.0,
"bogo_ops_s_real_time": 0.0,
"bogo_ops_s_usr_sys_time": 0.0,
"cpu_used_per_instance": 0.0,
"rss_max_kb": None,
"stats": {},
"syscall_calls": [],
},
)
metrics_map[target]["stats"][stat_name] = int(stat_counter)

metrics: list[StressNGMetrics] = []
for stressor, info in metrics_map.items():
Expand All @@ -560,6 +594,7 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901
float(info.get("bogo_ops_s_usr_sys_time", -1)),
float(info.get("cpu_used_per_instance", -1)),
int(info["rss_max_kb"]) if info.get("rss_max_kb") is not None else None,
info.get("stats") or None,
top10_slowest,
)
except (ValueError, TypeError) as e:
Expand Down
61 changes: 60 additions & 1 deletion tests/unit/imgtests/exec/loaders/test_stress_ng.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
stress-ng: metrc: [999] syscall: open 9.0 1 10
stress-ng: metrc: [999] syscall: close 2.0 1 10
stress-ng: metrc: [999] syscall: read 7.0 1 10
stress-ng: info: [999] 5000000000 CPU Clock 0.500 B/sec
stress-ng: info: [999] 0 Page Faults Major 0.000 /sec
stress-ng: info: [999] 7712 Kmalloc 1.518 K/sec
stress-ng: info: [999] 262,244 RCU Utilization 3.809 K/sec
stress-ng: info: [999] 3,742,640,922 Cache Misses 54.365 M/sec ( 1.572%)
""",
).strip(),
[
Expand All @@ -63,6 +68,13 @@
1.00,
50.00,
None,
{
"cpu_clock": 5000000000,
"page_faults_major": 0,
"kmalloc": 7712,
"rcu_utilization": 262244,
"cache_misses": 3742640922,
},
(
StressNGSyscallTiming("open", 9.0, 1, 10),
StressNGSyscallTiming("read", 7.0, 1, 10),
Expand All @@ -71,6 +83,52 @@
),
],
),
(
dedent(
"""\
stress-ng: info: [999] syscall:
stress-ng: info: [999] 4,658,202,225 CPU Cycles 67.665 M/sec
stress-ng: info: [999] 4,330,169,695 Instructions 62.900 M/sec
stress-ng: info: [999] hdd:
stress-ng: info: [999] 21,900,101,550 CPU Cycles 0.318 B/sec
stress-ng: info: [999] 34,961,558,984 Instructions 0.508 B/sec
""",
).strip(),
[
StressNGMetrics(
"syscall",
0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
None,
{
"cpu_cycles": 4658202225,
"instructions": 4330169695,
},
None,
),
StressNGMetrics(
"hdd",
0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
None,
{
"cpu_cycles": 21900101550,
"instructions": 34961558984,
},
None,
),
],
),
],
ids=[
"One stressor with old metrics format.",
Expand All @@ -80,7 +138,8 @@
"Invalid bogo opts format.",
"One stressor with new metrics format.",
"Two stressors with new metrics format.",
"Syscall with syscall-top entries.",
"Syscall with syscall-top and perf entries.",
"Metrics for different subsystems.",
],
)
def test_parse_metrics(raw_metrics: str, expected: list[StressNGMetrics]) -> None:
Expand Down
Loading