diff --git a/test/performance/odp_queue_perf.c b/test/performance/odp_queue_perf.c
index e1c02f33f..0cda5879b 100644
--- a/test/performance/odp_queue_perf.c
+++ b/test/performance/odp_queue_perf.c
@@ -26,6 +26,15 @@ typedef struct test_options_t {
 
 } test_options_t;
 
+typedef struct test_stat_t {
+	uint64_t rounds;
+	uint64_t events;
+	uint64_t nsec;
+	uint64_t cycles;
+	uint64_t deq_retry;
+
+} test_stat_t;
+
 typedef struct test_global_t {
 	odp_barrier_t    barrier;
 	test_options_t   options;
@@ -34,6 +43,7 @@ typedef struct test_global_t {
 	odp_pool_t       pool;
 	odp_queue_t      queue[MAX_QUEUES];
 	odph_odpthread_t thread_tbl[ODP_THREAD_COUNT_MAX];
+	test_stat_t      stat[ODP_THREAD_COUNT_MAX];
 
 } test_global_t;
 
@@ -46,8 +56,9 @@ static void print_usage(void)
 	       "\n"
 	       "Usage: odp_queue_perf [options]\n"
 	       "\n"
-	       "  -q, --num_queue        Number of queues\n"
-	       "  -e, --num_event        Number of events per queue\n"
+	       "  -c, --num_cpu          Number of worker threads. Default: 1\n"
+	       "  -q, --num_queue        Number of queues. Default: 1\n"
+	       "  -e, --num_event        Number of events per queue. Default: 1\n"
 	       "  -r, --num_round        Number of rounds\n"
 	       "  -l, --lockfree         Lockfree queues\n"
 	       "  -w, --waitfree         Waitfree queues\n"
@@ -63,6 +74,7 @@ static int parse_options(int argc, char *argv[], test_options_t *test_options)
 	int ret = 0;
 
 	static const struct option longopts[] = {
+		{"num_cpu",   required_argument, NULL, 'c'},
 		{"num_queue", required_argument, NULL, 'q'},
 		{"num_event", required_argument, NULL, 'e'},
 		{"num_round", required_argument, NULL, 'r'},
@@ -73,7 +85,7 @@ static int parse_options(int argc, char *argv[], test_options_t *test_options)
 		{NULL, 0, NULL, 0}
 	};
 
-	static const char *shortopts = "+q:e:r:lwsh";
+	static const char *shortopts = "+c:q:e:r:lwsh";
 
 	test_options->num_cpu   = 1;
 	test_options->num_queue = 1;
@@ -89,6 +101,9 @@ static int parse_options(int argc, char *argv[], test_options_t *test_options)
 			break;
 
 		switch (opt) {
+		case 'c':
+			test_options->num_cpu = atoi(optarg);
+			break;
 		case 'q':
 			test_options->num_queue = atoi(optarg);
 			break;
@@ -333,67 +348,66 @@ static int destroy_queues(test_global_t *global)
 
 static int run_test(void *arg)
 {
-	uint64_t c1, c2, diff, ops, nsec;
+	uint64_t c1, c2, cycles, nsec;
 	odp_time_t t1, t2;
 	odp_event_t ev;
-	uint32_t i, rounds;
+	uint32_t rounds;
+	test_stat_t *stat;
 	test_global_t *global = arg;
 	test_options_t *test_options = &global->options;
-	odp_queue_t *queue = global->queue;
+	odp_queue_t queue;
 	uint64_t num_retry = 0;
+	uint64_t events = 0;
 	uint32_t num_queue = test_options->num_queue;
 	uint32_t num_round = test_options->num_round;
+	int thr = odp_thread_id();
 	int ret = 0;
+	uint32_t i = 0;
+
+	stat = &global->stat[thr];
+
+	/* Start all workers at the same time */
+	odp_barrier_wait(&global->barrier);
 
 	t1 = odp_time_local();
 	c1 = odp_cpu_cycles();
 
 	for (rounds = 0; rounds < num_round; rounds++) {
-		int retry = 0;
+		do {
+			queue = global->queue[i++];
 
-		for (i = 0; i < num_queue; i++) {
-			ev = odp_queue_deq(queue[i]);
+			if (i == num_queue)
+				i = 0;
 
-			if (ev == ODP_EVENT_INVALID) {
-				if (retry < 5) {
-					retry++;
-					num_retry++;
-					continue;
-				}
+			ev = odp_queue_deq(queue);
 
-				printf("Error: Queue deq failed %u\n", i);
-				ret = -1;
-				goto error;
-			}
+			if (odp_unlikely(ev == ODP_EVENT_INVALID))
+				num_retry++;
 
-			retry = 0;
+		} while (ev == ODP_EVENT_INVALID);
 
-			if (odp_queue_enq(queue[i], ev)) {
-				printf("Error: Queue enq failed %u\n", i);
-				ret = -1;
-				goto error;
-			}
+		if (odp_queue_enq(queue, ev)) {
+			printf("Error: Queue enq failed %u\n", i);
+			ret = -1;
+			goto error;
 		}
+
+		events++;
 	}
 
 	c2 = odp_cpu_cycles();
 	t2 = odp_time_local();
 
-	nsec = odp_time_diff_ns(t2, t1);
-	diff = odp_cpu_cycles_diff(c2, c1);
-	ops = num_round * num_queue;
+	nsec   = odp_time_diff_ns(t2, t1);
+	cycles = odp_cpu_cycles_diff(c2, c1);
 
-	printf("RESULT:\n");
-	printf("  num deq + enq operations: %" PRIu64 "\n", ops);
-	printf("  num events:               %" PRIu64 "\n", ops);
-	printf("  duration (nsec):          %" PRIu64 "\n", nsec);
-	printf("  num cycles:               %" PRIu64 "\n", diff);
-	printf("  cycles per deq + enq:     %.3f\n", (double)diff / ops);
-	printf("  events per sec:           %.3f M\n", (1000.0 * ops) / nsec);
-	printf("  num retries:              %" PRIu64 "\n\n", num_retry);
+	stat->rounds = rounds;
+	stat->events = events;
+	stat->nsec   = nsec;
+	stat->cycles = cycles;
+	stat->deq_retry = num_retry;
 
 error:
-
 	return ret;
 }
 
@@ -435,6 +449,69 @@ static int start_workers(test_global_t *global)
 	return 0;
 }
 
+static void print_stat(test_global_t *global)
+{
+	int i, num;
+	double events_ave, nsec_ave, cycles_ave, retry_ave;
+	test_options_t *test_options = &global->options;
+	int num_cpu = test_options->num_cpu;
+	uint64_t rounds_sum = 0;
+	uint64_t events_sum = 0;
+	uint64_t nsec_sum = 0;
+	uint64_t cycles_sum = 0;
+	uint64_t retry_sum = 0;
+
+	/* Averages */
+	for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+		rounds_sum   += global->stat[i].rounds;
+		events_sum   += global->stat[i].events;
+		nsec_sum     += global->stat[i].nsec;
+		cycles_sum   += global->stat[i].cycles;
+		retry_sum    += global->stat[i].deq_retry;
+	}
+
+	if (rounds_sum == 0) {
+		printf("No results.\n");
+		return;
+	}
+
+	events_ave   = events_sum / num_cpu;
+	nsec_ave     = nsec_sum / num_cpu;
+	cycles_ave   = cycles_sum / num_cpu;
+	retry_ave    = retry_sum / num_cpu;
+	num = 0;
+
+	printf("RESULTS - per thread (Million events per sec):\n");
+	printf("----------------------------------------------\n");
+	printf("        1      2      3      4      5      6      7      8      9     10");
+
+	for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+		if (global->stat[i].rounds) {
+			if ((num % 10) == 0)
+				printf("\n   ");
+
+			printf("%6.1f ", (1000.0 * global->stat[i].events) /
+			       global->stat[i].nsec);
+			num++;
+		}
+	}
+	printf("\n\n");
+
+	printf("RESULTS - per thread average (%i threads):\n", num_cpu);
+	printf("------------------------------------------\n");
+	printf("  duration:                 %.3f msec\n", nsec_ave / 1000000);
+	printf("  num cycles:               %.3f M\n", cycles_ave / 1000000);
+	printf("  cycles per event:         %.3f\n",
+	       cycles_ave / events_ave);
+	printf("  deq retries per sec:      %.3f k\n",
+	       (1000000.0 * retry_ave) / nsec_ave);
+	printf("  events per sec:           %.3f M\n\n",
+	       (1000.0 * events_ave) / nsec_ave);
+
+	printf("TOTAL events per sec:       %.3f M\n\n",
+	       (1000.0 * events_sum) / nsec_ave);
+}
+
 int main(int argc, char **argv)
 {
 	odp_instance_t instance;
@@ -483,6 +560,8 @@ int main(int argc, char **argv)
 	/* Wait workers to exit */
 	odph_odpthreads_join(global->thread_tbl);
 
+	print_stat(global);
+
 destroy:
 	if (destroy_queues(global)) {
 		printf("Error: Destroy queues failed.\n");
