DPDK patches and discussions
 help / color / mirror / Atom feed
From: Tianli Lai <laitianli@tom.com>
To: dev@dpdk.org
Subject: [PATCH] examples/kni: add interrupt mode to receive packets
Date: Fri,  8 Apr 2022 17:02:52 +0800	[thread overview]
Message-ID: <20220408090252.3858-1-laitianli@tom.com> (raw)
In-Reply-To: <20220407161205.8633-1-laitianli@tom.com>

kni application have two main-loop threads that they
CPU utilization are up to 100 percent, this two theads are
writing thread and reading thread. I thank set interrupt mode
at reading thread would reduce this thread CPU utilization.

Signed-off-by: Tianli Lai <laitianli@tom.com>
---
 examples/kni/main.c | 135 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 128 insertions(+), 7 deletions(-)

diff --git a/examples/kni/main.c b/examples/kni/main.c
index e99ef5c38a..eb9a7ce863 100644
--- a/examples/kni/main.c
+++ b/examples/kni/main.c
@@ -75,6 +75,7 @@
 #define KNI_SECOND_PER_DAY      86400
 
 #define KNI_MAX_KTHREAD 32
+#define MIN_ZERO_POLL_COUNT		100
 /*
  * Structure of port parameters
  */
@@ -98,6 +99,8 @@ static struct rte_eth_conf port_conf = {
 	},
 };
 
+/* ethernet addresses of ports */
+static rte_spinlock_t locks[RTE_MAX_ETHPORTS];
 /* Mempool for mbufs */
 static struct rte_mempool * pktmbuf_pool = NULL;
 
@@ -107,6 +110,8 @@ static uint32_t ports_mask = 0;
 static int promiscuous_on = 0;
 /* Monitor link status continually. off by default. */
 static int monitor_links;
+/* rx set in interrupt mode off by default. */
+static int intr_rx_en;
 
 /* Structure type for recording kni interface specific stats */
 struct kni_interface_stats {
@@ -206,7 +211,7 @@ kni_burst_free_mbufs(struct rte_mbuf **pkts, unsigned num)
 /**
  * Interface to burst rx and enqueue mbufs into rx_q
  */
-static void
+static int
 kni_ingress(struct kni_port_params *p)
 {
 	uint8_t i;
@@ -214,9 +219,9 @@ kni_ingress(struct kni_port_params *p)
 	unsigned nb_rx, num;
 	uint32_t nb_kni;
 	struct rte_mbuf *pkts_burst[PKT_BURST_SZ];
-
+	int ret = 0;
 	if (p == NULL)
-		return;
+		return -1;
 
 	nb_kni = p->nb_kni;
 	port_id = p->port_id;
@@ -225,8 +230,10 @@ kni_ingress(struct kni_port_params *p)
 		nb_rx = rte_eth_rx_burst(port_id, 0, pkts_burst, PKT_BURST_SZ);
 		if (unlikely(nb_rx > PKT_BURST_SZ)) {
 			RTE_LOG(ERR, APP, "Error receiving from eth\n");
-			return;
+			return -1;
 		}
+		if (nb_rx == 0)
+			ret = 1;
 		/* Burst tx to kni */
 		num = rte_kni_tx_burst(p->kni[i], pkts_burst, nb_rx);
 		if (num)
@@ -239,6 +246,7 @@ kni_ingress(struct kni_port_params *p)
 			kni_stats[port_id].rx_dropped += nb_rx - num;
 		}
 	}
