diff --git a/app/test-mldev/meson.build b/app/test-mldev/meson.build
index 15db534dc2..18e28f2713 100644
--- a/app/test-mldev/meson.build
+++ b/app/test-mldev/meson.build
@@ -19,6 +19,7 @@ sources = files(
         'test_inference_common.c',
         'test_inference_ordered.c',
         'test_inference_interleave.c',
+        'test_stats.c'
 )
 
 deps += ['mldev', 'hash']
diff --git a/app/test-mldev/ml_common.h b/app/test-mldev/ml_common.h
index 624a5aff50..8d7cc9eeb7 100644
--- a/app/test-mldev/ml_common.h
+++ b/app/test-mldev/ml_common.h
@@ -26,4 +26,15 @@
 
 #define ml_dump_end printf("\b\t}\n\n")
 
+static inline void
+ml_print_line(uint16_t len)
+{
+	uint16_t i;
+
+	for (i = 0; i < len; i++)
+		printf("-");
+
+	printf("\n");
+}
+
 #endif /* ML_COMMON_H */
diff --git a/app/test-mldev/ml_options.c b/app/test-mldev/ml_options.c
index 2efcc3532c..1daa229748 100644
--- a/app/test-mldev/ml_options.c
+++ b/app/test-mldev/ml_options.c
@@ -205,7 +205,8 @@ ml_dump_test_options(const char *testname)
 	}
 
 	if (strcmp(testname, "model_ops") == 0) {
-		printf("\t\t--models           : comma separated list of models\n");
+		printf("\t\t--models           : comma separated list of models\n"
+		       "\t\t--stats            : enable reporting device statistics\n");
 		printf("\n");
 	}
 
@@ -218,7 +219,7 @@ ml_dump_test_options(const char *testname)
 		       "\t\t--queue_size       : size fo queue-pair\n"
 		       "\t\t--batches          : number of batches of input\n"
 		       "\t\t--tolerance        : maximum tolerance (%%) for output validation\n"
-		       "\t\t--stats            : enable reporting performance statistics\n");
+		       "\t\t--stats            : enable reporting device and model statistics\n");
 		printf("\n");
 	}
 }
diff --git a/app/test-mldev/test_common.h b/app/test-mldev/test_common.h
index a7b2ea652a..def108d5b2 100644
--- a/app/test-mldev/test_common.h
+++ b/app/test-mldev/test_common.h
@@ -14,6 +14,9 @@ struct test_common {
 	struct ml_options *opt;
 	enum ml_test_result result;
 	struct rte_ml_dev_info dev_info;
+	struct rte_ml_dev_xstats_map *xstats_map;
+	uint64_t *xstats_values;
+	int xstats_size;
 };
 
 bool ml_test_cap_check(struct ml_options *opt);
diff --git a/app/test-mldev/test_inference_common.c b/app/test-mldev/test_inference_common.c
index 1e16608582..469ed35f6c 100644
--- a/app/test-mldev/test_inference_common.c
+++ b/app/test-mldev/test_inference_common.c
@@ -39,17 +39,6 @@
 		}                                                                                  \
 	} while (0)
 
-static void
-print_line(uint16_t len)
-{
-	uint16_t i;
-
-	for (i = 0; i < len; i++)
-		printf("-");
-
-	printf("\n");
-}
-
 /* Enqueue inference requests with burst size equal to 1 */
 static int
 ml_enqueue_single(void *arg)
@@ -1027,52 +1016,3 @@ ml_inference_launch_cores(struct ml_test *test, struct ml_options *opt, uint16_t
 
 	return 0;
 }
-
-int
-ml_inference_throughput_get(struct ml_test *test, struct ml_options *opt)
-{
-	struct test_inference *t = ml_test_priv(test);
-	uint64_t total_cycles = 0;
-	uint32_t nb_filelist;
-	uint64_t throughput;
-	uint64_t avg_e2e;
-	uint32_t qp_id;
-	uint64_t freq;
-
-	if (!opt->stats)
-		return 0;
-
-	/* print end-to-end stats */
-	freq = rte_get_tsc_hz();
-	for (qp_id = 0; qp_id < RTE_MAX_LCORE; qp_id++)
-		total_cycles += t->args[qp_id].end_cycles - t->args[qp_id].start_cycles;
-	avg_e2e = total_cycles / opt->repetitions;
-
-	if (freq == 0) {
-		avg_e2e = total_cycles / opt->repetitions;
-		printf(" %-64s = %" PRIu64 "\n", "Average End-to-End Latency (cycles)", avg_e2e);
-	} else {
-		avg_e2e = (total_cycles * NS_PER_S) / (opt->repetitions * freq);
-		printf(" %-64s = %" PRIu64 "\n", "Average End-to-End Latency (ns)", avg_e2e);
-	}
-
-	/* print inference throughput */
-	if (strcmp(opt->test_name, "inference_ordered") == 0)
-		nb_filelist = 1;
-	else
-		nb_filelist = opt->nb_filelist;
-
-	if (freq == 0) {
-		throughput = (nb_filelist * t->cmn.opt->repetitions * 1000000) / total_cycles;
-		printf(" %-64s = %" PRIu64 "\n", "Average Throughput (inferences / million cycles)",
-		       throughput);
-	} else {
-		throughput = (nb_filelist * t->cmn.opt->repetitions * freq) / total_cycles;
-		printf(" %-64s = %" PRIu64 "\n", "Average Throughput (inferences / second)",
-		       throughput);
-	}
-
-	print_line(80);
-
-	return 0;
-}
diff --git a/app/test-mldev/test_inference_common.h b/app/test-mldev/test_inference_common.h
index 0a9b930788..8f27af25e4 100644
--- a/app/test-mldev/test_inference_common.h
+++ b/app/test-mldev/test_inference_common.h
@@ -70,6 +70,5 @@ void ml_inference_mem_destroy(struct ml_test *test, struct ml_options *opt);
 int ml_inference_result(struct ml_test *test, struct ml_options *opt, uint16_t fid);
 int ml_inference_launch_cores(struct ml_test *test, struct ml_options *opt, uint16_t start_fid,
 			      uint16_t end_fid);
-int ml_inference_throughput_get(struct ml_test *test, struct ml_options *opt);
 
 #endif /* TEST_INFERENCE_COMMON_H */
diff --git a/app/test-mldev/test_inference_interleave.c b/app/test-mldev/test_inference_interleave.c
index 23b8efe4f0..9503dda042 100644
--- a/app/test-mldev/test_inference_interleave.c
+++ b/app/test-mldev/test_inference_interleave.c
@@ -7,6 +7,7 @@
 
 #include "ml_common.h"
 #include "test_inference_common.h"
+#include "test_stats.h"
 
 static int
 test_inference_interleave_driver(struct ml_test *test, struct ml_options *opt)
@@ -58,7 +59,8 @@ test_inference_interleave_driver(struct ml_test *test, struct ml_options *opt)
 		ml_inference_iomem_destroy(test, opt, fid);
 	}
 
-	ml_inference_throughput_get(test, opt);
+	for (fid = 0; fid < opt->nb_filelist; fid++)
+		ml_stats_get(test, opt, RTE_ML_DEV_XSTATS_MODEL, fid);
 
 	for (fid = 0; fid < opt->nb_filelist; fid++) {
 		ret = ml_model_stop(test, opt, &t->model[fid], fid);
@@ -70,6 +72,8 @@ test_inference_interleave_driver(struct ml_test *test, struct ml_options *opt)
 			goto error;
 	}
 
+	ml_stats_get(test, opt, RTE_ML_DEV_XSTATS_DEVICE, -1);
+	ml_throughput_get(test, opt);
 	ml_inference_mem_destroy(test, opt);
 
 	ret = ml_inference_mldev_destroy(test, opt);
