From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id AE79E4608B; Wed, 15 Jan 2025 15:19:59 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4E8F4402E5; Wed, 15 Jan 2025 15:19:40 +0100 (CET) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mails.dpdk.org (Postfix) with ESMTP id 0F25C402DD for ; Wed, 15 Jan 2025 15:19:37 +0100 (CET) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D818011FB; Wed, 15 Jan 2025 06:20:04 -0800 (PST) Received: from localhost.localdomain (JR4XG4HTQC.cambridge.arm.com [10.1.39.16]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id A00D23F63F; Wed, 15 Jan 2025 06:19:35 -0800 (PST) From: Luca Vizzarro To: dev@dpdk.org Cc: Nicholas Pratte , Luca Vizzarro , Paul Szczepanek , Patrick Robb Subject: [PATCH v3 4/7] dts: rework DPDK attributes in SUT node config Date: Wed, 15 Jan 2025 14:18:06 +0000 Message-ID: <20250115141809.3898708-5-luca.vizzarro@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250115141809.3898708-1-luca.vizzarro@arm.com> References: <20240705171341.23894-2-npratte@iol.unh.edu> <20250115141809.3898708-1-luca.vizzarro@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Nicholas Pratte Rework 'lcores' and 'memory_channels' into a new 'dpdk_config' subsection in an effort to make these attributes SUT specific; the traffic generator, more often than not, does not need this information. Ideally, if such information is needed, then it will be listed in the 'traffic_generator' component in TG Node configuration. Such logic is not introduced in this patch, but the framework can be rewritten to do so without any implications of extreme effort. To make this work, use_first_core has been removed from the framework entirely in favor of doing this within the LogicalCoreListFilter object. Since use_first_core was only ever activated when logical core 0 was explicitly defined, core 0 can be removed from the list of total logical cores assuming that it was not listed within filter_specifier. This patch also removes 'vdevs' from 'system_under_test_node' and moves it into 'test_runs'. Bugzilla ID: 1360 Signed-off-by: Nicholas Pratte Signed-off-by: Luca Vizzarro Reviewed-by: Paul Szczepanek --- dts/conf.yaml | 20 +++++----- dts/framework/config/__init__.py | 39 ++++++++++---------- dts/framework/runner.py | 6 +-- dts/framework/testbed_model/cpu.py | 6 ++- dts/framework/testbed_model/linux_session.py | 5 +-- dts/framework/testbed_model/node.py | 27 +------------- dts/framework/testbed_model/os_session.py | 2 +- dts/framework/testbed_model/sut_node.py | 14 ++++++- 8 files changed, 54 insertions(+), 65 deletions(-) diff --git a/dts/conf.yaml b/dts/conf.yaml index c93eedbc94..bc78882d0d 100644 --- a/dts/conf.yaml +++ b/dts/conf.yaml @@ -26,12 +26,11 @@ test_runs: skip_smoke_tests: false # optional test_suites: # the following test suites will be run in their entirety - hello_world + vdevs: # optional; if removed, vdevs won't be used in the execution + - "crypto_openssl" # The machine running the DPDK test executable - system_under_test_node: - node_name: "SUT 1" - vdevs: # optional; if removed, vdevs won't be used in the test run - - "crypto_openssl" - # Traffic generator node to use for this test run + system_under_test_node: "SUT 1" + # Traffic generator node to use for this execution environment traffic_generator_node: "TG 1" nodes: # Define a system under test node, having two network ports physically @@ -40,11 +39,6 @@ nodes: hostname: sut1.change.me.localhost user: dtsuser os: linux - lcores: "" # use all available logical cores (Skips first core) - memory_channels: 4 # tells DPDK to use 4 memory channels - hugepages_2mb: # optional; if removed, will use system hugepage configuration - number_of: 256 - force_first_numa: false ports: # sets up the physical link between "SUT 1"@0000:00:08.0 and "TG 1"@0000:00:08.0 - pci: "0000:00:08.0" @@ -58,6 +52,12 @@ nodes: os_driver: i40e peer_node: "TG 1" peer_pci: "0000:00:08.1" + hugepages_2mb: # optional; if removed, will use system hugepage configuration + number_of: 256 + force_first_numa: false + dpdk_config: + lcores: "" # use all available logical cores (Skips first core) + memory_channels: 4 # tells DPDK to use 4 memory channels # Define a Scapy traffic generator node, having two network ports # physically connected to the corresponding ports in SUT 1 (the peer node). - name: "TG 1" diff --git a/dts/framework/config/__init__.py b/dts/framework/config/__init__.py index 5dfa0cf0d4..2496f48e20 100644 --- a/dts/framework/config/__init__.py +++ b/dts/framework/config/__init__.py @@ -161,15 +161,23 @@ class NodeConfiguration(FrozenModel): password: str | None = None #: The operating system of the :class:`~framework.testbed_model.node.Node`. os: OS - #: A comma delimited list of logical cores to use when running DPDK. ```any```, an empty - #: string or omitting this field means use any core except for the first one. The first core - #: will only be used if explicitly set. - lcores: LogicalCores = "" #: An optional hugepage configuration. hugepages: HugepageConfiguration | None = Field(None, alias="hugepages_2mb") #: The ports that can be used in testing. ports: list[PortConfig] = Field(min_length=1) + +class DPDKConfiguration(FrozenModel): + """Configuration of the DPDK EAL parameters.""" + + #: A comma delimited list of logical cores to use when running DPDK. ```any```, an empty + #: string or omitting this field means use any core except for the first one. The first core + #: will only be used if explicitly set. + lcores: LogicalCores = "" + + #: The number of memory channels to use when running DPDK. + memory_channels: int = 1 + @property def use_first_core(self) -> bool: """Returns :data:`True` if `lcores` explicitly selects the first core.""" @@ -179,8 +187,8 @@ def use_first_core(self) -> bool: class SutNodeConfiguration(NodeConfiguration): """:class:`~framework.testbed_model.sut_node.SutNode` specific configuration.""" - #: The number of memory channels to use when running DPDK. - memory_channels: int = 1 + #: The runtime configuration for DPDK. + dpdk_config: DPDKConfiguration class TGNodeConfiguration(NodeConfiguration): @@ -405,15 +413,6 @@ def validate_names(self) -> Self: return self -class TestRunSUTNodeConfiguration(FrozenModel): - """The SUT node configuration of a test run.""" - - #: The SUT node to use in this test run. - node_name: str - #: The names of virtual devices to test. - vdevs: list[str] = Field(default_factory=list) - - class TestRunConfiguration(FrozenModel): """The configuration of a test run. @@ -431,10 +430,12 @@ class TestRunConfiguration(FrozenModel): skip_smoke_tests: bool = False #: The names of test suites and/or test cases to execute. test_suites: list[TestSuiteConfig] = Field(min_length=1) - #: The SUT node configuration to use in this test run. - system_under_test_node: TestRunSUTNodeConfiguration + #: The SUT node name to use in this test run. + system_under_test_node: str #: The TG node name to use in this test run. traffic_generator_node: str + #: The names of virtual devices to test. + vdevs: list[str] = Field(default_factory=list) #: The seed to use for pseudo-random generation. random_seed: int | None = None @@ -464,12 +465,12 @@ def test_runs_with_nodes(self) -> list[TestRunWithNodesConfiguration]: test_runs_with_nodes = [] for test_run_no, test_run in enumerate(self.test_runs): - sut_node_name = test_run.system_under_test_node.node_name + sut_node_name = test_run.system_under_test_node sut_node = next(filter(lambda n: n.name == sut_node_name, self.nodes), None) assert sut_node is not None, ( f"test_runs.{test_run_no}.sut_node_config.node_name " - f"({test_run.system_under_test_node.node_name}) is not a valid node name" + f"({test_run.system_under_test_node}) is not a valid node name" ) assert isinstance(sut_node, SutNodeConfiguration), ( f"test_runs.{test_run_no}.sut_node_config.node_name is a valid node name, " diff --git a/dts/framework/runner.py b/dts/framework/runner.py index 510be1a870..0cdbb07e06 100644 --- a/dts/framework/runner.py +++ b/dts/framework/runner.py @@ -277,7 +277,7 @@ def _connect_nodes_and_run_test_run( tg_node = TGNode(tg_node_config) tg_nodes[tg_node.name] = tg_node except Exception as e: - failed_node = test_run_config.system_under_test_node.node_name + failed_node = test_run_config.system_under_test_node if sut_node: failed_node = test_run_config.traffic_generator_node self._logger.exception(f"The Creation of node {failed_node} failed.") @@ -315,9 +315,7 @@ def _run_test_run( Raises: ConfigurationError: If the DPDK sources or build is not set up from config or settings. """ - self._logger.info( - f"Running test run with SUT '{test_run_config.system_under_test_node.node_name}'." - ) + self._logger.info(f"Running test run with SUT '{test_run_config.system_under_test_node}'.") test_run_result.ports = sut_node.ports test_run_result.sut_info = sut_node.node_info try: diff --git a/dts/framework/testbed_model/cpu.py b/dts/framework/testbed_model/cpu.py index d19fa5d597..b8bc601c22 100644 --- a/dts/framework/testbed_model/cpu.py +++ b/dts/framework/testbed_model/cpu.py @@ -185,7 +185,6 @@ def __init__( # sorting by core is needed in case hyperthreading is enabled self._lcores_to_filter = sorted(lcore_list, key=lambda x: x.core, reverse=not ascending) - self.filter() @abstractmethod def filter(self) -> list[LogicalCore]: @@ -228,6 +227,8 @@ def filter(self) -> list[LogicalCore]: Returns: The filtered cores. """ + if 0 in self._lcores_to_filter: + self._lcores_to_filter = self._lcores_to_filter[1:] sockets_to_filter = self._filter_sockets(self._lcores_to_filter) filtered_lcores = [] for socket_to_filter in sockets_to_filter: @@ -356,6 +357,9 @@ def filter(self) -> list[LogicalCore]: Raises: ValueError: If the specified lcore filter specifier is invalid. """ + if 0 not in self._filter_specifier.lcore_list: + self._lcores_to_filter = self._lcores_to_filter[1:] + if not len(self._filter_specifier.lcore_list): return self._lcores_to_filter diff --git a/dts/framework/testbed_model/linux_session.py b/dts/framework/testbed_model/linux_session.py index bda2d448f7..396bdbd890 100644 --- a/dts/framework/testbed_model/linux_session.py +++ b/dts/framework/testbed_model/linux_session.py @@ -67,15 +67,12 @@ class LinuxSession(PosixSession): def _get_privileged_command(command: str) -> str: return f"sudo -- sh -c '{command}'" - def get_remote_cpus(self, use_first_core: bool) -> list[LogicalCore]: + def get_remote_cpus(self) -> list[LogicalCore]: """Overrides :meth:`~.os_session.OSSession.get_remote_cpus`.""" cpu_info = self.send_command("lscpu -p=CPU,CORE,SOCKET,NODE|grep -v \\#").stdout lcores = [] for cpu_line in cpu_info.splitlines(): lcore, core, socket, node = map(int, cpu_line.split(",")) - if core == 0 and socket == 0 and not use_first_core: - self._logger.info("Not using the first physical core.") - continue lcores.append(LogicalCore(lcore, core, socket, node)) return lcores diff --git a/dts/framework/testbed_model/node.py b/dts/framework/testbed_model/node.py index b08b1cf14d..6c2dfd6185 100644 --- a/dts/framework/testbed_model/node.py +++ b/dts/framework/testbed_model/node.py @@ -24,14 +24,7 @@ from framework.exception import ConfigurationError from framework.logger import DTSLogger, get_dts_logger -from .cpu import ( - Architecture, - LogicalCore, - LogicalCoreCount, - LogicalCoreList, - LogicalCoreListFilter, - lcore_filter, -) +from .cpu import Architecture, LogicalCore, LogicalCoreCount, LogicalCoreList, lcore_filter from .linux_session import LinuxSession from .os_session import OSSession from .port import Port @@ -82,24 +75,8 @@ def __init__(self, node_config: NodeConfiguration): self._logger = get_dts_logger(self.name) self.main_session = create_session(self.config, self.name, self._logger) self.arch = Architecture(self.main_session.get_arch_info()) - self._logger.info(f"Connected to node: {self.name}") - self._get_remote_cpus() - # filter the node lcores according to the test run configuration - self.lcores = LogicalCoreListFilter( - self.lcores, LogicalCoreList(self.config.lcores) - ).filter() - - if LogicalCore(lcore=0, core=0, socket=0, node=0) in self.lcores: - self._logger.info( - """ - WARNING: First core being used; - using the first core is considered risky and should only - be done by advanced users. - """ - ) - self._other_sessions = [] self._init_ports() @@ -188,7 +165,7 @@ def filter_lcores( def _get_remote_cpus(self) -> None: """Scan CPUs in the remote OS and store a list of LogicalCores.""" self._logger.info("Getting CPU information.") - self.lcores = self.main_session.get_remote_cpus(self.config.use_first_core) + self.lcores = self.main_session.get_remote_cpus() def _setup_hugepages(self) -> None: """Setup hugepages on the node. diff --git a/dts/framework/testbed_model/os_session.py b/dts/framework/testbed_model/os_session.py index fcda9b3de1..e436886692 100644 --- a/dts/framework/testbed_model/os_session.py +++ b/dts/framework/testbed_model/os_session.py @@ -445,7 +445,7 @@ def get_dpdk_version(self, version_path: str | PurePath) -> str: """ @abstractmethod - def get_remote_cpus(self, use_first_core: bool) -> list[LogicalCore]: + def get_remote_cpus(self) -> list[LogicalCore]: r"""Get the list of :class:`~.cpu.LogicalCore`\s on the remote node. Args: diff --git a/dts/framework/testbed_model/sut_node.py b/dts/framework/testbed_model/sut_node.py index 11d4b22089..d8f1f9d452 100644 --- a/dts/framework/testbed_model/sut_node.py +++ b/dts/framework/testbed_model/sut_node.py @@ -33,6 +33,7 @@ from framework.remote_session.remote_session import CommandResult from framework.utils import MesonArgs, TarCompressionFormat +from .cpu import LogicalCore, LogicalCoreList from .node import Node from .os_session import OSSession, OSSessionInfo from .virtual_device import VirtualDevice @@ -92,6 +93,17 @@ def __init__(self, node_config: SutNodeConfiguration): node_config: The SUT node's test run configuration. """ super().__init__(node_config) + self.lcores = self.filter_lcores(LogicalCoreList(self.config.dpdk_config.lcores)) + if LogicalCore(lcore=0, core=0, socket=0, node=0) in self.lcores: + self._logger.info( + """ + WARNING: First core being used; + using the first core is considered risky and should only + be done by advanced users. + """ + ) + else: + self._logger.info("Not using first core") self.virtual_devices = [] self.dpdk_prefix_list = [] self._env_vars = {} @@ -198,7 +210,7 @@ def set_up_test_run( dpdk_build_config: The build configuration of DPDK. """ super().set_up_test_run(test_run_config, dpdk_build_config) - for vdev in test_run_config.system_under_test_node.vdevs: + for vdev in test_run_config.vdevs: self.virtual_devices.append(VirtualDevice(vdev)) self._set_up_dpdk(dpdk_build_config) -- 2.43.0