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 BBC6245C88; Tue, 5 Nov 2024 17:58:16 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 1BCBA427BC; Tue, 5 Nov 2024 17:58:13 +0100 (CET) Received: from mail-qt1-f174.google.com (mail-qt1-f174.google.com [209.85.160.174]) by mails.dpdk.org (Postfix) with ESMTP id D540440151 for ; Tue, 5 Nov 2024 17:58:10 +0100 (CET) Received: by mail-qt1-f174.google.com with SMTP id d75a77b69052e-460d1145cd8so38661191cf.3 for ; Tue, 05 Nov 2024 08:58:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iol.unh.edu; s=unh-iol; t=1730825890; x=1731430690; 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=4D5ioURsej0QGf1NBsyvUaAPQHQsqfaa64Utj2BMk8A=; b=gsyMLcDIZUOIg2Sl4qeYzfowJz8j04LSTU1RK5gRrv/eI6EjulSUAdWkFKdd8PxNvX NbaUI7SszyAJO45pkCRx1tRf/WR833g5krWDJUCzuxqwUFLxCy6EuLC8IsxPlg8j5jGJ pIKDZX6vGgt2u/BKhW4EzXvMKFqSqn8D2J8LQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730825890; x=1731430690; 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=4D5ioURsej0QGf1NBsyvUaAPQHQsqfaa64Utj2BMk8A=; b=JK3m4KGWim6hSzvt/Ipd47eibIM1FSvdY8CpoK7oV6yZR7pxbpmeILELBFM2cLOKmF Aco8dJ7qRhmfeGbKezBaOz0rIHsJOPSQTRfv+5YdXHqNpNXvb3fRLdmZiB5FaUlWxekX L+ZAJyIvJgtGMO9vbzbAdVQGGBo63D8d8BZU2CZOwDtvZDSJI3VVeNev0RecFVoZMLXx OC45leljtw3p7ACqbjoanMYGcJN2b0Q1WCjUInPsUHjAyS8hn99gDiyMGm2H7+F9i0Eq HhlsLTHFSQSZ9Tyl8BLTL2lCGq6dfWyToF/jGhhFI8j8jpPr/i+61be3HMtTbm3SuvE3 hwxQ== X-Gm-Message-State: AOJu0YyOylGmCgGDRd3oRoVWa0fH+8f1Uhc0rAQVD78LUv4I/eEVirk8 ZKH6QC69WKqzRAg41RESmJg4fzCx8/ThBA2bZ63pXmdVqULj1H0KbqFeSEFLS2E= X-Google-Smtp-Source: AGHT+IEUMthUsJhV1irGmkqieH4y3kQgAomRmErVeMNIm0+yc+EonhSUil7mWUEfvIVbuaa5FBozUQ== X-Received: by 2002:ac8:5987:0:b0:460:93b6:a4d1 with SMTP id d75a77b69052e-462b86a2d4cmr202335901cf.31.1730825890105; Tue, 05 Nov 2024 08:58:10 -0800 (PST) Received: from dean-laptop.iol.unh.edu ([2606:4100:3880:1271:f9bd:24da:464d:6294]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-462ad161597sm61017051cf.63.2024.11.05.08.58.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Nov 2024 08:58:09 -0800 (PST) From: Dean Marx To: probb@iol.unh.edu, npratte@iol.unh.edu, luca.vizzarro@arm.com, yoan.picchi@foss.arm.com, Honnappa.Nagarahalli@arm.com, paul.szczepanek@arm.com Cc: dev@dpdk.org, Dean Marx , Jeremy Spewock Subject: [PATCH v6 1/2] dts: add port queue modification and forwarding stats to testpmd Date: Tue, 5 Nov 2024 11:58:29 -0500 Message-ID: <20241105165830.15881-2-dmarx@iol.unh.edu> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20241105165830.15881-1-dmarx@iol.unh.edu> References: <20240925192013.17446-1-jspewock@iol.unh.edu> <20241105165830.15881-1-dmarx@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 This patch adds methods for querying and modifying port queue state and configuration. In addition to this, it also adds the ability to capture the forwarding statistics that get outputted when you send the "stop" command in testpmd. Querying of port queue information is handled through a TextParser dataclass in case there is future need for using more of the output from the command used to query the information. Signed-off-by: Jeremy Spewock Signed-off-by: Dean Marx --- dts/framework/remote_session/testpmd_shell.py | 216 +++++++++++++++--- 1 file changed, 182 insertions(+), 34 deletions(-) diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py index 16b41a7814..995ba17ec4 100644 --- a/dts/framework/remote_session/testpmd_shell.py +++ b/dts/framework/remote_session/testpmd_shell.py @@ -425,7 +425,46 @@ def make_parser(cls) -> ParserFn: @dataclass -class TestPmdRxqInfo(TextParser): +class TestPmdQueueInfo(TextParser): + """Dataclass representation of the common parts of the testpmd `show rxq/txq info` commands.""" + + #: + prefetch_threshold: int = field(metadata=TextParser.find_int(r"prefetch threshold: (\d+)")) + #: + host_threshold: int = field(metadata=TextParser.find_int(r"host threshold: (\d+)")) + #: + writeback_threshold: int = field(metadata=TextParser.find_int(r"writeback threshold: (\d+)")) + #: + free_threshold: int = field(metadata=TextParser.find_int(r"free threshold: (\d+)")) + #: + deferred_start: bool = field(metadata=TextParser.find("deferred start: on")) + #: The number of RXD/TXDs is just the ring size of the queue. + ring_size: int = field(metadata=TextParser.find_int(r"Number of (?:RXDs|TXDs): (\d+)")) + #: + is_queue_started: bool = field(metadata=TextParser.find("queue state: started")) + #: + burst_mode: str | None = field( + default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)") + ) + + +@dataclass +class TestPmdTxqInfo(TestPmdQueueInfo): + """Representation of testpmd's ``show txq info `` command. + + References: + testpmd command function: ``app/test-pmd/cmdline.c:cmd_showqueue()`` + testpmd display function: ``app/test-pmd/config.c:rx_queue_infos_display()`` + """ + + #: Ring size threshold + rs_threshold: int | None = field( + default=None, metadata=TextParser.find_int(r"TX RS threshold: (\d+)\b") + ) + + +@dataclass +class TestPmdRxqInfo(TestPmdQueueInfo): """Representation of testpmd's ``show rxq info `` command. References: @@ -433,42 +472,18 @@ class TestPmdRxqInfo(TextParser): testpmd display function: ``app/test-pmd/config.c:rx_queue_infos_display()`` """ - #: - port_id: int = field(metadata=TextParser.find_int(r"Infos for port (\d+)\b ?, RX queue \d+\b")) - #: - queue_id: int = field(metadata=TextParser.find_int(r"Infos for port \d+\b ?, RX queue (\d+)\b")) #: Mempool used by that queue - mempool: str = field(metadata=TextParser.find(r"Mempool: ([^\r\n]+)")) - #: Ring prefetch threshold - rx_prefetch_threshold: int = field( - metadata=TextParser.find_int(r"RX prefetch threshold: (\d+)\b") - ) - #: Ring host threshold - rx_host_threshold: int = field(metadata=TextParser.find_int(r"RX host threshold: (\d+)\b")) - #: Ring writeback threshold - rx_writeback_threshold: int = field( - metadata=TextParser.find_int(r"RX writeback threshold: (\d+)\b") - ) - #: Drives the freeing of Rx descriptors - rx_free_threshold: int = field(metadata=TextParser.find_int(r"RX free threshold: (\d+)\b")) + mempool: str | None = field(default=None, metadata=TextParser.find(r"Mempool: ([^\r\n]+)")) #: Drop packets if no descriptors are available - rx_drop_packets: bool = field(metadata=TextParser.find(r"RX drop packets: on")) - #: Do not start queue with rte_eth_dev_start() - rx_deferred_start: bool = field(metadata=TextParser.find(r"RX deferred start: on")) - #: Scattered packets Rx enabled - rx_scattered_packets: bool = field(metadata=TextParser.find(r"RX scattered packets: on")) - #: The state of the queue - rx_queue_state: str = field(metadata=RxQueueState.make_parser()) - #: Configured number of RXDs - number_of_rxds: int = field(metadata=TextParser.find_int(r"Number of RXDs: (\d+)\b")) - #: Hardware receive buffer size - rx_buffer_size: int | None = field( - default=None, metadata=TextParser.find_int(r"RX buffer size: (\d+)\b") + drop_packets: bool | None = field( + default=None, metadata=TextParser.find(r"RX drop packets: on") ) - #: Burst mode information - burst_mode: str | None = field( - default=None, metadata=TextParser.find(r"Burst mode: ([^\r\n]+)") + #: Scattered packets Rx enabled + scattered_packets: bool | None = field( + default=None, metadata=TextParser.find(r"RX scattered packets: on") ) + #: The state of the queue + queue_state: str | None = field(default=None, metadata=RxQueueState.make_parser()) @dataclass @@ -1975,6 +1990,139 @@ def get_capabilities_rx_offload( rx_offload_capabilities.per_port | rx_offload_capabilities.per_queue, ) + def get_port_queue_info( + self, port_id: int, queue_id: int, is_rx_queue: bool + ) -> TestPmdQueueInfo: + """Returns the current state of the specified queue.""" + command = f"show {'rxq' if is_rx_queue else 'txq'} info {port_id} {queue_id}" + queue_info = TestPmdQueueInfo.parse(self.send_command(command)) + return queue_info + + def setup_port_queue(self, port_id: int, queue_id: int, is_rx_queue: bool) -> None: + """Setup a given queue on a port. + + This functionality cannot be verified because the setup action only takes effect when the + queue is started. + + Args: + port_id: ID of the port where the queue resides. + queue_id: ID of the queue to setup. + is_rx_queue: Type of queue to setup. If :data:`True` an RX queue will be setup, + otherwise a TX queue will be setup. + """ + self.send_command(f"port {port_id} {'rxq' if is_rx_queue else 'txq'} {queue_id} setup") + + def stop_port_queue( + self, port_id: int, queue_id: int, is_rx_queue: bool, verify: bool = True + ) -> None: + """Stops a given queue on a port. + + Args: + port_id: ID of the port that the queue belongs to. + queue_id: ID of the queue to stop. + is_rx_queue: Type of queue to stop. If :data:`True` an RX queue will be stopped, + otherwise a TX queue will be stopped. + verify: If :data:`True` an additional command will be sent to verify the queue stopped. + Defaults to :data:`True`. + + Raises: + InteractiveCommandExecutionError: If `verify` is :data:`True` and the queue fails to + stop. + """ + port_type = "rxq" if is_rx_queue else "txq" + stop_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} stop") + if verify: + queue_started = self.get_port_queue_info( + port_id, queue_id, is_rx_queue + ).is_queue_started + if queue_started: + self._logger.debug( + f"Failed to stop {port_type} {queue_id} on port {port_id}:\n{stop_cmd_output}" + ) + raise InteractiveCommandExecutionError( + f"Test pmd failed to stop {port_type} {queue_id} on port {port_id}" + ) + + def start_port_queue( + self, port_id: int, queue_id: int, is_rx_queue: bool, verify: bool = True + ) -> None: + """Starts a given queue on a port. + + First sets up the port queue, then starts it. + + Args: + port_id: ID of the port that the queue belongs to. + queue_id: ID of the queue to start. + is_rx_queue: Type of queue to start. If :data:`True` an RX queue will be started, + otherwise a TX queue will be started. + verify: if :data:`True` an additional command will be sent to verify that the queue was + started. Defaults to :data:`True`. + + Raises: + InteractiveCommandExecutionError: If `verify` is :data:`True` and the queue fails to + start. + """ + port_type = "rxq" if is_rx_queue else "txq" + self.setup_port_queue(port_id, queue_id, is_rx_queue) + start_cmd_output = self.send_command(f"port {port_id} {port_type} {queue_id} start") + if verify: + queue_started = self.get_port_queue_info( + port_id, queue_id, is_rx_queue + ).is_queue_started + if not queue_started: + self._logger.debug( + f"Failed to start {port_type} {queue_id} on port {port_id}:\n{start_cmd_output}" + ) + raise InteractiveCommandExecutionError( + f"Test pmd failed to start {port_type} {queue_id} on port {port_id}" + ) + + def get_queue_ring_size(self, port_id: int, queue_id: int, is_rx_queue: bool) -> int: + """Returns the current size of the ring on the specified queue.""" + command = f"show {'rxq' if is_rx_queue else 'txq'} info {port_id} {queue_id}" + queue_info = TestPmdQueueInfo.parse(self.send_command(command)) + return queue_info.ring_size + + def set_queue_ring_size( + self, + port_id: int, + queue_id: int, + size: int, + is_rx_queue: bool, + verify: bool = True, + ) -> None: + """Update the ring size of an Rx/Tx queue on a given port. + + Queue is setup after setting the ring size so that the queue info reflects this change and + it can be verified. + + Args: + port_id: The port that the queue resides on. + queue_id: The ID of the queue on the port. + size: The size to update the ring size to. + is_rx_queue: Whether to modify an RX or TX queue. If :data:`True` an RX queue will be + updated, otherwise a TX queue will be updated. + verify: If :data:`True` an additional command will be sent to check the ring size of + the queue in an attempt to validate that the size was changes properly. + + Raises: + InteractiveCommandExecutionError: If `verify` is :data:`True` and there is a failure + when updating ring size. + """ + queue_type = "rxq" if is_rx_queue else "txq" + self.send_command(f"port config {port_id} {queue_type} {queue_id} ring_size {size}") + self.setup_port_queue(port_id, queue_id, is_rx_queue) + if verify: + curr_ring_size = self.get_queue_ring_size(port_id, queue_id, is_rx_queue) + if curr_ring_size != size: + self._logger.debug( + f"Failed up update ring size of queue {queue_id} on port {port_id}. Current" + f" ring size is {curr_ring_size}." + ) + raise InteractiveCommandExecutionError( + f"Failed to update ring size of queue {queue_id} on port {port_id}" + ) + def _update_capabilities_from_flag( self, supported_capabilities: MutableSet["NicCapability"], @@ -2004,7 +2152,7 @@ def get_capabilities_rxq_info( self._logger.debug("Getting rxq capabilities.") command = f"show rxq info {self.ports[0].id} 0" rxq_info = TestPmdRxqInfo.parse(self.send_command(command)) - if rxq_info.rx_scattered_packets: + if rxq_info.scattered_packets: supported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED) else: unsupported_capabilities.add(NicCapability.SCATTERED_RX_ENABLED) -- 2.44.0