diff --git a/app/test-mldev/test_inference_ordered.c b/app/test-mldev/test_inference_ordered.c
index f49810c152..e0e826d972 100644
--- a/app/test-mldev/test_inference_ordered.c
+++ b/app/test-mldev/test_inference_ordered.c
@@ -7,6 +7,7 @@
 
 #include "ml_common.h"
 #include "test_inference_common.h"
+#include "test_stats.h"
 
 static int
 test_inference_ordered_driver(struct ml_test *test, struct ml_options *opt)
@@ -54,7 +55,8 @@ test_inference_ordered_driver(struct ml_test *test, struct ml_options *opt)
 		goto error;
 
 	ml_inference_iomem_destroy(test, opt, fid);
-	ml_inference_throughput_get(test, opt);
+	ml_stats_get(test, opt, RTE_ML_DEV_XSTATS_MODEL, fid);
+	ml_throughput_get(test, opt);
 
 	/* stop model */
 	ret = ml_model_stop(test, opt, &t->model[fid], fid);
@@ -70,6 +72,7 @@ test_inference_ordered_driver(struct ml_test *test, struct ml_options *opt)
 	if (fid < opt->nb_filelist)
 		goto next_model;
 
+	ml_stats_get(test, opt, RTE_ML_DEV_XSTATS_DEVICE, -1);
 	ml_inference_mem_destroy(test, opt);
 
 	ret = ml_inference_mldev_destroy(test, opt);
diff --git a/app/test-mldev/test_model_ops.c b/app/test-mldev/test_model_ops.c
index 5bbbcb1a6c..b15587a3c5 100644
--- a/app/test-mldev/test_model_ops.c
+++ b/app/test-mldev/test_model_ops.c
@@ -9,6 +9,7 @@
 #include <rte_mldev.h>
 
 #include "test_model_ops.h"
+#include "test_stats.h"
 
 static bool
 test_model_ops_cap_check(struct ml_options *opt)
@@ -384,6 +385,8 @@ test_model_ops_driver(struct ml_test *test, struct ml_options *opt)
 
 	printf("\n");
 
+	ml_stats_get(test, opt, RTE_ML_DEV_XSTATS_DEVICE, -1);
+
 	/* device destroy */
 	ret = test_model_ops_mldev_destroy(test, opt);
 	if (ret != 0)
diff --git a/app/test-mldev/test_stats.c b/app/test-mldev/test_stats.c
new file mode 100644
index 0000000000..ffe24a9b91
--- /dev/null
+++ b/app/test-mldev/test_stats.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2023 Marvell.
+ */
+
+#include "test_stats.h"
+#include "test_inference_common.h"
+#include "test_model_ops.h"
+
+int
+ml_stats_get(struct ml_test *test, struct ml_options *opt, enum rte_ml_dev_xstats_mode mode,
+	     int32_t fid)
+{
+	struct test_common *t = ml_test_priv(test);
+	int32_t model_id;
+	int ret;
+	int i;
+
+	if (!opt->stats)
+		return 0;
+
+	if (mode == RTE_ML_DEV_XSTATS_MODEL)
+		model_id = ((struct test_inference *)t)->model[fid].id;
+	else
+		model_id = -1;
+
+	/* get xstats size */
+	t->xstats_size = rte_ml_dev_xstats_names_get(opt->dev_id, mode, model_id, NULL, 0);
+	if (t->xstats_size > 0) {
+		/* allocate for xstats_map and values */
+		t->xstats_map = rte_malloc(
+			"ml_xstats_map", t->xstats_size * sizeof(struct rte_ml_dev_xstats_map), 0);
+		if (t->xstats_map == NULL) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		t->xstats_values =
+			rte_malloc("ml_xstats_values", t->xstats_size * sizeof(uint64_t), 0);
+		if (t->xstats_values == NULL) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		ret = rte_ml_dev_xstats_names_get(opt->dev_id, mode, model_id, t->xstats_map,
+						  t->xstats_size);
+		if (ret != t->xstats_size) {
+			printf("Unable to get xstats names, ret = %d\n", ret);
+			ret = -1;
+			goto error;
+		}
+
+		for (i = 0; i < t->xstats_size; i++)
+			rte_ml_dev_xstats_get(opt->dev_id, mode, model_id, &t->xstats_map[i].id,
+					      &t->xstats_values[i], 1);
+	}
+
+	/* print xstats*/
+	printf("\n");
+	ml_print_line(80);
+	if (mode == RTE_ML_DEV_XSTATS_MODEL)
+		printf(" Model Statistics: %s\n",
+		       ((struct test_inference *)t)->model[fid].info.name);
+	else
+		printf(" Device Statistics\n");
+	ml_print_line(80);
+	for (i = 0; i < t->xstats_size; i++)
+		printf(" %-64s = %" PRIu64 "\n", t->xstats_map[i].name, t->xstats_values[i]);
+	ml_print_line(80);
+
+	rte_free(t->xstats_map);
+	rte_free(t->xstats_values);
+
+	return 0;
+
+error:
+	rte_free(t->xstats_map);
+	rte_free(t->xstats_values);
+
+	return ret;
+}
+
+int
+ml_throughput_get(struct ml_test *test, struct ml_options *opt)
+{
+	struct test_inference *t = ml_test_priv(test);
+	uint64_t total_cycles = 0;
+	uint32_t nb_filelist;
+	uint64_t throughput;
+	uint64_t avg_e2e;
+	uint32_t qp_id;
+	uint64_t freq;
+
+	if (!opt->stats)
+		return 0;
+
+	/* print inference throughput */
+	if (strcmp(opt->test_name, "inference_ordered") == 0)
+		nb_filelist = 1;
+	else
+		nb_filelist = opt->nb_filelist;
+
+	/* Print model end-to-end latency and throughput */
+	freq = rte_get_tsc_hz();
+	for (qp_id = 0; qp_id < RTE_MAX_LCORE; qp_id++)
+		total_cycles += t->args[qp_id].end_cycles - t->args[qp_id].start_cycles;
+
+	avg_e2e = total_cycles / (opt->repetitions * nb_filelist);
+	if (freq == 0) {
+		printf(" %-64s = %" PRIu64 "\n", "Average End-to-End Latency (cycles)", avg_e2e);
+	} else {
+		avg_e2e = (avg_e2e * NS_PER_S) / freq;
+		printf(" %-64s = %" PRIu64 "\n", "Average End-to-End Latency (ns)", avg_e2e);
+	}
+
+	/* Print model throughput */
+	if (freq == 0) {
+		throughput = 1000000 / avg_e2e;
+		printf(" %-64s = %" PRIu64 "\n", "Average Throughput (inferences / million cycles)",
+		       throughput);
+	} else {
+		throughput = freq / avg_e2e;
+		printf(" %-64s = %" PRIu64 "\n", "Average Throughput (inferences / second)",
+		       throughput);
+	}
+
+	ml_print_line(80);
+
+	return 0;
+}
diff --git a/app/test-mldev/test_stats.h b/app/test-mldev/test_stats.h
new file mode 100644
index 0000000000..89648490fa
--- /dev/null
+++ b/app/test-mldev/test_stats.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2023 Marvell.
+ */
+
+#include <rte_malloc.h>
+#include <rte_mldev.h>
+
+#include "ml_test.h"
+#include "test_inference_common.h"
+
+int ml_stats_get(struct ml_test *test, struct ml_options *opt, enum rte_ml_dev_xstats_mode,
+		 int32_t fid);
+int ml_throughput_get(struct ml_test *test, struct ml_options *opt);