+	return ret;
 }
 
 /**
@@ -277,12 +285,95 @@ kni_egress(struct kni_port_params *p)
 	}
 }
 
+/**
+ * force polling thread sleep until one-shot rx interrupt triggers
+ * @param port_id
+ *  Port id.
+ * @param queue_id
+ *  Rx queue id.
+ * @return
+ *  0 on success
+ */
+static int
+sleep_until_rx_interrupt(int num, int lcore)
+{
+	/*
+	 * we want to track when we are woken up by traffic so that we can go
+	 * back to sleep again without log spamming. Avoid cache line sharing
+	 * to prevent threads stepping on each others' toes.
+	 */
+	static struct {
+		bool wakeup;
+	} __rte_cache_aligned status[RTE_MAX_LCORE];
+	struct rte_epoll_event event[num];
+	int n, i;
+	uint16_t port_id;
+	uint8_t queue_id;
+	void *data;
+
+	if (status[lcore].wakeup) {
+		RTE_LOG(INFO, APP,
+				"lcore %u sleeps until interrupt triggers\n",
+				rte_lcore_id());
+	}
+
+	n = rte_epoll_wait(RTE_EPOLL_PER_THREAD, event, num, 10);
+	for (i = 0; i < n; i++) {
+		data = event[i].epdata.data;
+		port_id = ((uintptr_t)data) >> CHAR_BIT;
+		queue_id = ((uintptr_t)data) &
+			RTE_LEN2MASK(CHAR_BIT, uint8_t);
+		RTE_LOG(INFO, APP,
+			"lcore %u is waked up from rx interrupt on"
+			" port %d queue %d\n",
+			rte_lcore_id(), port_id, queue_id);
+	}
+	status[lcore].wakeup = n != 0;
+
+	return 0;
+}
+
+static void
+turn_on_off_intr(uint16_t port_id, uint16_t queue_id, bool on)
+{
+	rte_spinlock_lock(&(locks[port_id]));
+	if (on)
+		rte_eth_dev_rx_intr_enable(port_id, queue_id);
+	else
+		rte_eth_dev_rx_intr_disable(port_id, queue_id);
+	rte_spinlock_unlock(&(locks[port_id]));
+}
+
+static int event_register(void)
+{
+	uint8_t queueid;
+	uint16_t portid;
+	uint32_t data;
+	int ret;
+
+	portid = 0;
+	queueid = 0;
+	data = portid << CHAR_BIT | queueid;
+
+	ret = rte_eth_dev_rx_intr_ctl_q(portid, queueid,
+					RTE_EPOLL_PER_THREAD,
+					RTE_INTR_EVENT_ADD,
+					(void *)((uintptr_t)data));
+	if (ret)
+		return ret;
+
+
+	return 0;
+}
+
 static int
 main_loop(__rte_unused void *arg)
 {
 	uint16_t i;
 	int32_t f_stop;
 	int32_t f_pause;
+	int ret = 0;
+	uint32_t zero_rx_packet_count = 0;
 	const unsigned lcore_id = rte_lcore_id();
 	enum lcore_rxtx {
 		LCORE_NONE,
@@ -291,12 +382,19 @@ main_loop(__rte_unused void *arg)
 		LCORE_MAX
 	};
 	enum lcore_rxtx flag = LCORE_NONE;
+	int intr_en = 0;
 
 	RTE_ETH_FOREACH_DEV(i) {
 		if (!kni_port_params_array[i])
 			continue;
+		/* initialize spinlock for each port */
+		rte_spinlock_init(&(locks[i]));
 		if (kni_port_params_array[i]->lcore_rx == (uint8_t)lcore_id) {
 			flag = LCORE_RX;
+			if (intr_rx_en && !event_register())
+				intr_en = 1;
+			else
+				RTE_LOG(INFO, APP, "RX interrupt won't enable.\n");
 			break;
 		} else if (kni_port_params_array[i]->lcore_tx ==
 						(uint8_t)lcore_id) {
@@ -316,7 +414,24 @@ main_loop(__rte_unused void *arg)
 				break;
 			if (f_pause)
 				continue;
-			kni_ingress(kni_port_params_array[i]);
+			ret = kni_ingress(kni_port_params_array[i]);
+			if (ret == 1) {
+				zero_rx_packet_count++;
+				if (zero_rx_packet_count <=
+						MIN_ZERO_POLL_COUNT)
+					continue;
+			} else
+				zero_rx_packet_count = 0;
+
+			if (zero_rx_packet_count > 0) {
+				zero_rx_packet_count = 0;
+				if (unlikely(intr_en)) {
+					turn_on_off_intr(i, 0, 1);
+					sleep_until_rx_interrupt(1, lcore_id);
+					turn_on_off_intr(i, 0, 0);
+				}
+			}
 		}
 	} else if (flag == LCORE_TX) {
 		RTE_LOG(INFO, APP, "Lcore %u is writing to port %d\n",
@@ -341,12 +456,13 @@ main_loop(__rte_unused void *arg)
 static void
 print_usage(const char *prgname)
 {
-	RTE_LOG(INFO, APP, "\nUsage: %s [EAL options] -- -p PORTMASK -P -m "
+	RTE_LOG(INFO, APP, "\nUsage: %s [EAL options] -- -p PORTMASK -P -m -I "
 		   "[--config (port,lcore_rx,lcore_tx,lcore_kthread...)"
 		   "[,(port,lcore_rx,lcore_tx,lcore_kthread...)]]\n"
 		   "    -p PORTMASK: hex bitmask of ports to use\n"
 		   "    -P : enable promiscuous mode\n"
 		   "    -m : enable monitoring of port carrier state\n"
+		   "    -I : enable rx interrupt mode\n"
 		   "    --config (port,lcore_rx,lcore_tx,lcore_kthread...): "
 		   "port and lcore configurations\n",
 	           prgname);
@@ -527,7 +643,7 @@ parse_args(int argc, char **argv)
 	opterr = 0;
 
 	/* Parse command line */
-	while ((opt = getopt_long(argc, argv, "p:Pm", longopts,
+	while ((opt = getopt_long(argc, argv, "p:PmI", longopts,
 						&longindex)) != EOF) {
 		switch (opt) {
 		case 'p':
@@ -539,6 +655,9 @@ parse_args(int argc, char **argv)
 		case 'm':
 			monitor_links = 1;
 			break;
+		case 'I':
+			intr_rx_en = 1;
+			break;
 		case 0:
 			if (!strncmp(longopts[longindex].name,
 				     CMDLINE_OPT_CONFIG,
@@ -610,6 +729,8 @@ init_port(uint16_t port)
 	if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
 		local_port_conf.txmode.offloads |=
 			RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE;
+	if (intr_rx_en)
+		local_port_conf.intr_conf.rxq = 1;
 	ret = rte_eth_dev_configure(port, 1, 1, &local_port_conf);
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Could not configure port%u (%d)\n",
-- 
2.27.0


  reply	other threads:[~2022-04-08  1:03 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-07 16:12 Tianli Lai
2022-04-08  9:02 ` Tianli Lai [this message]
2022-04-08  9:12 ` [PATCH v3] " Tianli Lai
2022-04-08 15:15   ` Stephen Hemminger
2022-04-09 10:13 ` [PATCH v4] " Tianli Lai
2023-07-04  2:58   ` Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220408090252.3858-1-laitianli@tom.com \
    --to=laitianli@tom.com \
    --cc=dev@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).