From: Petri Savolainen <petri.savolai...@linaro.org> Added support for multiple threads and -c options to select number of worker threads.
Signed-off-by: Petri Savolainen <petri.savolai...@linaro.org> --- /** Email created from pull request 680 (psavol:master-test-queue-perf-multithread) ** https://github.com/Linaro/odp/pull/680 ** Patch: https://github.com/Linaro/odp/pull/680.patch ** Base sha: 1c36bf726387b291d73bee1448cf163527cf5fb0 ** Merge commit sha: cce6d22c7a83b846bd9589a48869c664f75980ae **/ test/performance/odp_queue_perf.c | 153 ++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 37 deletions(-) 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");