aboutsummaryrefslogtreecommitdiff
path: root/test/performance
diff options
context:
space:
mode:
authorMike Holmes <mike.holmes@linaro.org>2014-12-24 17:36:12 -0500
committerMaxim Uvarov <maxim.uvarov@linaro.org>2014-12-26 14:06:50 +0300
commitfcb2c9cb40ed5524b6c9915d09221b89e01de2ce (patch)
tree599f883cc5ce9c874f43571eb78d87dce8f8132d /test/performance
parent88e69882905b81a90e4ed7310bd9cd7eab2a34dc (diff)
example: move odp_example to test/performance
odp_example is too complex to be an example, and is not a unit test, instead it is a performance oriented test application. Signed-off-by: Mike Holmes <mike.holmes@linaro.org> Reviewed-by: Taras Kondratiuk <taras.kondratiuk@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'test/performance')
-rw-r--r--test/performance/.gitignore1
-rw-r--r--test/performance/Makefile.am10
-rw-r--r--test/performance/odp_scheduling.c1143
3 files changed, 1154 insertions, 0 deletions
diff --git a/test/performance/.gitignore b/test/performance/.gitignore
new file mode 100644
index 000000000..a229e1032
--- /dev/null
+++ b/test/performance/.gitignore
@@ -0,0 +1 @@
+odp_scheduling
diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am
new file mode 100644
index 000000000..359c4f07b
--- /dev/null
+++ b/test/performance/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/test/Makefile.inc
+
+bin_PROGRAMS = odp_scheduling
+odp_scheduling_LDFLAGS = $(AM_LDFLAGS) -static
+odp_scheduling_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/test
+
+noinst_HEADERS = \
+ $(top_srcdir)/test/test_debug.h
+
+dist_odp_scheduling_SOURCES = odp_scheduling.c
diff --git a/test/performance/odp_scheduling.c b/test/performance/odp_scheduling.c
new file mode 100644
index 000000000..a18e85810
--- /dev/null
+++ b/test/performance/odp_scheduling.c
@@ -0,0 +1,1143 @@
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * @example odp_example.c ODP example application
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <test_debug.h>
+
+/* ODP main header */
+#include <odp.h>
+
+/* ODP helper for Linux apps */
+#include <odph_linux.h>
+
+/* Needs librt*/
+#include <time.h>
+
+/* GNU lib C */
+#include <getopt.h>
+
+
+#define MAX_WORKERS 32 /**< Max worker threads */
+#define MSG_POOL_SIZE (4*1024*1024) /**< Message pool size */
+#define MAX_ALLOCS 35 /**< Alloc burst size */
+#define QUEUES_PER_PRIO 64 /**< Queue per priority */
+#define QUEUE_ROUNDS (512*1024) /**< Queue test rounds */
+#define ALLOC_ROUNDS (1024*1024) /**< Alloc test rounds */
+#define MULTI_BUFS_MAX 4 /**< Buffer burst size */
+#define TEST_SEC 2 /**< Time test duration in sec */
+
+/** Dummy message */
+typedef struct {
+ int msg_id; /**< Message ID */
+ int seq; /**< Sequence number */
+} test_message_t;
+
+#define MSG_HELLO 1 /**< Hello */
+#define MSG_ACK 2 /**< Ack */
+
+/** Test arguments */
+typedef struct {
+ int core_count; /**< Core count */
+ int proc_mode; /**< Process mode */
+} test_args_t;
+
+
+/** Test global variables */
+typedef struct {
+ odp_barrier_t barrier;/**< @private Barrier for test synchronisation */
+} test_globals_t;
+
+
+/**
+ * @internal Clear all scheduled queues. Retry to be sure that all
+ * buffers have been scheduled.
+ */
+static void clear_sched_queues(void)
+{
+ odp_buffer_t buf;
+
+ while (1) {
+ buf = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
+
+ if (buf == ODP_BUFFER_INVALID)
+ break;
+
+ odp_buffer_free(buf);
+ }
+}
+
+/**
+ * @internal Create a single queue from a pool of buffers
+ *
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Queue priority
+ *
+ * @return 0 if successful
+ */
+static int create_queue(int thr, odp_buffer_pool_t msg_pool, int prio)
+{
+ char name[] = "sched_XX_00";
+ odp_buffer_t buf;
+ odp_queue_t queue;
+
+ buf = odp_buffer_alloc(msg_pool);
+
+ if (!odp_buffer_is_valid(buf)) {
+ LOG_ERR(" [%i] msg_pool alloc failed\n", thr);
+ return -1;
+ }
+
+ name[6] = '0' + prio/10;
+ name[7] = '0' + prio - 10*(prio/10);
+
+ queue = odp_queue_lookup(name);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR(" [%i] Queue %s lookup failed.\n", thr, name);
+ return -1;
+ }
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * @internal Create multiple queues from a pool of buffers
+ *
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Queue priority
+ *
+ * @return 0 if successful
+ */
+static int create_queues(int thr, odp_buffer_pool_t msg_pool, int prio)
+{
+ char name[] = "sched_XX_YY";
+ odp_buffer_t buf;
+ odp_queue_t queue;
+ int i;
+
+ name[6] = '0' + prio/10;
+ name[7] = '0' + prio - 10*(prio/10);
+
+ /* Alloc and enqueue a buffer per queue */
+ for (i = 0; i < QUEUES_PER_PRIO; i++) {
+ name[9] = '0' + i/10;
+ name[10] = '0' + i - 10*(i/10);
+
+ queue = odp_queue_lookup(name);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR(" [%i] Queue %s lookup failed.\n", thr,
+ name);
+ return -1;
+ }
+
+ buf = odp_buffer_alloc(msg_pool);
+
+ if (!odp_buffer_is_valid(buf)) {
+ LOG_ERR(" [%i] msg_pool alloc failed\n", thr);
+ return -1;
+ }
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * @internal Test single buffer alloc and free
+ *
+ * @param thr Thread
+ * @param pool Buffer pool
+ *
+ * @return 0 if successful
+ */
+static int test_alloc_single(int thr, odp_buffer_pool_t pool)
+{
+ int i;
+ odp_buffer_t temp_buf;
+ uint64_t t1, t2, cycles, ns;
+
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < ALLOC_ROUNDS; i++) {
+ temp_buf = odp_buffer_alloc(pool);
+
+ if (!odp_buffer_is_valid(temp_buf)) {
+ LOG_ERR(" [%i] alloc_single failed\n", thr);
+ return -1;
+ }
+
+ odp_buffer_free(temp_buf);
+ }
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ printf(" [%i] alloc_sng alloc+free %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, cycles/ALLOC_ROUNDS, ns/ALLOC_ROUNDS);
+
+ return 0;
+}
+
+/**
+ * @internal Test multiple buffers alloc and free
+ *
+ * @param thr Thread
+ * @param pool Buffer pool
+ *
+ * @return 0 if successful
+ */
+static int test_alloc_multi(int thr, odp_buffer_pool_t pool)
+{
+ int i, j;
+ odp_buffer_t temp_buf[MAX_ALLOCS];
+ uint64_t t1, t2, cycles, ns;
+
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < ALLOC_ROUNDS; i++) {
+ for (j = 0; j < MAX_ALLOCS; j++) {
+ temp_buf[j] = odp_buffer_alloc(pool);
+
+ if (!odp_buffer_is_valid(temp_buf[j])) {
+ LOG_ERR(" [%i] alloc_multi failed\n", thr);
+ return -1;
+ }
+ }
+
+ for (; j > 0; j--)
+ odp_buffer_free(temp_buf[j-1]);
+ }
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ printf(" [%i] alloc_multi alloc+free %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, cycles/(ALLOC_ROUNDS*MAX_ALLOCS),
+ ns/(ALLOC_ROUNDS*MAX_ALLOCS));
+
+ return 0;
+}
+
+/**
+ * @internal Test queue polling
+ *
+ * Enqueue to and dequeue to/from a single shared queue.
+ *
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ *
+ * @return 0 if successful
+ */
+static int test_poll_queue(int thr, odp_buffer_pool_t msg_pool)
+{
+ odp_buffer_t buf;
+ test_message_t *t_msg;
+ odp_queue_t queue;
+ uint64_t t1, t2, cycles, ns;
+ int i;
+
+ /* Alloc test message */
+ buf = odp_buffer_alloc(msg_pool);
+
+ if (!odp_buffer_is_valid(buf)) {
+ LOG_ERR(" [%i] msg_pool alloc failed\n", thr);
+ return -1;
+ }
+
+ /* odp_buffer_print(buf); */
+
+ t_msg = odp_buffer_addr(buf);
+ t_msg->msg_id = MSG_HELLO;
+ t_msg->seq = 0;
+
+ queue = odp_queue_lookup("poll_queue");
+
+ if (queue == ODP_QUEUE_INVALID) {
+ printf(" [%i] Queue lookup failed.\n", thr);
+ return -1;
+ }
+
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+
+ buf = odp_queue_deq(queue);
+
+ if (!odp_buffer_is_valid(buf)) {
+ LOG_ERR(" [%i] Queue empty.\n", thr);
+ return -1;
+ }
+ }
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ printf(" [%i] poll_queue enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, cycles/QUEUE_ROUNDS, ns/QUEUE_ROUNDS);
+
+ odp_buffer_free(buf);
+ return 0;
+}
+
+/**
+ * @internal Test scheduling of a single queue - with odp_schedule_one()
+ *
+ * Enqueue a buffer to the shared queue. Schedule and enqueue the received
+ * buffer back into the queue.
+ *
+ * @param str Test case name string
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Priority
+ * @param barrier Barrier
+ *
+ * @return 0 if successful
+ */
+static int test_schedule_one_single(const char *str, int thr,
+ odp_buffer_pool_t msg_pool,
+ int prio, odp_barrier_t *barrier)
+{
+ odp_buffer_t buf;
+ odp_queue_t queue;
+ uint64_t t1, t2, cycles, ns;
+ uint32_t i;
+ uint32_t tot = 0;
+
+ if (create_queue(thr, msg_pool, prio))
+ return -1;
+
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ buf = odp_schedule_one(&queue, ODP_SCHED_WAIT);
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ if (odp_queue_sched_type(queue) == ODP_SCHED_SYNC_ATOMIC)
+ odp_schedule_release_atomic();
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+ tot = i;
+
+ odp_barrier_wait(barrier);
+ clear_sched_queues();
+
+ cycles = cycles/tot;
+ ns = ns/tot;
+
+ printf(" [%i] %s enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, str, cycles, ns);
+
+ return 0;
+}
+
+/**
+ * @internal Test scheduling of multiple queues - with odp_schedule_one()
+ *
+ * Enqueue a buffer to each queue. Schedule and enqueue the received
+ * buffer back into the queue it came from.
+ *
+ * @param str Test case name string
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Priority
+ * @param barrier Barrier
+ *
+ * @return 0 if successful
+ */
+static int test_schedule_one_many(const char *str, int thr,
+ odp_buffer_pool_t msg_pool,
+ int prio, odp_barrier_t *barrier)
+{
+ odp_buffer_t buf;
+ odp_queue_t queue;
+ uint64_t t1 = 0;
+ uint64_t t2 = 0;
+ uint64_t cycles, ns;
+ uint32_t i;
+ uint32_t tot = 0;
+
+ if (create_queues(thr, msg_pool, prio))
+ return -1;
+
+ /* Start sched-enq loop */
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ buf = odp_schedule_one(&queue, ODP_SCHED_WAIT);
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ if (odp_queue_sched_type(queue) == ODP_SCHED_SYNC_ATOMIC)
+ odp_schedule_release_atomic();
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+ tot = i;
+
+ odp_barrier_wait(barrier);
+ clear_sched_queues();
+
+ cycles = cycles/tot;
+ ns = ns/tot;
+
+ printf(" [%i] %s enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, str, cycles, ns);
+
+ return 0;
+}
+
+/**
+ * @internal Test scheduling of a single queue - with odp_schedule()
+ *
+ * Enqueue a buffer to the shared queue. Schedule and enqueue the received
+ * buffer back into the queue.
+ *
+ * @param str Test case name string
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Priority
+ * @param barrier Barrier
+ *
+ * @return 0 if successful
+ */
+static int test_schedule_single(const char *str, int thr,
+ odp_buffer_pool_t msg_pool,
+ int prio, odp_barrier_t *barrier)
+{
+ odp_buffer_t buf;
+ odp_queue_t queue;
+ uint64_t t1, t2, cycles, ns;
+ uint32_t i;
+ uint32_t tot = 0;
+
+ if (create_queue(thr, msg_pool, prio))
+ return -1;
+
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ buf = odp_schedule(&queue, ODP_SCHED_WAIT);
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ /* Clear possible locally stored buffers */
+ odp_schedule_pause();
+
+ tot = i;
+
+ while (1) {
+ buf = odp_schedule(&queue, ODP_SCHED_NO_WAIT);
+
+ if (buf == ODP_BUFFER_INVALID)
+ break;
+
+ tot++;
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ odp_schedule_resume();
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ odp_barrier_wait(barrier);
+ clear_sched_queues();
+
+ cycles = cycles/tot;
+ ns = ns/tot;
+
+ printf(" [%i] %s enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, str, cycles, ns);
+
+ return 0;
+}
+
+
+/**
+ * @internal Test scheduling of multiple queues - with odp_schedule()
+ *
+ * Enqueue a buffer to each queue. Schedule and enqueue the received
+ * buffer back into the queue it came from.
+ *
+ * @param str Test case name string
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Priority
+ * @param barrier Barrier
+ *
+ * @return 0 if successful
+ */
+static int test_schedule_many(const char *str, int thr,
+ odp_buffer_pool_t msg_pool,
+ int prio, odp_barrier_t *barrier)
+{
+ odp_buffer_t buf;
+ odp_queue_t queue;
+ uint64_t t1 = 0;
+ uint64_t t2 = 0;
+ uint64_t cycles, ns;
+ uint32_t i;
+ uint32_t tot = 0;
+
+ if (create_queues(thr, msg_pool, prio))
+ return -1;
+
+ /* Start sched-enq loop */
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ buf = odp_schedule(&queue, ODP_SCHED_WAIT);
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ /* Clear possible locally stored buffers */
+ odp_schedule_pause();
+
+ tot = i;
+
+ while (1) {
+ buf = odp_schedule(&queue, ODP_SCHED_NO_WAIT);
+
+ if (buf == ODP_BUFFER_INVALID)
+ break;
+
+ tot++;
+
+ if (odp_queue_enq(queue, buf)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ odp_schedule_resume();
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ odp_barrier_wait(barrier);
+ clear_sched_queues();
+
+ cycles = cycles/tot;
+ ns = ns/tot;
+
+ printf(" [%i] %s enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, str, cycles, ns);
+
+ return 0;
+}
+
+/**
+ * @internal Test scheduling of multiple queues with multi_sched and multi_enq
+ *
+ * @param str Test case name string
+ * @param thr Thread
+ * @param msg_pool Buffer pool
+ * @param prio Priority
+ * @param barrier Barrier
+ *
+ * @return 0 if successful
+ */
+static int test_schedule_multi(const char *str, int thr,
+ odp_buffer_pool_t msg_pool,
+ int prio, odp_barrier_t *barrier)
+{
+ odp_buffer_t buf[MULTI_BUFS_MAX];
+ odp_queue_t queue;
+ uint64_t t1 = 0;
+ uint64_t t2 = 0;
+ uint64_t cycles, ns;
+ int i, j;
+ int num;
+ uint32_t tot = 0;
+ char name[] = "sched_XX_YY";
+
+ name[6] = '0' + prio/10;
+ name[7] = '0' + prio - 10*(prio/10);
+
+ /* Alloc and enqueue a buffer per queue */
+ for (i = 0; i < QUEUES_PER_PRIO; i++) {
+ name[9] = '0' + i/10;
+ name[10] = '0' + i - 10*(i/10);
+
+ queue = odp_queue_lookup(name);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR(" [%i] Queue %s lookup failed.\n", thr,
+ name);
+ return -1;
+ }
+
+ for (j = 0; j < MULTI_BUFS_MAX; j++) {
+ buf[j] = odp_buffer_alloc(msg_pool);
+
+ if (!odp_buffer_is_valid(buf[j])) {
+ LOG_ERR(" [%i] msg_pool alloc failed\n",
+ thr);
+ return -1;
+ }
+ }
+
+ if (odp_queue_enq_multi(queue, buf, MULTI_BUFS_MAX)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ /* Start sched-enq loop */
+ t1 = odp_time_cycles();
+
+ for (i = 0; i < QUEUE_ROUNDS; i++) {
+ num = odp_schedule_multi(&queue, ODP_SCHED_WAIT, buf,
+ MULTI_BUFS_MAX);
+
+ tot += num;
+
+ if (odp_queue_enq_multi(queue, buf, num)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ /* Clear possible locally stored buffers */
+ odp_schedule_pause();
+
+ while (1) {
+ num = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT, buf,
+ MULTI_BUFS_MAX);
+
+ if (num == 0)
+ break;
+
+ tot += num;
+
+ if (odp_queue_enq_multi(queue, buf, num)) {
+ LOG_ERR(" [%i] Queue enqueue failed.\n", thr);
+ return -1;
+ }
+ }
+
+ odp_schedule_resume();
+
+
+ t2 = odp_time_cycles();
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns = odp_time_cycles_to_ns(cycles);
+
+ odp_barrier_wait(barrier);
+ clear_sched_queues();
+
+ if (tot) {
+ cycles = cycles/tot;
+ ns = ns/tot;
+ } else {
+ cycles = 0;
+ ns = 0;
+ }
+
+ printf(" [%i] %s enq+deq %"PRIu64" cycles, %"PRIu64" ns\n",
+ thr, str, cycles, ns);
+
+ return 0;
+}
+
+/**
+ * @internal Worker thread
+ *
+ * @param arg Arguments
+ *
+ * @return NULL on failure
+ */
+static void *run_thread(void *arg)
+{
+ int thr;
+ odp_buffer_pool_t msg_pool;
+ odp_shm_t shm;
+ test_globals_t *globals;
+ odp_barrier_t *barrier;
+
+ thr = odp_thread_id();
+
+ printf("Thread %i starts on core %i\n", thr, odp_thread_core());
+
+ shm = odp_shm_lookup("test_globals");
+ globals = odp_shm_addr(shm);
+
+ if (globals == NULL) {
+ LOG_ERR("Shared mem lookup failed\n");
+ return NULL;
+ }
+
+ barrier = &globals->barrier;
+
+ /*
+ * Test barriers back-to-back
+ */
+ odp_barrier_wait(barrier);
+ odp_barrier_wait(barrier);
+ odp_barrier_wait(barrier);
+ odp_barrier_wait(barrier);
+
+ /*
+ * Find the buffer pool
+ */
+ msg_pool = odp_buffer_pool_lookup("msg_pool");
+
+ if (msg_pool == ODP_BUFFER_POOL_INVALID) {
+ LOG_ERR(" [%i] msg_pool not found\n", thr);
+ return NULL;
+ }
+
+ odp_barrier_wait(barrier);
+
+ if (test_alloc_single(thr, msg_pool))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_alloc_multi(thr, msg_pool))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_poll_queue(thr, msg_pool))
+ return NULL;
+
+ /* Low prio */
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_one_single("sched_one_s_lo", thr, msg_pool,
+ ODP_SCHED_PRIO_LOWEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_single("sched_____s_lo", thr, msg_pool,
+ ODP_SCHED_PRIO_LOWEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_one_many("sched_one_m_lo", thr, msg_pool,
+ ODP_SCHED_PRIO_LOWEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_many("sched_____m_lo", thr, msg_pool,
+ ODP_SCHED_PRIO_LOWEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_multi("sched_multi_lo", thr, msg_pool,
+ ODP_SCHED_PRIO_LOWEST, barrier))
+ return NULL;
+
+ /* High prio */
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_one_single("sched_one_s_hi", thr, msg_pool,
+ ODP_SCHED_PRIO_HIGHEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_single("sched_____s_hi", thr, msg_pool,
+ ODP_SCHED_PRIO_HIGHEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_one_many("sched_one_m_hi", thr, msg_pool,
+ ODP_SCHED_PRIO_HIGHEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_many("sched_____m_hi", thr, msg_pool,
+ ODP_SCHED_PRIO_HIGHEST, barrier))
+ return NULL;
+
+ odp_barrier_wait(barrier);
+
+ if (test_schedule_multi("sched_multi_hi", thr, msg_pool,
+ ODP_SCHED_PRIO_HIGHEST, barrier))
+ return NULL;
+
+
+ printf("Thread %i exits\n", thr);
+ fflush(NULL);
+ return arg;
+}
+
+/**
+ * @internal Test cycle counter accuracy
+ */
+static void test_time(void)
+{
+ struct timespec tp1, tp2;
+ uint64_t t1, t2;
+ uint64_t ns1, ns2, cycles;
+ double err;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp2)) {
+ LOG_ERR("clock_gettime failed.\n");
+ return;
+ }
+
+ printf("\nTime accuracy test (%i sec)\n", TEST_SEC);
+
+ do {
+ if (clock_gettime(CLOCK_MONOTONIC, &tp1)) {
+ LOG_ERR("clock_gettime failed.\n");
+ return;
+ }
+
+ } while (tp1.tv_sec == tp2.tv_sec);
+
+ t1 = odp_time_cycles();
+
+ do {
+ if (clock_gettime(CLOCK_MONOTONIC, &tp2)) {
+ LOG_ERR("clock_gettime failed.\n");
+ return;
+ }
+
+ } while ((tp2.tv_sec - tp1.tv_sec) < TEST_SEC);
+
+ t2 = odp_time_cycles();
+
+ ns1 = (tp2.tv_sec - tp1.tv_sec)*1000000000;
+
+ if (tp2.tv_nsec > tp1.tv_nsec)
+ ns1 += tp2.tv_nsec - tp1.tv_nsec;
+ else
+ ns1 -= tp1.tv_nsec - tp2.tv_nsec;
+
+ cycles = odp_time_diff_cycles(t1, t2);
+ ns2 = odp_time_cycles_to_ns(cycles);
+
+ err = ((double)(ns2) - (double)ns1) / (double)ns1;
+
+ printf("clock_gettime %"PRIu64" ns\n", ns1);
+ printf("odp_time_cycles %"PRIu64" cycles\n", cycles);
+ printf("odp_time_cycles_to_ns %"PRIu64" ns\n", ns2);
+ printf("odp get cycle error %f%%\n", err*100.0);
+
+ printf("\n");
+}
+
+/**
+ * @internal Print help
+ */
+static void print_usage(void)
+{
+ printf("\n\nUsage: ./odp_example [options]\n");
+ printf("Options:\n");
+ printf(" -c, --count <number> core count, core IDs start from 1\n");
+ printf(" -h, --help this help\n");
+ printf(" --proc process mode\n");
+ printf("\n\n");
+}
+
+/**
+ * @internal Parse arguments
+ *
+ * @param argc Argument count
+ * @param argv Argument vector
+ * @param args Test arguments
+ */
+static void parse_args(int argc, char *argv[], test_args_t *args)
+{
+ int opt;
+ int long_index;
+
+ static struct option longopts[] = {
+ {"count", required_argument, NULL, 'c'},
+ {"help", no_argument, NULL, 'h'},
+ {"proc", no_argument, NULL, 0},
+ {NULL, 0, NULL, 0}
+ };
+
+ while (1) {
+ opt = getopt_long(argc, argv, "+c:h", longopts, &long_index);
+
+ if (opt == -1)
+ break; /* No more options */
+
+ switch (opt) {
+ case 0:
+ args->proc_mode = 1;
+ break;
+
+ case 'c':
+ args->core_count = atoi(optarg);
+ break;
+
+ case 'h':
+ print_usage();
+ exit(EXIT_SUCCESS);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/**
+ * Test main function
+ */
+int main(int argc, char *argv[])
+{
+ odph_linux_pthread_t thread_tbl[MAX_WORKERS];
+ test_args_t args;
+ int num_workers;
+ odp_buffer_pool_t pool;
+ odp_queue_t queue;
+ int i, j;
+ int prios;
+ int first_core;
+ odp_shm_t shm;
+ test_globals_t *globals;
+ odp_buffer_pool_param_t params;
+
+ printf("\nODP example starts\n\n");
+
+ memset(&args, 0, sizeof(args));
+ parse_args(argc, argv, &args);
+
+ if (args.proc_mode)
+ printf("Process mode\n");
+ else
+ printf("Thread mode\n");
+
+ memset(thread_tbl, 0, sizeof(thread_tbl));
+
+ /* ODP global init */
+ if (odp_init_global(NULL, NULL)) {
+ LOG_ERR("ODP global init failed.\n");
+ return -1;
+ }
+
+ /*
+ * Init this thread. It makes also ODP calls when
+ * setting up resources for worker threads.
+ */
+ if (odp_init_local()) {
+ LOG_ERR("ODP global init failed.\n");
+ return -1;
+ }
+
+ printf("\n");
+ printf("ODP system info\n");
+ printf("---------------\n");
+ printf("ODP API version: %s\n", odp_version_api_str());
+ printf("CPU model: %s\n", odp_sys_cpu_model_str());
+ printf("CPU freq (hz): %"PRIu64"\n", odp_sys_cpu_hz());
+ printf("Cache line size: %i\n", odp_sys_cache_line_size());
+ printf("Max core count: %i\n", odp_sys_core_count());
+
+ printf("\n");
+
+ /* A worker thread per core */
+ num_workers = odp_sys_core_count();
+
+ if (args.core_count)
+ num_workers = args.core_count;
+
+ /* force to max core count */
+ if (num_workers > MAX_WORKERS)
+ num_workers = MAX_WORKERS;
+
+ printf("num worker threads: %i\n", num_workers);
+
+ /*
+ * By default core #0 runs Linux kernel background tasks.
+ * Start mapping thread from core #1
+ */
+ first_core = 1;
+
+ if (odp_sys_core_count() == 1)
+ first_core = 0;
+
+ printf("first core: %i\n", first_core);
+
+
+ /* Test cycle count accuracy */
+ test_time();
+
+ shm = odp_shm_reserve("test_globals",
+ sizeof(test_globals_t), ODP_CACHE_LINE_SIZE, 0);
+
+ globals = odp_shm_addr(shm);
+
+ if (globals == NULL) {
+ LOG_ERR("Shared memory reserve failed.\n");
+ return -1;
+ }
+
+ memset(globals, 0, sizeof(test_globals_t));
+
+ /*
+ * Create message pool
+ */
+
+ params.buf_size = sizeof(test_message_t);
+ params.buf_align = 0;
+ params.num_bufs = MSG_POOL_SIZE/sizeof(test_message_t);
+ params.buf_type = ODP_BUFFER_TYPE_RAW;
+
+ pool = odp_buffer_pool_create("msg_pool", ODP_SHM_NULL, &params);
+
+ if (pool == ODP_BUFFER_POOL_INVALID) {
+ LOG_ERR("Pool create failed.\n");
+ return -1;
+ }
+
+ /* odp_buffer_pool_print(pool); */
+
+ /*
+ * Create a queue for direct poll test
+ */
+ queue = odp_queue_create("poll_queue", ODP_QUEUE_TYPE_POLL, NULL);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR("Poll queue create failed.\n");
+ return -1;
+ }
+
+ /*
+ * Create queues for schedule test. QUEUES_PER_PRIO per priority.
+ */
+ prios = odp_schedule_num_prio();
+
+ for (i = 0; i < prios; i++) {
+ if (i != ODP_SCHED_PRIO_HIGHEST &&
+ i != ODP_SCHED_PRIO_LOWEST)
+ continue;
+
+ odp_queue_param_t param;
+ char name[] = "sched_XX_YY";
+
+ name[6] = '0' + i/10;
+ name[7] = '0' + i - 10*(i/10);
+
+ param.sched.prio = i;
+ param.sched.sync = ODP_SCHED_SYNC_ATOMIC;
+ param.sched.group = ODP_SCHED_GROUP_DEFAULT;
+
+ for (j = 0; j < QUEUES_PER_PRIO; j++) {
+ name[9] = '0' + j/10;
+ name[10] = '0' + j - 10*(j/10);
+
+ queue = odp_queue_create(name, ODP_QUEUE_TYPE_SCHED,
+ &param);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR("Schedule queue create failed.\n");
+ return -1;
+ }
+ }
+ }
+
+ odp_shm_print_all();
+
+ /* Barrier to sync test case execution */
+ odp_barrier_init(&globals->barrier, num_workers);
+
+ if (args.proc_mode) {
+ int ret;
+ odph_linux_process_t proc[MAX_WORKERS];
+
+ /* Fork worker processes */
+ ret = odph_linux_process_fork_n(proc, num_workers,
+ first_core);
+
+ if (ret < 0) {
+ LOG_ERR("Fork workers failed %i\n", ret);
+ return -1;
+ }
+
+ if (ret == 0) {
+ /* Child process */
+ run_thread(NULL);
+ } else {
+ /* Parent process */
+ odph_linux_process_wait_n(proc, num_workers);
+ printf("ODP example complete\n\n");
+ }
+
+ } else {
+ /* Create and launch worker threads */
+ odph_linux_pthread_create(thread_tbl, num_workers, first_core,
+ run_thread, NULL);
+
+ /* Wait for worker threads to terminate */
+ odph_linux_pthread_join(thread_tbl, num_workers);
+
+ printf("ODP example complete\n\n");
+ }
+
+ return 0;
+}