[v12] app/procinfo: display eventdev xstats

Message ID 20230320022316.2298874-1-abdullah.sevincer@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers
Series [v12] app/procinfo: display eventdev xstats |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation success Compilation OK
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/github-robot: build success github build: passed
ci/iol-intel-Performance success Performance Testing PASS
ci/intel-Testing success Testing PASS
ci/iol-aarch64-compile-testing success Testing PASS
ci/iol-x86_64-compile-testing success Testing PASS
ci/iol-aarch64-unit-testing success Testing PASS
ci/iol-abi-testing success Testing PASS
ci/iol-broadcom-Performance fail Performance Testing issues
ci/iol-testing success Testing PASS
ci/iol-x86_64-unit-testing success Testing PASS
ci/iol-unit-testing success Testing PASS
ci/intel-Functional success Functional PASS

Commit Message

Sevincer, Abdullah March 20, 2023, 2:23 a.m. UTC
  This commit extends proc-info application to
display xstats for the eventdev devices.

New command line arguments are introduced to
display xstats for eventdev devices. The command
example is like:

For displaying a specific port stats (e.g. port 1):
./dpdk-proc-info -- --show-edev-port-xstats=1:0

If any xstats parameters for eventdev passed through
proc-info command line, proc-info will only display
requested eventdev data and exit.

Users should not pass any eventdev xstats parameters
if they desire to dump other proc-info data such as
Rx/Tx descriptor dump.
More information can be found in proc-info app doc.

Signed-off-by: Abdullah Sevincer <abdullah.sevincer@intel.com>
---
 app/proc-info/main.c           | 294 ++++++++++++++++++++++++++++++++-
 app/proc-info/meson.build      |   2 +-
 doc/guides/tools/proc_info.rst |  32 +++-
 3 files changed, 325 insertions(+), 3 deletions(-)
  

Comments

Pattan, Reshma March 20, 2023, 5:29 p.m. UTC | #1
> -----Original Message-----
> From: Sevincer, Abdullah <abdullah.sevincer@intel.com>

> +static uint8_t evdev_id;
> +static uint8_t num_ports;
> +static uint8_t ports[MAX_PORTS_QUEUES]; 
>+static uint8_t num_queues;
> +static uint8_t queues[MAX_PORTS_QUEUES];
> +static uint32_t enable_shw_all_eventdev_queues; static uint32_t

<snip>

> +enable_shw_all_eventdev_ports; static uint32_t
> +enable_dump_eventdev_xstats; static uint32_t
> +enable_eventdev_reset_xstats; static uint32_t
> +enable_shw_eventdev_device_xstats;

How about keeping  a struct to maintain  all the data together that way you know on which all ports and queues of eventdev we have requested display. 
You can refer the existing code "struct desc_param" to see how this is done
Then you can declare global variables of type struct eventdev_params eventdev_var[MAX_EVENTDEV_DEV] to handle data of all evendev ids as an array, instead of keeping many global variables.
.

Ex: 
struct eventdev_params {
           	unit8_t eventdev_id;
           	unit8_t ports[MAX_PORTS_QUEUES]
          	 unit8_t queues[MAX_PORTS_QUEUES]
          	 static uint8_t num_queues
          	 static uint8_t num_ports

	static uint32_t enable_shw_all_eventdev_queues;
	static uint32_t enable_shw_all_eventdev_ports;
	static uint32_t enable_dump_eventdev_xstats;
	static uint32_t enable_eventdev_reset_xstats;
	static uint32_t enable_shw_eventdev_device_xstats;
}

> +	if (show_edev_xstats()) {

I don't think we really need the show_edev_xstats() function.  You can directly call process_eventdev_xstats() here.


> +		const uint8_t ndevs = rte_event_dev_count();
> +
> +		if (ndevs == 0)
> +			rte_panic("No event devs found. Do you need"
> +			  " to pass in a --vdev flag?\n");
> +
> +		/* Verify the command line options */
> +		if (evdev_id >= rte_event_dev_count())
> +			rte_panic("invalid event device %hhu\n", evdev_id);

Also, You can move above eventdev id validation code to  a small separate function().  
That new function can be called from parse_eventdev_queue_params() and parse_eventdev_port_params(), to validate the event dev id.
So you no need to do this eventdev validation here.

> +
> +		if (enable_dump_eventdev_xstats) {
> +			ret = rte_event_dev_dump(evdev_id, stdout);
> +			if (ret)
> +				rte_panic("dump failed with err=%d\n", ret);
> +		}


Also I guess you can move the below piece of code to be part of the process_eventdev_xstats()

> diff --git a/doc/guides/tools/proc_info.rst b/doc/guides/tools/proc_info.rst
> index cf3502a8cb..f0a7d37e41 100644

> -   --show-tx-descriptor queue_id:offset:num ]
> +   --show-tx-descriptor queue_id:offset:num | --show-edev-queue-
> xstats=queue_num |

> +   --show-edev-port-xstats=port_num | --edev-dump-xstats | --edev-reset-
> xstats |
> +   --show-edev-device-xstats]
> 
Need to edit these eventdev commands  to show the new  format port:eventdevid, queue:eventdevid and eventdev id.

Thanks,
Reshma
  
Sevincer, Abdullah March 20, 2023, 6:01 p.m. UTC | #2
+>How about keeping  a struct to maintain  all the data together that way you know on which all ports and queues of eventdev we have requested display. 
+>You can refer the existing code "struct desc_param" to see how this is done Then you can declare global variables of type struct eventdev_params eventdev_var[MAX_EVENTDEV_DEV] to handle data of all evendev ids as an array, instead of keeping +>many global variables.
This is very good idea, there are other global variables as well which can be put in the structure. I think many global variables declared in this file can follow this approach. However, I haven't scoped this within this release timeline as we have reached almost end of it.


> +	if (show_edev_xstats()) {

>+I don't think we really need the show_edev_xstats() function.  You can directly call process_eventdev_xstats() here.
I think we need this here because we want to exit from the app after displaying xstats for eventdev. We don't want to mix rte_eventdev data displayed (if we don't exit rest of the program continues to display other stats for rte, e.g. check show mempool command line)


> +		const uint8_t ndevs = rte_event_dev_count();
> +
> +		if (ndevs == 0)
> +			rte_panic("No event devs found. Do you need"
> +			  " to pass in a --vdev flag?\n");
> +
> +		/* Verify the command line options */
> +		if (evdev_id >= rte_event_dev_count())
> +			rte_panic("invalid event device %hhu\n", evdev_id);

>+Also, You can move above eventdev id validation code to  a small separate function().  
>+That new function can be called from parse_eventdev_queue_params() and parse_eventdev_port_params(), to validate the event dev id.
>+So you no need to do this eventdev validation here.
I think consolidating this call(checking the validation after evdevid is passed) in here is better, it seems more consolidated compared to have call at each parameter read in the parse function. 

> +
> +		if (enable_dump_eventdev_xstats) {
> +			ret = rte_event_dev_dump(evdev_id, stdout);
> +			if (ret)
> +				rte_panic("dump failed with err=%d\n", ret);
> +		}


>+Also I guess you can move the below piece of code to be part of the process_eventdev_xstats()
Okay, I will move this inside  process_eventdev_xstats().

>+Need to edit these eventdev commands  to show the new  format port:eventdevid, queue:eventdevid and eventdev id.
Will do.

Thanks,
Abdullah
  
Sevincer, Abdullah March 20, 2023, 6:35 p.m. UTC | #3
> -----Original Message-----
> From: Sevincer, Abdullah <abdullah.sevincer@intel.com>

> +static uint8_t evdev_id;
> +static uint8_t num_ports;
> +static uint8_t ports[MAX_PORTS_QUEUES];
>+static uint8_t num_queues;
> +static uint8_t queues[MAX_PORTS_QUEUES]; static uint32_t 
> +enable_shw_all_eventdev_queues; static uint32_t

<snip>

> +enable_shw_all_eventdev_ports; static uint32_t 
> +enable_dump_eventdev_xstats; static uint32_t 
> +enable_eventdev_reset_xstats; static uint32_t 
> +enable_shw_eventdev_device_xstats;

>+How about keeping  a struct to maintain  all the data together that way you know on which all ports and queues of eventdev we have requested display. 
>+You can refer the existing code "struct desc_param" to see how this is done Then you can declare global variables of type struct eventdev_params eventdev_var[MAX_EVENTDEV_DEV] to handle data of all evendev ids as an array, instead of keeping >+many global variables.
.

>+Ex: 
>+struct eventdev_params {
>+           	unit8_t eventdev_id;
>+           	unit8_t ports[MAX_PORTS_QUEUES]
>+          	 unit8_t queues[MAX_PORTS_QUEUES]
>+          	 static uint8_t num_queues
>+          	 static uint8_t num_ports
>+
>+	static uint32_t enable_shw_all_eventdev_queues;
>+	static uint32_t enable_shw_all_eventdev_ports;
>+	static uint32_t enable_dump_eventdev_xstats;
>+	static uint32_t enable_eventdev_reset_xstats;
>+	static uint32_t enable_shw_eventdev_device_xstats;
>+}

Also, all global variables are tied to a command itself like "static uint32_t enable_shw_port_priv" or "static uint32_t enable_shw_ring" . I also want the same for eventdev params to be called a command like the others in the file. If user wants he/she can chain commands. The "struct desc_param" is handling one command only but its 3 parameters (queue_id, offset and num) are put in the structure, for easy parsing. None of the command line arguments, hence global variables are handled/put in a structure. Would you like to change that for proc app going forward?
  
Pattan, Reshma March 21, 2023, 9:37 a.m. UTC | #4
> -----Original Message-----
> From: Sevincer, Abdullah <abdullah.sevincer@intel.com>
> >+Ex:
> >+struct eventdev_params {
> >+           	unit8_t eventdev_id;
> >+           	unit8_t ports[MAX_PORTS_QUEUES]
> >+          	 unit8_t queues[MAX_PORTS_QUEUES]
> >+          	 static uint8_t num_queues
> >+          	 static uint8_t num_ports
> >+
> >+	static uint32_t enable_shw_all_eventdev_queues;
> >+	static uint32_t enable_shw_all_eventdev_ports;
> >+	static uint32_t enable_dump_eventdev_xstats;
> >+	static uint32_t enable_eventdev_reset_xstats;
> >+	static uint32_t enable_shw_eventdev_device_xstats;
> >+}
> 
> Also, all global variables are tied to a command itself like "static uint32_t
> enable_shw_port_priv" or "static uint32_t enable_shw_ring" . I also want the
> same for eventdev params to be called a command like the others in the file. If
> user wants he/she can chain commands. The "struct desc_param" is handling
> one command only but its 3 parameters (queue_id, offset and num) are put in
> the structure, for easy parsing. None of the command line arguments, hence
> global variables are handled/put in a structure. Would you like to change that
> for proc app going forward?
> 

Having structure like suggested not only help-s simple data handling but also would help for the cases like below , where you need to maintain different event ids in the code. 
With the current patch version the below scenario is not possible as you have only one global variable for the eventdev id which always holds the latest evet id in the command , from below example evetdev id 2.


Ex 1: Where you want to show queue 0 xstats of eventdev 2 and port0 xstats of eventdev 1
./proc --show-evendev-port-xtstas=0:1 --show-evendev-queue-xsats=0:2

Thanks.
Reshma
  
Sevincer, Abdullah March 21, 2023, 10:20 a.m. UTC | #5
>+Having structure like suggested not only help-s simple data handling but also would help for the cases like below , where you need to maintain different event ids in the code. 
>+With the current patch version the below scenario is not possible as you have only one global variable for the eventdev id which always holds the latest evet id in the command , from below example evetdev id 2.


>+Ex 1: Where you want to show queue 0 xstats of eventdev 2 and port0 xstats of eventdev 1 ./proc --show-evendev-port-xtstas=0:1 --show-evendev-queue-xsats=0:2

>+Thanks.
>+Reshma

Thanks Reshma, now I understood the point. The intent is only display one event dev data with the same eventdev id being passed. Therefore I can change the patch
Passing another command line parameter --eventid and instead of taking two parameters from --show-evendev-port-xtstas=0:1 just take the port number (same for other command types). If no eventid is passed
Eventid defaults to 0.

If you want your approach of maintaining and displaying mix of more eventdevs with different ids, your suggestion is the way to go. Let me know.
  
Pattan, Reshma March 21, 2023, 10:27 a.m. UTC | #6
> -----Original Message-----
> From: Sevincer, Abdullah <abdullah.sevincer@intel.com>
> 
> >+Ex 1: Where you want to show queue 0 xstats of eventdev 2 and port0
> >+xstats of eventdev 1 ./proc --show-evendev-port-xtstas=0:1
> >+--show-evendev-queue-xsats=0:2
> 
> >+Thanks.
> >+Reshma
> 
> 
> If you want your approach of maintaining and displaying mix of more eventdevs
> with different ids, your suggestion is the way to go. Let me know.
> 
> 

Will go with my suggestion, I feel it will be more maintenance friendly going forward.
  

Patch

diff --git a/app/proc-info/main.c b/app/proc-info/main.c
index 53e852a07c..0e0d8ab4ce 100644
--- a/app/proc-info/main.c
+++ b/app/proc-info/main.c
@@ -40,11 +40,17 @@ 
 #include <rte_tm.h>
 #include <rte_hexdump.h>
 #include <rte_version.h>
+#include <rte_eventdev.h>
 
 /* Maximum long option length for option parsing. */
 #define MAX_LONG_OPT_SZ 64
 #define MAX_STRING_LEN 256
 
+/* Note: Port_queue_id in xstats APIs is 8 bits, so we have a maximum of
+ * 256 ports and queues for event_Dev
+ */
+#define MAX_PORTS_QUEUES 256
+
 #define ETHDEV_FWVERS_LEN 32
 #define RTE_RETA_CONF_GROUP_NUM 32
 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
@@ -121,6 +127,18 @@  static uint32_t enable_shw_module_eeprom;
 static uint32_t enable_shw_rx_desc_dump;
 static uint32_t enable_shw_tx_desc_dump;
 
+static uint32_t enable_shw_all_eventdev_queues;
+static uint32_t enable_shw_all_eventdev_ports;
+static uint32_t enable_dump_eventdev_xstats;
+static uint32_t enable_eventdev_reset_xstats;
+static uint32_t enable_shw_eventdev_device_xstats;
+
+static uint8_t evdev_id;
+static uint8_t num_ports;
+static uint8_t ports[MAX_PORTS_QUEUES];
+static uint8_t num_queues;
+static uint8_t queues[MAX_PORTS_QUEUES];
+
 #define DESC_PARAM_NUM 3
 
 struct desc_param {
@@ -172,7 +190,12 @@  proc_info_usage(const char *prgname)
 			"offset: The offset of the descriptor starting from tail. "
 			"num: The number of the descriptors to dump.\n"
 		"  --iter-mempool=name: iterate mempool elements to display content\n"
-		"  --dump-regs=file-prefix: dump registers to file with the file-prefix\n",
+		"  --dump-regs=file-prefix: dump registers to file with the file-prefix\n"
+		"  --show-edev-queue-xstats=queue_num:evdev_id or *:evdev_id to get queue xstats for specified queue or all queues;\n"
+		"  --show-edev-port-xstats=port_num:evdev_id or *:evdev_id to get queue xstats for specified port or all ports;\n"
+		"  --edev-dump-xstats=evdev_id to dump all event_dev xstats for specified eventdev device;\n"
+		"  --edev-reset-xstats=evdev_id to reset event_dev xstats after reading;\n"
+		"  --show-edev-device-xstats=evdev_id to get event_dev device xstats for specified eventdev device;\n",
 		prgname);
 }
 
@@ -236,6 +259,40 @@  parse_descriptor_param(char *list, struct desc_param *desc)
 	return 0;
 }
 
+static int
+parse_eventdev_queue_params(char *list)
+{
+	int queue_id;
+
+	if (sscanf(list, "*:%hhu", &evdev_id) == 1) {
+		enable_shw_all_eventdev_queues = 1;
+	} else if (sscanf(list, "%d:%hhu", &queue_id, &evdev_id) == 2) {
+		queues[num_queues] = queue_id;
+		num_queues++;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+parse_eventdev_port_params(char *list)
+{
+	int port_id;
+
+	if (sscanf(list, "*:%hhu", &evdev_id) == 1) {
+		enable_shw_all_eventdev_ports = 1;
+	} else if (sscanf(list, "%d:%hhu", &port_id, &evdev_id) == 2) {
+		ports[num_ports] = port_id;
+		num_ports++;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 proc_info_preparse_args(int argc, char **argv)
 {
@@ -302,6 +359,11 @@  proc_info_parse_args(int argc, char **argv)
 		{"show-module-eeprom", 0, NULL, 0},
 		{"show-rx-descriptor", required_argument, NULL, 1},
 		{"show-tx-descriptor", required_argument, NULL, 1},
+		{"show-edev-queue-xstats", required_argument, NULL, 0},
+		{"show-edev-port-xstats", required_argument, NULL, 0},
+		{"edev-dump-xstats", required_argument, NULL, 0},
+		{"edev-reset-xstats", required_argument, NULL, 0},
+		{"show-edev-device-xstats", required_argument, NULL, 0},
 		{NULL, 0, 0, 0}
 	};
 
@@ -385,6 +447,35 @@  proc_info_parse_args(int argc, char **argv)
 			else if (!strncmp(long_option[option_index].name,
 					"show-module-eeprom", MAX_LONG_OPT_SZ))
 				enable_shw_module_eeprom = 1;
+			else if (!strncmp(long_option[option_index].name,
+					"edev-dump-xstats", MAX_LONG_OPT_SZ)) {
+				enable_dump_eventdev_xstats = 1;
+				evdev_id = (uint8_t)atoi(optarg);
+			} else if (!strncmp(long_option[option_index].name,
+					"edev-reset-xstats", MAX_LONG_OPT_SZ)) {
+				enable_eventdev_reset_xstats = 1;
+				evdev_id = (uint8_t)atoi(optarg);
+			} else if (!strncmp(long_option[option_index].name,
+					"show-edev-device-xstats", MAX_LONG_OPT_SZ)) {
+				enable_shw_eventdev_device_xstats = 1;
+				evdev_id = (uint8_t)atoi(optarg);
+			} else if (!strncmp(long_option[option_index].name,
+					"show-edev-queue-xstats", MAX_LONG_OPT_SZ)) {
+				int ret = parse_eventdev_queue_params(optarg);
+				if (ret < 0) {
+					fprintf(stderr, "Error parsing eventdev queue params: %s\n",
+						strerror(-ret));
+					return -1;
+				}
+			} else if (!strncmp(long_option[option_index].name,
+					"show-edev-port-xstats", MAX_LONG_OPT_SZ)) {
+				int ret = parse_eventdev_port_params(optarg);
+				if (ret < 0) {
+					fprintf(stderr, "Error parsing eventdev port params: %s\n",
+						strerror(-ret));
+					return -1;
+				}
+			}
 			break;
 		case 1:
 			/* Print xstat single value given by name*/
@@ -1744,6 +1835,186 @@  nic_tx_descriptor_display(uint16_t port_id, struct desc_param *desc)
 			strerror(-ret));
 }
 
+static bool
+show_edev_xstats(void)
+{
+	/* Check if any event dev xstats requested from command line */
+	if (enable_shw_all_eventdev_queues || enable_shw_all_eventdev_ports
+		|| enable_dump_eventdev_xstats || enable_eventdev_reset_xstats ||
+		enable_shw_eventdev_device_xstats || num_ports > 0 || num_queues > 0)
+		return true;
+
+	return false;
+}
+
+static unsigned int
+xstats_get_names_and_ids_size(uint8_t dev_id,
+	  enum rte_event_dev_xstats_mode mode,
+	  uint8_t queue_port_id)
+{
+
+	int ret;
+
+	/* Get amount of storage required */
+	ret = rte_event_dev_xstats_names_get(dev_id,
+					     mode,
+					     queue_port_id,
+					     NULL, /* names */
+					     NULL, /* ids */
+					     0);   /* num */
+
+	if (ret < 0)
+		rte_panic("rte_event_dev_xstats_names_get err %d\n", ret);
+
+	return (unsigned int)ret;
+
+}
+
+static void
+xstats_display(uint8_t dev_id,
+	  enum rte_event_dev_xstats_mode mode,
+	  uint8_t queue_port_id)
+{
+	int ret;
+	struct rte_event_dev_xstats_name *xstats_names;
+	uint64_t *ids;
+	uint64_t *values;
+	unsigned int size;
+	int i;
+
+	size = xstats_get_names_and_ids_size(dev_id, mode, queue_port_id);
+
+	if (size == 0) {
+		printf(
+		"No stats available for this item, mode=%d, queue_port_id=%d\n",
+			mode, queue_port_id);
+		return;
+	}
+
+	/* Get memory to hold stat names, IDs, and values */
+	xstats_names = malloc(sizeof(struct rte_event_dev_xstats_name) * size);
+	ids = malloc(sizeof(unsigned int) * size);
+
+	if (!xstats_names || !ids)
+		rte_panic("unable to alloc memory for stats retrieval\n");
+
+	ret = rte_event_dev_xstats_names_get(dev_id, mode, queue_port_id,
+					     xstats_names, ids,
+					     size);
+	if (ret != (int)size)
+		rte_panic("rte_event_dev_xstats_names_get err %d\n", ret);
+
+	values = malloc(sizeof(uint64_t) * size);
+	if (!values)
+		rte_panic("unable to alloc memory for stats retrieval\n");
+
+	ret = rte_event_dev_xstats_get(dev_id, mode, queue_port_id,
+					    ids, values, size);
+
+	if (ret != (int)size)
+		rte_panic("rte_event_dev_xstats_get err %d\n", ret);
+
+	for (i = 0; i < (int)size; i++) {
+		printf("id %"PRIu64"  %s = %"PRIu64"\n",
+			ids[i], &xstats_names[i].name[0], values[i]);
+	}
+
+	free(values);
+	free(xstats_names);
+	free(ids);
+
+}
+
+static void
+xstats_reset(uint8_t dev_id,
+	  enum rte_event_dev_xstats_mode mode,
+	  uint8_t queue_port_id)
+{
+	int ret;
+	struct rte_event_dev_xstats_name *xstats_names;
+	uint64_t *ids;
+	unsigned int size;
+
+	size = xstats_get_names_and_ids_size(dev_id, mode, queue_port_id);
+
+	if (size == 0) {
+		printf(
+		"No stats available for this item, mode=%d, queue_port_id=%d\n",
+			mode, queue_port_id);
+		return;
+	}
+
+	/* Get memory to hold stat names, IDs, and values */
+	xstats_names = malloc(sizeof(struct rte_event_dev_xstats_name) * size);
+	ids = malloc(sizeof(unsigned int) * size);
+
+	if (!xstats_names || !ids)
+		rte_panic("unable to alloc memory for stats retrieval\n");
+
+	ret = rte_event_dev_xstats_names_get(dev_id, mode, queue_port_id,
+					     xstats_names, ids,
+					     size);
+	if (ret != (int)size)
+		rte_panic("rte_event_dev_xstats_names_get err %d\n", ret);
+
+	rte_event_dev_xstats_reset(dev_id, mode, queue_port_id,
+					   ids, size);
+
+	free(xstats_names);
+	free(ids);
+
+}
+
+static void
+process_eventdev_xstats(void)
+{
+	int i;
+
+	if (enable_shw_eventdev_device_xstats) {
+		xstats_display(evdev_id,
+			  RTE_EVENT_DEV_XSTATS_DEVICE,
+			  0);
+		if (enable_eventdev_reset_xstats)
+			xstats_reset(evdev_id, RTE_EVENT_DEV_XSTATS_DEVICE, 0);
+	}
+
+	if (enable_shw_all_eventdev_ports) {
+		for (i = 0; i < MAX_PORTS_QUEUES; i++) {
+			xstats_display(evdev_id,
+				  RTE_EVENT_DEV_XSTATS_PORT,
+				  i);
+			if (enable_eventdev_reset_xstats)
+				xstats_reset(evdev_id, RTE_EVENT_DEV_XSTATS_PORT, i);
+		}
+	} else {
+		for (i = 0; i < num_ports; i++) {
+			xstats_display(evdev_id,
+				  RTE_EVENT_DEV_XSTATS_PORT,
+				  ports[i]);
+			if (enable_eventdev_reset_xstats)
+				xstats_reset(evdev_id, RTE_EVENT_DEV_XSTATS_PORT, ports[i]);
+		}
+	}
+
+	if (enable_shw_all_eventdev_queues) {
+		for (i = 0; i < MAX_PORTS_QUEUES; i++) {
+			xstats_display(evdev_id,
+				  RTE_EVENT_DEV_XSTATS_QUEUE,
+				  i);
+			if (enable_eventdev_reset_xstats)
+				xstats_reset(evdev_id, RTE_EVENT_DEV_XSTATS_QUEUE, i);
+		}
+	} else {
+		for (i = 0; i < num_queues; i++) {
+			xstats_display(evdev_id,
+				  RTE_EVENT_DEV_XSTATS_QUEUE,
+				  queues[i]);
+			if (enable_eventdev_reset_xstats)
+				xstats_reset(evdev_id, RTE_EVENT_DEV_XSTATS_QUEUE, queues[i]);
+		}
+	}
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1794,6 +2065,27 @@  main(int argc, char **argv)
 		return 0;
 	}
 
+	if (show_edev_xstats()) {
+		const uint8_t ndevs = rte_event_dev_count();
+
+		if (ndevs == 0)
+			rte_panic("No event devs found. Do you need"
+			  " to pass in a --vdev flag?\n");
+
+		/* Verify the command line options */
+		if (evdev_id >= rte_event_dev_count())
+			rte_panic("invalid event device %hhu\n", evdev_id);
+
+		if (enable_dump_eventdev_xstats) {
+			ret = rte_event_dev_dump(evdev_id, stdout);
+			if (ret)
+				rte_panic("dump failed with err=%d\n", ret);
+		}
+
+		process_eventdev_xstats();
+		return 0;
+	}
+
 	nb_ports = rte_eth_dev_count_avail();
 	if (nb_ports == 0)
 		rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n");
diff --git a/app/proc-info/meson.build b/app/proc-info/meson.build
index 1563ce656a..4f83f29a64 100644
--- a/app/proc-info/meson.build
+++ b/app/proc-info/meson.build
@@ -8,7 +8,7 @@  if is_windows
 endif
 
 sources = files('main.c')
-deps += ['ethdev', 'security']
+deps += ['ethdev', 'security', 'eventdev']
 if dpdk_conf.has('RTE_LIB_METRICS')
     deps += 'metrics'
 endif
diff --git a/doc/guides/tools/proc_info.rst b/doc/guides/tools/proc_info.rst
index cf3502a8cb..f0a7d37e41 100644
--- a/doc/guides/tools/proc_info.rst
+++ b/doc/guides/tools/proc_info.rst
@@ -22,7 +22,9 @@  The application has a number of command line options:
    --show-ring[=name] | --show-mempool[=name] | --iter-mempool=name |
    --show-port-private | --version | --firmware-version | --show-rss-reta |
    --show-module-eeprom | --show-rx-descriptor queue_id:offset:num |
-   --show-tx-descriptor queue_id:offset:num ]
+   --show-tx-descriptor queue_id:offset:num | --show-edev-queue-xstats=queue_num |
+   --show-edev-port-xstats=port_num | --edev-dump-xstats | --edev-reset-xstats |
+   --show-edev-device-xstats]
 
 Parameters
 ~~~~~~~~~~
