xref: /dpdk/dts/framework/testbed_model/node.py (revision b76d80a4dbb900ac50a8ab3a0cae9996bcd9b8d0)
1c4ef44deSJuraj Linkeš# SPDX-License-Identifier: BSD-3-Clause
2c4ef44deSJuraj Linkeš# Copyright(c) 2010-2014 Intel Corporation
378534506SJuraj Linkeš# Copyright(c) 2022-2023 PANTHEON.tech s.r.o.
478534506SJuraj Linkeš# Copyright(c) 2022-2023 University of New Hampshire
5c4ef44deSJuraj Linkeš
6c4ef44deSJuraj Linkeš"""
7c4ef44deSJuraj LinkešA node is a generic host that DTS connects to and manages.
8c4ef44deSJuraj Linkeš"""
9c4ef44deSJuraj Linkeš
10680d8a24SJuraj Linkešfrom typing import Any, Callable
11680d8a24SJuraj Linkeš
1278534506SJuraj Linkešfrom framework.config import (
1378534506SJuraj Linkeš    BuildTargetConfiguration,
1478534506SJuraj Linkeš    ExecutionConfiguration,
1578534506SJuraj Linkeš    NodeConfiguration,
1678534506SJuraj Linkeš)
17c4ef44deSJuraj Linkešfrom framework.logger import DTSLOG, getLogger
1878534506SJuraj Linkešfrom framework.remote_session import OSSession, create_session
19680d8a24SJuraj Linkešfrom framework.settings import SETTINGS
20c4ef44deSJuraj Linkeš
21c020b7ceSJuraj Linkešfrom .hw import (
22c020b7ceSJuraj Linkeš    LogicalCore,
23c020b7ceSJuraj Linkeš    LogicalCoreCount,
24c020b7ceSJuraj Linkeš    LogicalCoreList,
25c020b7ceSJuraj Linkeš    LogicalCoreListFilter,
26c020b7ceSJuraj Linkeš    lcore_filter,
27c020b7ceSJuraj Linkeš)
28c020b7ceSJuraj Linkeš
29c4ef44deSJuraj Linkeš
30c4ef44deSJuraj Linkešclass Node(object):
31c4ef44deSJuraj Linkeš    """
3278534506SJuraj Linkeš    Basic class for node management. This class implements methods that
33c4ef44deSJuraj Linkeš    manage a node, such as information gathering (of CPU/PCI/NIC) and
34c4ef44deSJuraj Linkeš    environment setup.
35c4ef44deSJuraj Linkeš    """
36c4ef44deSJuraj Linkeš
3778534506SJuraj Linkeš    main_session: OSSession
3878534506SJuraj Linkeš    config: NodeConfiguration
39c4ef44deSJuraj Linkeš    name: str
40c020b7ceSJuraj Linkeš    lcores: list[LogicalCore]
4178534506SJuraj Linkeš    _logger: DTSLOG
4278534506SJuraj Linkeš    _other_sessions: list[OSSession]
43c4ef44deSJuraj Linkeš
44c4ef44deSJuraj Linkeš    def __init__(self, node_config: NodeConfiguration):
4578534506SJuraj Linkeš        self.config = node_config
4678534506SJuraj Linkeš        self.name = node_config.name
4778534506SJuraj Linkeš        self._logger = getLogger(self.name)
4878534506SJuraj Linkeš        self.main_session = create_session(self.config, self.name, self._logger)
4978534506SJuraj Linkeš
50c020b7ceSJuraj Linkeš        self._get_remote_cpus()
51c020b7ceSJuraj Linkeš        # filter the node lcores according to user config
52c020b7ceSJuraj Linkeš        self.lcores = LogicalCoreListFilter(
53c020b7ceSJuraj Linkeš            self.lcores, LogicalCoreList(self.config.lcores)
54c020b7ceSJuraj Linkeš        ).filter()
55c020b7ceSJuraj Linkeš
56c4ef44deSJuraj Linkeš        self._other_sessions = []
57c4ef44deSJuraj Linkeš
5878534506SJuraj Linkeš        self._logger.info(f"Created node: {self.name}")
59c4ef44deSJuraj Linkeš
6078534506SJuraj Linkeš    def set_up_execution(self, execution_config: ExecutionConfiguration) -> None:
61c4ef44deSJuraj Linkeš        """
6278534506SJuraj Linkeš        Perform the execution setup that will be done for each execution
6378534506SJuraj Linkeš        this node is part of.
6478534506SJuraj Linkeš        """
65*b76d80a4SJuraj Linkeš        self._setup_hugepages()
6678534506SJuraj Linkeš        self._set_up_execution(execution_config)
6778534506SJuraj Linkeš
6878534506SJuraj Linkeš    def _set_up_execution(self, execution_config: ExecutionConfiguration) -> None:
6978534506SJuraj Linkeš        """
7078534506SJuraj Linkeš        This method exists to be optionally overwritten by derived classes and
7178534506SJuraj Linkeš        is not decorated so that the derived class doesn't have to use the decorator.
72c4ef44deSJuraj Linkeš        """
73c4ef44deSJuraj Linkeš
7478534506SJuraj Linkeš    def tear_down_execution(self) -> None:
7578534506SJuraj Linkeš        """
7678534506SJuraj Linkeš        Perform the execution teardown that will be done after each execution
7778534506SJuraj Linkeš        this node is part of concludes.
7878534506SJuraj Linkeš        """
7978534506SJuraj Linkeš        self._tear_down_execution()
80c4ef44deSJuraj Linkeš
8178534506SJuraj Linkeš    def _tear_down_execution(self) -> None:
8278534506SJuraj Linkeš        """
8378534506SJuraj Linkeš        This method exists to be optionally overwritten by derived classes and
8478534506SJuraj Linkeš        is not decorated so that the derived class doesn't have to use the decorator.
8578534506SJuraj Linkeš        """
8678534506SJuraj Linkeš
8778534506SJuraj Linkeš    def set_up_build_target(
8878534506SJuraj Linkeš        self, build_target_config: BuildTargetConfiguration
8978534506SJuraj Linkeš    ) -> None:
9078534506SJuraj Linkeš        """
9178534506SJuraj Linkeš        Perform the build target setup that will be done for each build target
9278534506SJuraj Linkeš        tested on this node.
9378534506SJuraj Linkeš        """
9478534506SJuraj Linkeš        self._set_up_build_target(build_target_config)
9578534506SJuraj Linkeš
9678534506SJuraj Linkeš    def _set_up_build_target(
9778534506SJuraj Linkeš        self, build_target_config: BuildTargetConfiguration
9878534506SJuraj Linkeš    ) -> None:
9978534506SJuraj Linkeš        """
10078534506SJuraj Linkeš        This method exists to be optionally overwritten by derived classes and
10178534506SJuraj Linkeš        is not decorated so that the derived class doesn't have to use the decorator.
10278534506SJuraj Linkeš        """
10378534506SJuraj Linkeš
10478534506SJuraj Linkeš    def tear_down_build_target(self) -> None:
10578534506SJuraj Linkeš        """
10678534506SJuraj Linkeš        Perform the build target teardown that will be done after each build target
10778534506SJuraj Linkeš        tested on this node.
10878534506SJuraj Linkeš        """
10978534506SJuraj Linkeš        self._tear_down_build_target()
11078534506SJuraj Linkeš
11178534506SJuraj Linkeš    def _tear_down_build_target(self) -> None:
11278534506SJuraj Linkeš        """
11378534506SJuraj Linkeš        This method exists to be optionally overwritten by derived classes and
11478534506SJuraj Linkeš        is not decorated so that the derived class doesn't have to use the decorator.
11578534506SJuraj Linkeš        """
11678534506SJuraj Linkeš
11778534506SJuraj Linkeš    def create_session(self, name: str) -> OSSession:
11878534506SJuraj Linkeš        """
11978534506SJuraj Linkeš        Create and return a new OSSession tailored to the remote OS.
12078534506SJuraj Linkeš        """
12178534506SJuraj Linkeš        session_name = f"{self.name} {name}"
12278534506SJuraj Linkeš        connection = create_session(
12378534506SJuraj Linkeš            self.config,
12478534506SJuraj Linkeš            session_name,
12578534506SJuraj Linkeš            getLogger(session_name, node=self.name),
126c4ef44deSJuraj Linkeš        )
127c4ef44deSJuraj Linkeš        self._other_sessions.append(connection)
128c4ef44deSJuraj Linkeš        return connection
129c4ef44deSJuraj Linkeš
130c020b7ceSJuraj Linkeš    def filter_lcores(
131c020b7ceSJuraj Linkeš        self,
132c020b7ceSJuraj Linkeš        filter_specifier: LogicalCoreCount | LogicalCoreList,
133c020b7ceSJuraj Linkeš        ascending: bool = True,
134c020b7ceSJuraj Linkeš    ) -> list[LogicalCore]:
135c020b7ceSJuraj Linkeš        """
136c020b7ceSJuraj Linkeš        Filter the LogicalCores found on the Node according to
137c020b7ceSJuraj Linkeš        a LogicalCoreCount or a LogicalCoreList.
138c020b7ceSJuraj Linkeš
139c020b7ceSJuraj Linkeš        If ascending is True, use cores with the lowest numerical id first
140c020b7ceSJuraj Linkeš        and continue in ascending order. If False, start with the highest
141c020b7ceSJuraj Linkeš        id and continue in descending order. This ordering affects which
142c020b7ceSJuraj Linkeš        sockets to consider first as well.
143c020b7ceSJuraj Linkeš        """
144c020b7ceSJuraj Linkeš        self._logger.debug(f"Filtering {filter_specifier} from {self.lcores}.")
145c020b7ceSJuraj Linkeš        return lcore_filter(
146c020b7ceSJuraj Linkeš            self.lcores,
147c020b7ceSJuraj Linkeš            filter_specifier,
148c020b7ceSJuraj Linkeš            ascending,
149c020b7ceSJuraj Linkeš        ).filter()
150c020b7ceSJuraj Linkeš
151c020b7ceSJuraj Linkeš    def _get_remote_cpus(self) -> None:
152c020b7ceSJuraj Linkeš        """
153c020b7ceSJuraj Linkeš        Scan CPUs in the remote OS and store a list of LogicalCores.
154c020b7ceSJuraj Linkeš        """
155c020b7ceSJuraj Linkeš        self._logger.info("Getting CPU information.")
156c020b7ceSJuraj Linkeš        self.lcores = self.main_session.get_remote_cpus(self.config.use_first_core)
157c020b7ceSJuraj Linkeš
158*b76d80a4SJuraj Linkeš    def _setup_hugepages(self):
159*b76d80a4SJuraj Linkeš        """
160*b76d80a4SJuraj Linkeš        Setup hugepages on the Node. Different architectures can supply different
161*b76d80a4SJuraj Linkeš        amounts of memory for hugepages and numa-based hugepage allocation may need
162*b76d80a4SJuraj Linkeš        to be considered.
163*b76d80a4SJuraj Linkeš        """
164*b76d80a4SJuraj Linkeš        if self.config.hugepages:
165*b76d80a4SJuraj Linkeš            self.main_session.setup_hugepages(
166*b76d80a4SJuraj Linkeš                self.config.hugepages.amount, self.config.hugepages.force_first_numa
167*b76d80a4SJuraj Linkeš            )
168*b76d80a4SJuraj Linkeš
16978534506SJuraj Linkeš    def close(self) -> None:
170c4ef44deSJuraj Linkeš        """
17178534506SJuraj Linkeš        Close all connections and free other resources.
172c4ef44deSJuraj Linkeš        """
173c4ef44deSJuraj Linkeš        if self.main_session:
174c4ef44deSJuraj Linkeš            self.main_session.close()
175c4ef44deSJuraj Linkeš        for session in self._other_sessions:
176c4ef44deSJuraj Linkeš            session.close()
17778534506SJuraj Linkeš        self._logger.logger_exit()
178680d8a24SJuraj Linkeš
179680d8a24SJuraj Linkeš    @staticmethod
180680d8a24SJuraj Linkeš    def skip_setup(func: Callable[..., Any]) -> Callable[..., Any]:
181680d8a24SJuraj Linkeš        if SETTINGS.skip_setup:
182680d8a24SJuraj Linkeš            return lambda *args: None
183680d8a24SJuraj Linkeš        else:
184680d8a24SJuraj Linkeš            return func
185