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 8BF324559C; Fri, 5 Jul 2024 20:32:48 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 77356410FD; Fri, 5 Jul 2024 20:32:48 +0200 (CEST) Received: from mail-qv1-f45.google.com (mail-qv1-f45.google.com [209.85.219.45]) by mails.dpdk.org (Postfix) with ESMTP id 4CB41410F2 for ; Fri, 5 Jul 2024 20:32:47 +0200 (CEST) Received: by mail-qv1-f45.google.com with SMTP id 6a1803df08f44-6b5e6b23577so2508356d6.3 for ; Fri, 05 Jul 2024 11:32:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1720204366; x=1720809166; darn=dpdk.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=oODAuiVQecsgeP3rA3WM0BXIV13zpPlKhISisvICxl4=; b=Ox+mtQmZ5sYI9Kjm5VqZbYEV3VgeR0qeZoAQHn//ws0l7bxFusIhyqLtMC/XfO4Edi Lw8QFJD3KuRIiBoww1+fIh1ntt1lsa57+joKACOIFa75neWBKvDgJB9WPUSSLItI58aF bYHduWOKSx5be5jbjUOYq6NVxtKHpKldZ73AM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720204366; x=1720809166; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oODAuiVQecsgeP3rA3WM0BXIV13zpPlKhISisvICxl4=; b=bXj3PUSFTEhbuIvUjFRxwXEFIoJgKz3WXWtgGxKPaO/X9dM5bCH1IOX/UN6FqI/KY2 Y6ek7bCizK4joMFTEJ2iurk/a+X26n3uU5U0gwG+hvpgBmMLIGEjDJ9zEoyV3H+/0x2B ba2jnxBalo6LPWXcXWeKsTMzvF7eroFZHp8ZM9gcpYLG3U1GqO2fijrAncfmJGQxJZLr WFA7X+Tq+VNg4qC4eRYflgQHSMu+tick3FOdkJOf3oIyvB91Z9jJs2pU2eIsuum3pmc4 25K/mCHvIEHN/hgy8Rc2NrmmtxM1iy7Q6cSdE0Yn+PY9MnReoefz8aEdNEtiWPSzpHch 2F5Q== X-Gm-Message-State: AOJu0YzORQe+fbWqj2TQPX4gBec4Rep+NyEvfGeLCcWDQ6H29OvhM2mM M1aVp0FQTI2tFEyNgmkxXy6AkO/B7lRGCLI9cN5wShZEqY8kbuBLuaYs0RGQAmA= X-Google-Smtp-Source: AGHT+IHwHzMRyDNjDCHygtUdC8eCIE4bq38M20V55mVDBk2BRFTUQqgAkvhKSuyKCTRfke1Oz0ogmA== X-Received: by 2002:a05:6214:19ca:b0:6b2:b621:559c with SMTP id 6a1803df08f44-6b5ed22409amr56825376d6.4.1720204366589; Fri, 05 Jul 2024 11:32:46 -0700 (PDT) Received: from localhost.unh.edu ([2606:4100:3880:1257::1003]) by smtp.gmail.com with ESMTPSA id 6a1803df08f44-6b5eb6309fcsm18469286d6.133.2024.07.05.11.32.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Jul 2024 11:32:45 -0700 (PDT) From: Nicholas Pratte To: dmarx@iol.unh.edu, paul.szczepanek@arm.com, juraj.linkes@pantheon.tech, yoan.picchi@foss.arm.com, jspewock@iol.unh.edu, luca.vizzarro@arm.com, probb@iol.unh.edu, Honnappa.Nagarahalli@arm.com Cc: dev@dpdk.org, Nicholas Pratte Subject: [PATCH v2 4/6] dts: Rework DPDK Attributes In SUT Node Config Date: Fri, 5 Jul 2024 14:32:35 -0400 Message-ID: <20240705183234.31333-2-npratte@iol.unh.edu> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240705171341.23894-2-npratte@iol.unh.edu> References: <20240705171341.23894-2-npratte@iol.unh.edu> 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 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 'executions.' Bugzilla ID: 1360 Signed-off-by: Nicholas Pratte --- dts/conf.yaml | 20 ++++----- dts/framework/config/__init__.py | 45 +++++++++++-------- dts/framework/config/conf_yaml_schema.json | 47 ++++++++++---------- dts/framework/config/types.py | 21 ++++++--- dts/framework/testbed_model/cpu.py | 6 ++- dts/framework/testbed_model/linux_session.py | 5 +-- dts/framework/testbed_model/node.py | 26 +---------- dts/framework/testbed_model/os_session.py | 2 +- dts/framework/testbed_model/sut_node.py | 12 +++++ 9 files changed, 95 insertions(+), 89 deletions(-) diff --git a/dts/conf.yaml b/dts/conf.yaml index 7ca4c05b55..bb1fbc86e3 100644 --- a/dts/conf.yaml +++ b/dts/conf.yaml @@ -14,12 +14,11 @@ test_runs: test_suites: # the following test suites will be run in their entirety - hello_world - os_udp + 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 @@ -28,11 +27,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"@000:00:08.0 and "TG 1"@0000:00:08.0 - pci: "0000:00:08.0" @@ -46,6 +40,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 662b3070a1..ed1c979fb6 100644 --- a/dts/framework/config/__init__.py +++ b/dts/framework/config/__init__.py @@ -209,8 +209,6 @@ class NodeConfiguration: password: The password of the user. The use of passwords is heavily discouraged. Please use keys instead. os: The operating system of the :class:`~framework.testbed_model.node.Node`. - lcores: A comma delimited list of logical cores to use when running DPDK. - use_first_core: If :data:`True`, the first logical core won't be used. hugepages: An optional hugepage configuration. ports: The ports that can be used in testing. """ @@ -220,8 +218,6 @@ class NodeConfiguration: user: str password: str | None os: OS - lcores: str - use_first_core: bool hugepages: HugepageConfiguration | None ports: list[PortConfig] @@ -244,9 +240,6 @@ def from_dict( hugepage_config_dict["force_first_numa"] = False hugepage_config = HugepageConfiguration(**hugepage_config_dict) - lcores = "1" if "lcores" not in d else d["lcores"] if "any" not in d["lcores"] else "" - use_first_core = "0" in lcores - # The calls here contain duplicated code which is here because Mypy doesn't # properly support dictionary unpacking with TypedDicts if "traffic_generator" in d: @@ -256,36 +249,54 @@ def from_dict( user=d["user"], password=d.get("password"), os=OS(d["os"]), - lcores=lcores, - use_first_core=use_first_core, hugepages=hugepage_config, ports=[PortConfig.from_dict(d["name"], port) for port in d["ports"]], traffic_generator=TrafficGeneratorConfig.from_dict(d["traffic_generator"]), ) else: + dpdk_config = d["dpdk_config"] + dpdk_config["lcores"] = ( + "1" + if "lcores" not in dpdk_config + else dpdk_config["lcores"] + if "any" not in dpdk_config["lcores"] + else "" + ) + dpdk_config["memory_channels"] = dpdk_config.get("memory_channels", 1) return SutNodeConfiguration( name=d["name"], hostname=d["hostname"], user=d["user"], password=d.get("password"), os=OS(d["os"]), - lcores=lcores, - use_first_core=use_first_core, + dpdk_config=DPDKConfig(**dpdk_config), hugepages=hugepage_config, ports=[PortConfig.from_dict(d["name"], port) for port in d["ports"]], - memory_channels=d.get("memory_channels", 1), ) +@dataclass(slots=True, frozen=True) +class DPDKConfig: + """EAL parameters for executing and running DPDK. + + Attributes: + lcores: Logical cores to be used for DPDK execution. + memory_channels: Memory channels to be used for DPDK execution. + """ + + lcores: str + memory_channels: int + + @dataclass(slots=True, frozen=True) class SutNodeConfiguration(NodeConfiguration): """:class:`~framework.testbed_model.sut_node.SutNode` specific configuration. Attributes: - memory_channels: The number of memory channels to use when running DPDK. + dpdk_config: DPDK configuration attributes to be used during execution. """ - memory_channels: int + dpdk_config: DPDKConfig @dataclass(slots=True, frozen=True) @@ -450,7 +461,7 @@ def from_dict( map(BuildTargetConfiguration.from_dict, d["build_targets"]) ) test_suites: list[TestSuiteConfig] = list(map(TestSuiteConfig.from_dict, d["test_suites"])) - sut_name = d["system_under_test_node"]["node_name"] + sut_name = d["system_under_test_node"] skip_smoke_tests = d.get("skip_smoke_tests", False) assert sut_name in node_map, f"Unknown SUT {sut_name} in test run {d}" system_under_test_node = node_map[sut_name] @@ -465,9 +476,7 @@ def from_dict( traffic_generator_node, TGNodeConfiguration ), f"Invalid TG configuration {traffic_generator_node}" - vdevs = ( - d["system_under_test_node"]["vdevs"] if "vdevs" in d["system_under_test_node"] else [] - ) + vdevs = d["vdevs"] if "vdevs" in d else [] return cls( build_targets=build_targets, perf=d["perf"], diff --git a/dts/framework/config/conf_yaml_schema.json b/dts/framework/config/conf_yaml_schema.json index e65ea45058..b31f4d8dbe 100644 --- a/dts/framework/config/conf_yaml_schema.json +++ b/dts/framework/config/conf_yaml_schema.json @@ -150,14 +150,21 @@ "os": { "$ref": "#/definitions/OS" }, - "lcores": { - "type": "string", - "pattern": "^(([0-9]+|([0-9]+-[0-9]+))(,([0-9]+|([0-9]+-[0-9]+)))*)?$|any", - "description": "Optional comma-separated list of logical cores to use, e.g.: 1,2,3,4,5,18-22. Defaults to 1. An empty string means use all lcores." - }, - "memory_channels": { - "type": "integer", - "description": "How many memory channels to use. Optional, defaults to 1." + "dpdk_config": { + "type": "object", + "description": "EAL arguments for DPDK execution", + "properties": { + "lcores": { + "type": "string", + "pattern": "^(([0-9]+|([0-9]+-[0-9]+))(,([0-9]+|([0-9]+-[0-9]+)))*)?$|any", + "description": "Optional comma-separated list of logical cores to use, e.g.: 1,2,3,4,5,18-22. Defaults to 1. An empty string means use all lcores." + }, + "memory_channels": { + "type": "integer", + "description": "How many memory channels to use. Optional, defaults to 1." + } + }, + "minimum": 1 }, "hugepages_2mb": { "$ref": "#/definitions/hugepages_2mb" @@ -264,23 +271,15 @@ "description": "Optional field that allows you to skip smoke testing", "type": "boolean" }, + "vdevs": { + "description": "Optional list of names of vdevs to be used in execution", + "type": "array", + "items": { + "type": "string" + } + }, "system_under_test_node": { - "type":"object", - "properties": { - "node_name": { - "$ref": "#/definitions/node_name" - }, - "vdevs": { - "description": "Optional list of names of vdevs to be used in the test run", - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "node_name" - ] + "$ref": "#/definitions/node_name" }, "traffic_generator_node": { "$ref": "#/definitions/node_name" diff --git a/dts/framework/config/types.py b/dts/framework/config/types.py index 9934fef503..004fc2b2d3 100644 --- a/dts/framework/config/types.py +++ b/dts/framework/config/types.py @@ -33,6 +33,15 @@ class TrafficGeneratorConfigDict(TypedDict): type: str +class DPDKConfigDict(TypedDict): + """Allowed keys and values.""" + + #: + memory_channels: int + #: + lcores: str + + class HugepageConfigurationDict(TypedDict): """Allowed keys and values.""" @@ -58,15 +67,11 @@ class NodeConfigDict(TypedDict): #: os: str #: - lcores: str - #: - use_first_core: bool - #: ports: list[PortConfigDict] #: - memory_channels: int - #: traffic_generator: TrafficGeneratorConfigDict + #: + dpdk_config: DPDKConfigDict class BuildTargetConfigDict(TypedDict): @@ -110,9 +115,11 @@ class TestRunConfigDict(TypedDict): #: test_suites: TestSuiteConfigDict #: - system_under_test_node: TestRunSUTConfigDict + system_under_test_node: str #: traffic_generator_node: str + #: + vdevs: list[str] class ConfigurationDict(TypedDict): diff --git a/dts/framework/testbed_model/cpu.py b/dts/framework/testbed_model/cpu.py index a50cf44c19..cc4ca40ad9 100644 --- a/dts/framework/testbed_model/cpu.py +++ b/dts/framework/testbed_model/cpu.py @@ -167,7 +167,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]: @@ -210,6 +209,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: @@ -328,6 +329,9 @@ def filter(self) -> list[LogicalCore]: Return: The filtered logical CPU cores. """ + 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 99abc21353..347d01878c 100644 --- a/dts/framework/testbed_model/linux_session.py +++ b/dts/framework/testbed_model/linux_session.py @@ -68,15 +68,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 09399f4823..9630407247 100644 --- a/dts/framework/testbed_model/node.py +++ b/dts/framework/testbed_model/node.py @@ -22,13 +22,7 @@ from framework.logger import DTSLogger, get_dts_logger from framework.settings import SETTINGS -from .cpu import ( - LogicalCore, - LogicalCoreCount, - LogicalCoreList, - LogicalCoreListFilter, - lcore_filter, -) +from .cpu import LogicalCore, LogicalCoreCount, LogicalCoreList, lcore_filter from .linux_session import LinuxSession from .os_session import OSSession from .port import Port @@ -79,24 +73,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() @@ -182,7 +160,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 02277eee1f..f217a40e7f 100644 --- a/dts/framework/testbed_model/os_session.py +++ b/dts/framework/testbed_model/os_session.py @@ -280,7 +280,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 a4511157b7..178535b617 100644 --- a/dts/framework/testbed_model/sut_node.py +++ b/dts/framework/testbed_model/sut_node.py @@ -29,6 +29,7 @@ from framework.settings import SETTINGS from framework.utils import MesonArgs +from .cpu import LogicalCore, LogicalCoreList from .node import Node from .os_session import OSSession from .virtual_device import VirtualDevice @@ -75,6 +76,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._build_target_config = None -- 2.44.0