From 1e1ff2e03cc9cdeea571fe6e29670dab6e0fb598 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:42:15 +0000 Subject: [PATCH 1/6] Initial plan From 52874fd68d75379d7ae939fe51dc8970a0f72216 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:51:47 +0000 Subject: [PATCH 2/6] Add UnifiedProvisionBootTimeMessage and send helper function Co-authored-by: squirrelsc <27178119+squirrelsc@users.noreply.github.com> --- lisa/messages.py | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/lisa/messages.py b/lisa/messages.py index 4bb8539535..c21862e767 100644 --- a/lisa/messages.py +++ b/lisa/messages.py @@ -301,6 +301,16 @@ class ProvisionBootTimeMessage(MessageBase): information: Dict[str, str] = field(default_factory=dict) +@dataclass +class UnifiedProvisionBootTimeMessage(ProvisionBootTimeMessage): + type: str = "UnifiedProvisionBootTime" + metric_name: str = "" + metric_value: float = 0.0 + metric_unit: str = "" + metric_description: str = "" + metric_relativity: Optional[MetricRelativity] = MetricRelativity.NA + + @dataclass class KernelBuildMessage(MessageBase): type: str = "KernelBuild" @@ -434,3 +444,49 @@ def send_unified_perf_message( notifier.notify(message) return message + + +def send_unified_provision_boot_time_message( + node: "Node", + metric_name: str = "", + metric_value: float = 0.0, + metric_unit: str = "", + metric_description: str = "", + metric_relativity: Optional[MetricRelativity] = MetricRelativity.NA, + boot_times: int = 0, + provision_time: float = 0, + kernel_boot_time: float = 0, + initrd_boot_time: float = 0, + userspace_boot_time: float = 0, + firmware_boot_time: float = 0, + loader_boot_time: float = 0, + information: Optional[Dict[str, str]] = None, +) -> UnifiedProvisionBootTimeMessage: + message = UnifiedProvisionBootTimeMessage() + + # Set boot time fields + message.boot_times = boot_times + message.provision_time = provision_time + message.kernel_boot_time = kernel_boot_time + message.initrd_boot_time = initrd_boot_time + message.userspace_boot_time = userspace_boot_time + message.firmware_boot_time = firmware_boot_time + message.loader_boot_time = loader_boot_time + + # Set unified metric fields + message.metric_name = metric_name + message.metric_value = metric_value + message.metric_unit = metric_unit + message.metric_description = metric_description + message.metric_relativity = metric_relativity + + # Set information + if information: + message.information.update(information) + + # Add node information + message.information.update(node.get_information()) + + notifier.notify(message) + + return message From f1421d99285c846d7ad72f37fd912ecaadfb3e6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Oct 2025 23:04:55 +0000 Subject: [PATCH 3/6] Change UnifiedProvisionBootTimeMessage to extend PerfMessage like UnifiedPerfMessage Co-authored-by: squirrelsc <27178119+squirrelsc@users.noreply.github.com> --- lisa/messages.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lisa/messages.py b/lisa/messages.py index c21862e767..e0713bb51b 100644 --- a/lisa/messages.py +++ b/lisa/messages.py @@ -302,8 +302,16 @@ class ProvisionBootTimeMessage(MessageBase): @dataclass -class UnifiedProvisionBootTimeMessage(ProvisionBootTimeMessage): +class UnifiedProvisionBootTimeMessage(PerfMessage): type: str = "UnifiedProvisionBootTime" + # boot times collected from `last reboot` entries + boot_times: int = 0 + provision_time: float = 0 + kernel_boot_time: float = 0 + initrd_boot_time: float = 0 + userspace_boot_time: float = 0 + firmware_boot_time: float = 0 + loader_boot_time: float = 0 metric_name: str = "" metric_value: float = 0.0 metric_unit: str = "" @@ -448,6 +456,8 @@ def send_unified_perf_message( def send_unified_provision_boot_time_message( node: "Node", + test_result: "TestResult", + test_case_name: str = "", metric_name: str = "", metric_value: float = 0.0, metric_unit: str = "", @@ -460,9 +470,13 @@ def send_unified_provision_boot_time_message( userspace_boot_time: float = 0, firmware_boot_time: float = 0, loader_boot_time: float = 0, - information: Optional[Dict[str, str]] = None, ) -> UnifiedProvisionBootTimeMessage: - message = UnifiedProvisionBootTimeMessage() + message = create_perf_message( + message_type=UnifiedProvisionBootTimeMessage, + node=node, + test_result=test_result, + test_case_name=test_case_name, + ) # Set boot time fields message.boot_times = boot_times @@ -480,13 +494,6 @@ def send_unified_provision_boot_time_message( message.metric_description = metric_description message.metric_relativity = metric_relativity - # Set information - if information: - message.information.update(information) - - # Add node information - message.information.update(node.get_information()) - notifier.notify(message) return message From e836a75210613d523c28716d418f22e485753459 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 02:04:05 +0000 Subject: [PATCH 4/6] Add send_boot_time_metrics method to send UnifiedPerfMessage for boot time data Co-authored-by: squirrelsc <27178119+squirrelsc@users.noreply.github.com> --- lisa/messages.py | 63 --------------------- lisa/tools/systemd_analyze.py | 103 +++++++++++++++++++++++++++++++++- 2 files changed, 102 insertions(+), 64 deletions(-) diff --git a/lisa/messages.py b/lisa/messages.py index e0713bb51b..4bb8539535 100644 --- a/lisa/messages.py +++ b/lisa/messages.py @@ -301,24 +301,6 @@ class ProvisionBootTimeMessage(MessageBase): information: Dict[str, str] = field(default_factory=dict) -@dataclass -class UnifiedProvisionBootTimeMessage(PerfMessage): - type: str = "UnifiedProvisionBootTime" - # boot times collected from `last reboot` entries - boot_times: int = 0 - provision_time: float = 0 - kernel_boot_time: float = 0 - initrd_boot_time: float = 0 - userspace_boot_time: float = 0 - firmware_boot_time: float = 0 - loader_boot_time: float = 0 - metric_name: str = "" - metric_value: float = 0.0 - metric_unit: str = "" - metric_description: str = "" - metric_relativity: Optional[MetricRelativity] = MetricRelativity.NA - - @dataclass class KernelBuildMessage(MessageBase): type: str = "KernelBuild" @@ -452,48 +434,3 @@ def send_unified_perf_message( notifier.notify(message) return message - - -def send_unified_provision_boot_time_message( - node: "Node", - test_result: "TestResult", - test_case_name: str = "", - metric_name: str = "", - metric_value: float = 0.0, - metric_unit: str = "", - metric_description: str = "", - metric_relativity: Optional[MetricRelativity] = MetricRelativity.NA, - boot_times: int = 0, - provision_time: float = 0, - kernel_boot_time: float = 0, - initrd_boot_time: float = 0, - userspace_boot_time: float = 0, - firmware_boot_time: float = 0, - loader_boot_time: float = 0, -) -> UnifiedProvisionBootTimeMessage: - message = create_perf_message( - message_type=UnifiedProvisionBootTimeMessage, - node=node, - test_result=test_result, - test_case_name=test_case_name, - ) - - # Set boot time fields - message.boot_times = boot_times - message.provision_time = provision_time - message.kernel_boot_time = kernel_boot_time - message.initrd_boot_time = initrd_boot_time - message.userspace_boot_time = userspace_boot_time - message.firmware_boot_time = firmware_boot_time - message.loader_boot_time = loader_boot_time - - # Set unified metric fields - message.metric_name = metric_name - message.metric_value = metric_value - message.metric_unit = metric_unit - message.metric_description = metric_description - message.metric_relativity = metric_relativity - - notifier.notify(message) - - return message diff --git a/lisa/tools/systemd_analyze.py b/lisa/tools/systemd_analyze.py index 5c67824bca..fb301b34b9 100644 --- a/lisa/tools/systemd_analyze.py +++ b/lisa/tools/systemd_analyze.py @@ -2,13 +2,21 @@ # Licensed under the MIT license. import re from pathlib import PurePath +from typing import TYPE_CHECKING from retry import retry from lisa.executable import Tool -from lisa.messages import ProvisionBootTimeMessage +from lisa.messages import ( + MetricRelativity, + ProvisionBootTimeMessage, + send_unified_perf_message, +) from lisa.util import LisaException, find_groups_in_lines +if TYPE_CHECKING: + from lisa.testsuite import TestResult + class SystemdAnalyze(Tool): # Startup finished in 2.020ms (kernel) + 8.866s (initrd) + 14.894s (userspace) = 25.782s # noqa: E501 @@ -78,6 +86,99 @@ def get_boot_time(self, force_run: bool = True) -> ProvisionBootTimeMessage: boot_time.provision_time = self.node.provision_time return boot_time + def send_boot_time_metrics( + self, test_result: "TestResult", test_case_name: str = "" + ) -> None: + """ + Send boot time metrics as UnifiedPerfMessage notifications. + This allows boot time data to be collected in a standardized format. + """ + boot_time = self.get_boot_time() + + # Send kernel boot time metric + if boot_time.kernel_boot_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="kernel_boot_time", + metric_value=boot_time.kernel_boot_time, + metric_unit="ms", + metric_description="Linux kernel boot time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + + # Send initrd boot time metric + if boot_time.initrd_boot_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="initrd_boot_time", + metric_value=boot_time.initrd_boot_time, + metric_unit="ms", + metric_description="Initial RAM disk boot time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + + # Send userspace boot time metric + if boot_time.userspace_boot_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="userspace_boot_time", + metric_value=boot_time.userspace_boot_time, + metric_unit="ms", + metric_description="Userspace initialization time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + + # Send firmware boot time metric + if boot_time.firmware_boot_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="firmware_boot_time", + metric_value=boot_time.firmware_boot_time, + metric_unit="ms", + metric_description="Firmware boot time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + + # Send loader boot time metric + if boot_time.loader_boot_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="loader_boot_time", + metric_value=boot_time.loader_boot_time, + metric_unit="ms", + metric_description="Boot loader time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + + # Send provision time metric + if boot_time.provision_time > 0: + send_unified_perf_message( + node=self.node, + test_result=test_result, + test_case_name=test_case_name, + tool="systemd-analyze", + metric_name="provision_time", + metric_value=boot_time.provision_time, + metric_unit="seconds", + metric_description="Total VM provision time", + metric_relativity=MetricRelativity.LowerIsBetter, + ) + def plot(self, output_file: PurePath, sudo: bool = False) -> None: self.run(f"plot > {output_file}", shell=True, sudo=sudo, expected_exit_code=0) From e1374dd1c9fbdd9d59b5e2a83727b6504d18d6bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 03:39:17 +0000 Subject: [PATCH 5/6] Move boot time message sending to SystemdAnalyze class Co-authored-by: squirrelsc <27178119+squirrelsc@users.noreply.github.com> --- lisa/operating_system.py | 4 +--- lisa/tools/systemd_analyze.py | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lisa/operating_system.py b/lisa/operating_system.py index 73850647af..62f449b5a0 100644 --- a/lisa/operating_system.py +++ b/lisa/operating_system.py @@ -475,9 +475,7 @@ def capture_system_information(self, saved_path: Path) -> None: try: systemd_analyze_tool = self._node.tools[SystemdAnalyze] - boot_time = systemd_analyze_tool.get_boot_time() - boot_time.information.update(self._node.get_information()) - notifier.notify(boot_time) + systemd_analyze_tool.send_boot_time_messages() except Exception as e: self._node.log.debug(f"error on get boot time: {e}") diff --git a/lisa/tools/systemd_analyze.py b/lisa/tools/systemd_analyze.py index fb301b34b9..b016d50777 100644 --- a/lisa/tools/systemd_analyze.py +++ b/lisa/tools/systemd_analyze.py @@ -86,14 +86,51 @@ def get_boot_time(self, force_run: bool = True) -> ProvisionBootTimeMessage: boot_time.provision_time = self.node.provision_time return boot_time + def send_boot_time_messages( + self, test_result: "TestResult" = None, test_case_name: str = "" + ) -> None: + """ + Send boot time messages. Sends both ProvisionBootTimeMessage and + UnifiedPerfMessage notifications. + + Args: + test_result: Optional test result for UnifiedPerfMessage. If None, + only ProvisionBootTimeMessage is sent. + test_case_name: Name of the test case for UnifiedPerfMessage. + """ + from lisa import notifier + + boot_time = self.get_boot_time() + boot_time.information.update(self.node.get_information()) + + # Send ProvisionBootTimeMessage + notifier.notify(boot_time) + + # Send UnifiedPerfMessage notifications if test_result is available + if test_result is not None: + self._send_unified_boot_time_metrics(boot_time, test_result, test_case_name) + def send_boot_time_metrics( self, test_result: "TestResult", test_case_name: str = "" ) -> None: """ Send boot time metrics as UnifiedPerfMessage notifications. This allows boot time data to be collected in a standardized format. + + Deprecated: Use send_boot_time_messages() instead to send both message formats. """ boot_time = self.get_boot_time() + self._send_unified_boot_time_metrics(boot_time, test_result, test_case_name) + + def _send_unified_boot_time_metrics( + self, + boot_time: ProvisionBootTimeMessage, + test_result: "TestResult", + test_case_name: str = "", + ) -> None: + """ + Internal method to send UnifiedPerfMessage notifications for boot time metrics. + """ # Send kernel boot time metric if boot_time.kernel_boot_time > 0: From eebdc4fb103062436df2b0654420ee0e9fae38da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Oct 2025 03:58:50 +0000 Subject: [PATCH 6/6] Simplify send_boot_time_messages and move imports to top Co-authored-by: squirrelsc <27178119+squirrelsc@users.noreply.github.com> --- lisa/tools/systemd_analyze.py | 135 +--------------------------------- 1 file changed, 4 insertions(+), 131 deletions(-) diff --git a/lisa/tools/systemd_analyze.py b/lisa/tools/systemd_analyze.py index b016d50777..3ff7df90f4 100644 --- a/lisa/tools/systemd_analyze.py +++ b/lisa/tools/systemd_analyze.py @@ -2,21 +2,14 @@ # Licensed under the MIT license. import re from pathlib import PurePath -from typing import TYPE_CHECKING from retry import retry +from lisa import notifier from lisa.executable import Tool -from lisa.messages import ( - MetricRelativity, - ProvisionBootTimeMessage, - send_unified_perf_message, -) +from lisa.messages import ProvisionBootTimeMessage from lisa.util import LisaException, find_groups_in_lines -if TYPE_CHECKING: - from lisa.testsuite import TestResult - class SystemdAnalyze(Tool): # Startup finished in 2.020ms (kernel) + 8.866s (initrd) + 14.894s (userspace) = 25.782s # noqa: E501 @@ -86,135 +79,15 @@ def get_boot_time(self, force_run: bool = True) -> ProvisionBootTimeMessage: boot_time.provision_time = self.node.provision_time return boot_time - def send_boot_time_messages( - self, test_result: "TestResult" = None, test_case_name: str = "" - ) -> None: + def send_boot_time_messages(self) -> None: """ - Send boot time messages. Sends both ProvisionBootTimeMessage and - UnifiedPerfMessage notifications. - - Args: - test_result: Optional test result for UnifiedPerfMessage. If None, - only ProvisionBootTimeMessage is sent. - test_case_name: Name of the test case for UnifiedPerfMessage. + Send boot time messages as ProvisionBootTimeMessage. """ - from lisa import notifier - boot_time = self.get_boot_time() boot_time.information.update(self.node.get_information()) # Send ProvisionBootTimeMessage notifier.notify(boot_time) - - # Send UnifiedPerfMessage notifications if test_result is available - if test_result is not None: - self._send_unified_boot_time_metrics(boot_time, test_result, test_case_name) - - def send_boot_time_metrics( - self, test_result: "TestResult", test_case_name: str = "" - ) -> None: - """ - Send boot time metrics as UnifiedPerfMessage notifications. - This allows boot time data to be collected in a standardized format. - - Deprecated: Use send_boot_time_messages() instead to send both message formats. - """ - boot_time = self.get_boot_time() - self._send_unified_boot_time_metrics(boot_time, test_result, test_case_name) - - def _send_unified_boot_time_metrics( - self, - boot_time: ProvisionBootTimeMessage, - test_result: "TestResult", - test_case_name: str = "", - ) -> None: - """ - Internal method to send UnifiedPerfMessage notifications for boot time metrics. - """ - - # Send kernel boot time metric - if boot_time.kernel_boot_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="kernel_boot_time", - metric_value=boot_time.kernel_boot_time, - metric_unit="ms", - metric_description="Linux kernel boot time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) - - # Send initrd boot time metric - if boot_time.initrd_boot_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="initrd_boot_time", - metric_value=boot_time.initrd_boot_time, - metric_unit="ms", - metric_description="Initial RAM disk boot time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) - - # Send userspace boot time metric - if boot_time.userspace_boot_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="userspace_boot_time", - metric_value=boot_time.userspace_boot_time, - metric_unit="ms", - metric_description="Userspace initialization time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) - - # Send firmware boot time metric - if boot_time.firmware_boot_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="firmware_boot_time", - metric_value=boot_time.firmware_boot_time, - metric_unit="ms", - metric_description="Firmware boot time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) - - # Send loader boot time metric - if boot_time.loader_boot_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="loader_boot_time", - metric_value=boot_time.loader_boot_time, - metric_unit="ms", - metric_description="Boot loader time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) - - # Send provision time metric - if boot_time.provision_time > 0: - send_unified_perf_message( - node=self.node, - test_result=test_result, - test_case_name=test_case_name, - tool="systemd-analyze", - metric_name="provision_time", - metric_value=boot_time.provision_time, - metric_unit="seconds", - metric_description="Total VM provision time", - metric_relativity=MetricRelativity.LowerIsBetter, - ) def plot(self, output_file: PurePath, sudo: bool = False) -> None: self.run(f"plot > {output_file}", shell=True, sudo=sudo, expected_exit_code=0)