@@ -101,6 +103,34 @@  queue_id: A Tx queue identifier on this port.
 offset: The offset of the descriptor starting from tail.
 num: The number of the descriptors to dump.
 
+**--show-edev-queue-xstats queue_num:evdev_id**
+The show-edev-queue-xstats parameter enables stats for specified queue or all queues.
+queue_num: The queue number to get queue xstats for this specified queue or * for all queues.
+evdev_id: Id of the eventdev device to display xstats.
+
+**--show-edev-port-xstats port_num:evdev_id**
+The show-edev-port-xstats parameter enables stats for specified port or all ports.
+port_num: The port number to get port xstats for this specified port or * for all ports.
+evdev_id: Id of the eventdev device to display xstats.
+
+**--edev-dump-xstats evdev_id**
+The edev-dump-xstats parameter dumps all eventdev stats.
+evdev_id: Id of the eventdev device to display xstats.
+
+**--edev-reset-xstats evdev_id**
+The edev-reset-xstats parameter resets eventdev xstats after reading.
+evdev_id: Id of the eventdev device to display xstats.
+
+**--show-edev-device-xstats evdev_id**
+The show-edev-device-xstats parameter displays eventdev device xstats.
+evdev_id: Id of the eventdev device to display xstats.
+
+A typical command line usage for eventdev stats:
+
+    .. code-block:: console
+
+       ./dpdk-proc-info -- --show-edev-port-xstats=1:0
+
 Limitations
 -----------