diff --git a/src/imgtests/exec/loaders/stress_ng.py b/src/imgtests/exec/loaders/stress_ng.py index 42f80f0b..ce390c65 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+(.+)$") 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).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(): @@ -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: diff --git a/tests/unit/imgtests/exec/loaders/test_stress_ng.py b/tests/unit/imgtests/exec/loaders/test_stress_ng.py index bdcfeaff..3da689be 100644 --- a/tests/unit/imgtests/exec/loaders/test_stress_ng.py +++ b/tests/unit/imgtests/exec/loaders/test_stress_ng.py @@ -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: 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(), [ @@ -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), @@ -80,7 +92,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: