From 0fd32ca8510f928e2ecc414e0ab4823276975489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B8=D0=B2=D0=BE=D0=B5=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=D1=82=D0=B0?= Date: Mon, 13 Jul 2026 21:27:37 +0300 Subject: [PATCH 1/3] feat: add perf parameter support for stress-ng --- src/imgtests/exec/loaders/stress_ng.py | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/imgtests/exec/loaders/stress_ng.py b/src/imgtests/exec/loaders/stress_ng.py index 09f492bc..c7867dce 100644 --- a/src/imgtests/exec/loaders/stress_ng.py +++ b/src/imgtests/exec/loaders/stress_ng.py @@ -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 @@ -68,6 +69,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+(\S+)$") class StressNg(PkgMgrMixin, GenericUtil): @@ -406,6 +408,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)) @@ -472,6 +475,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": [], }, ) @@ -511,6 +515,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": [], }, ) @@ -540,6 +545,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) + 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(): @@ -560,6 +588,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: @@ -618,6 +647,11 @@ def metrics_to_bmf(metrics: StressNGMetrics) -> dict[str, dict[str, Any]]: if metrics.rss_max_kb is not None: result["StressNGMetrics"]["rss_max_kb"] = {"value": metrics.rss_max_kb} + if metrics.stats: + result["StressNGMetrics"]["stats"] = { + stat_name: {"value": stat_value} for stat_name, stat_value in metrics.stats.items() + } + if metrics.top10_slowest: result["top10_slowest"] = {} for syscall in metrics.top10_slowest: From bd8066f0904636a40d2e5eedcd5ba8250e3686cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B8=D0=B2=D0=BE=D0=B5=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=D1=82=D0=B0?= Date: Mon, 13 Jul 2026 21:29:05 +0300 Subject: [PATCH 2/3] feat: add stats to parser test --- tests/unit/imgtests/exec/loaders/test_stress_ng.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/imgtests/exec/loaders/test_stress_ng.py b/tests/unit/imgtests/exec/loaders/test_stress_ng.py index bdcfeaff..4b9de2a4 100644 --- a/tests/unit/imgtests/exec/loaders/test_stress_ng.py +++ b/tests/unit/imgtests/exec/loaders/test_stress_ng.py @@ -50,6 +50,9 @@ 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: metrc: [999] 5000000000 CPU Clock 0.500 B/sec + stress-ng: metrc: [999] 0 Page Faults Major 0.000 /sec + stress-ng: metrc: [999] 7712 Kmalloc 1.518 K/sec """, ).strip(), [ @@ -63,6 +66,7 @@ 1.00, 50.00, None, + {"cpu_clock": 5000000000, "page_faults_major": 0, "kmalloc": 7712}, ( StressNGSyscallTiming("open", 9.0, 1, 10), StressNGSyscallTiming("read", 7.0, 1, 10), @@ -80,7 +84,7 @@ "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.", ], ) def test_parse_metrics(raw_metrics: str, expected: list[StressNGMetrics]) -> None: From 503d0d7ef94203e442fce81b37b39d63409d7e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B8=D0=B2=D0=BE=D0=B5=D0=B2=20=D0=9D=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=D1=82=D0=B0?= Date: Mon, 20 Jul 2026 21:59:33 +0300 Subject: [PATCH 3/3] refactor: update regular expression for different stress-ng versions --- src/imgtests/exec/loaders/stress_ng.py | 4 ++-- tests/unit/imgtests/exec/loaders/test_stress_ng.py | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/imgtests/exec/loaders/stress_ng.py b/src/imgtests/exec/loaders/stress_ng.py index 8f66f951..ce390c65 100644 --- a/src/imgtests/exec/loaders/stress_ng.py +++ b/src/imgtests/exec/loaders/stress_ng.py @@ -69,7 +69,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+(\S+)$") +STATS_RE: Final = re.compile(r"^([\d,]+)\s+(.+)\s+([\d.]+)\s+(.+)$") class StressNg(PkgMgrMixin, GenericUtil): @@ -549,7 +549,7 @@ def parse_metrics( # noqa: PLR0915, PLR0912, C901 stats = STATS_RE.match(clean_line) if stats: - stat_counter = stats.group(1) + stat_counter = stats.group(1).replace(",", "") stat_name = stats.group(2).strip().replace(" ", "_").replace("-", "_").lower() target = current_stressor or "stress-ng" metrics_map.setdefault( diff --git a/tests/unit/imgtests/exec/loaders/test_stress_ng.py b/tests/unit/imgtests/exec/loaders/test_stress_ng.py index 4b9de2a4..3da689be 100644 --- a/tests/unit/imgtests/exec/loaders/test_stress_ng.py +++ b/tests/unit/imgtests/exec/loaders/test_stress_ng.py @@ -53,6 +53,8 @@ stress-ng: metrc: [999] 5000000000 CPU Clock 0.500 B/sec stress-ng: metrc: [999] 0 Page Faults Major 0.000 /sec stress-ng: metrc: [999] 7712 Kmalloc 1.518 K/sec + stress-ng: metrc: [999] 262,244 RCU Utilization 3.809 K/sec + stress-ng: metrc: [999] 3,742,640,922 Cache Misses 54.365 M/sec ( 1.572%) """, ).strip(), [ @@ -66,7 +68,13 @@ 1.00, 50.00, None, - {"cpu_clock": 5000000000, "page_faults_major": 0, "kmalloc": 7712}, + { + "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),