diff options
author | Matias Elo <matias.elo@nokia.com> | 2022-10-19 17:23:57 +0300 |
---|---|---|
committer | Matias Elo <matias.elo@nokia.com> | 2022-10-25 14:22:24 +0300 |
commit | 14f5c6bd124fb4f57bc718551d873b7bfd231b43 (patch) | |
tree | 3acca92ee84fbfb7cfda31b309236adf5df98578 /test | |
parent | 2f64f805f030a6d1ac674b8f8a4086ddb378878d (diff) |
test: perf: add new buffer_bench application
Add new odp_bench_buffer microbenchmark application for testing buffer and
event fast path functions.
Signed-off-by: Matias Elo <matias.elo@nokia.com>
Reviewed-by: Petri Savolainen <petri.savolainen@nokia.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/performance/.gitignore | 1 | ||||
-rw-r--r-- | test/performance/Makefile.am | 2 | ||||
-rw-r--r-- | test/performance/odp_bench_buffer.c | 920 |
3 files changed, 923 insertions, 0 deletions
diff --git a/test/performance/.gitignore b/test/performance/.gitignore index 22abea846..3a32d0420 100644 --- a/test/performance/.gitignore +++ b/test/performance/.gitignore @@ -2,6 +2,7 @@ *.trs odp_atomic odp_atomic_perf +odp_bench_buffer odp_bench_packet odp_cpu_bench odp_crc diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am index c215e7151..b0885808e 100644 --- a/test/performance/Makefile.am +++ b/test/performance/Makefile.am @@ -3,6 +3,7 @@ include $(top_srcdir)/test/Makefile.inc TESTS_ENVIRONMENT += TEST_DIR=${builddir} EXECUTABLES = odp_atomic_perf \ + odp_bench_buffer \ odp_bench_packet \ odp_crc \ odp_lock_perf \ @@ -51,6 +52,7 @@ endif bin_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) odp_atomic_perf_SOURCES = odp_atomic_perf.c +odp_bench_buffer_SOURCES = odp_bench_buffer.c odp_bench_packet_SOURCES = odp_bench_packet.c odp_cpu_bench_SOURCES = odp_cpu_bench.c odp_crc_SOURCES = odp_crc.c diff --git a/test/performance/odp_bench_buffer.c b/test/performance/odp_bench_buffer.c new file mode 100644 index 000000000..e7029f57d --- /dev/null +++ b/test/performance/odp_bench_buffer.c @@ -0,0 +1,920 @@ +/* Copyright (c) 2017-2018, Linaro Limited + * Copyright (c) 2022, Nokia + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp_api.h> +#include <odp/helper/odph_api.h> + +#include <getopt.h> +#include <inttypes.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> + +/** Default buffer size */ +#define TEST_BUF_SIZE 1024 + +/** Default pool user area size in bytes */ +#define TEST_UAREA_SIZE 8 + +/** Number of function calls per test cycle */ +#define TEST_REPEAT_COUNT 1000 + +/** Default number of test cycles */ +#define TEST_CYCLES 1000 + +/** Maximum burst size for *_multi operations */ +#define TEST_MAX_BURST 64 + +/** Default burst size for *_multi operations */ +#define TEST_DEF_BURST 8 + +/** Get rid of path in filename - only for unix-type paths using '/' */ +#define NO_PATH(file_name) (strrchr((file_name), '/') ? \ + strrchr((file_name), '/') + 1 : (file_name)) + +#define BENCH_INFO(run, init, term, name) \ + {#run, run, init, term, name, NULL} + +#define BENCH_INFO_COND(run, init, term, name, cond) \ + {#run, run, init, term, name, cond} + +/** + * Parsed command line arguments + */ +typedef struct { + int bench_idx; /** Benchmark index to run indefinitely */ + int burst_size; /** Burst size for *_multi operations */ + int cache_size; /** Pool cache size */ + int test_cycles; /** Test cycles per tested function */ +} appl_args_t; + +/** + * Initialize benchmark resources + */ +typedef void (*bench_init_fn_t)(void); + +/** + * Run benchmark + * + * @retval >0 on success + * */ +typedef int (*bench_run_fn_t)(void); + +/** + * Release benchmark resources + */ +typedef void (*bench_term_fn_t)(void); + +/** + * Check benchmark preconditions + * + * @retval !0 test enabled + * */ +typedef int (*bench_cond_fn_t)(void); + +/** + * Benchmark data + */ +typedef struct { + const char *name; + bench_run_fn_t run; + bench_init_fn_t init; + bench_term_fn_t term; + const char *desc; + bench_cond_fn_t cond; +} bench_info_t; + +/** + * Grouping of all global data + */ +typedef struct { + /** Application (parsed) arguments */ + appl_args_t appl; + /** Buffer pool */ + odp_pool_t pool; + /** Benchmark functions */ + bench_info_t *bench; + /** Number of benchmark functions */ + int num_bench; + /** Buffer size */ + uint32_t buf_size; + /** Buffer user area size */ + uint32_t uarea_size; + /** Max flow id */ + uint32_t max_flow_id; + /** Break worker loop if set to 1 */ + odp_atomic_u32_t exit_thread; + /** Array for storing test buffers */ + odp_buffer_t buf_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST]; + /** Array for storing test event */ + odp_event_t event_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST]; + /** Array for storing test pointers */ + void *ptr_tbl[TEST_REPEAT_COUNT]; + /** Array for storing test pool handles */ + odp_pool_t pool_tbl[TEST_REPEAT_COUNT]; + /** Array for storing test event types */ + odp_event_type_t event_type_tbl[TEST_REPEAT_COUNT]; + /** Array for storing test event subtypes */ + odp_event_subtype_t event_subtype_tbl[TEST_REPEAT_COUNT]; + /** Benchmark run failed */ + uint8_t bench_failed; + /** CPU mask as string */ + char cpumask_str[ODP_CPUMASK_STR_SIZE]; +} args_t; + +/** Global pointer to args */ +static args_t *gbl_args; + +static void sig_handler(int signo ODP_UNUSED) +{ + if (gbl_args == NULL) + return; + odp_atomic_store_u32(&gbl_args->exit_thread, 1); +} + +/** + * Run given benchmark indefinitely + */ +static void run_indef(args_t *args, int idx) +{ + const char *desc; + + desc = args->bench[idx].desc != NULL ? + args->bench[idx].desc : args->bench[idx].name; + + printf("Running odp_%s test indefinitely\n", desc); + + while (!odp_atomic_load_u32(&gbl_args->exit_thread)) { + int ret; + + if (args->bench[idx].init != NULL) + args->bench[idx].init(); + + ret = args->bench[idx].run(); + + if (args->bench[idx].term != NULL) + args->bench[idx].term(); + + if (!ret) + ODPH_ABORT("Benchmark %s failed\n", desc); + } +} + +static int run_benchmarks(void *arg) +{ + int i, j, k; + args_t *args = arg; + + printf("\nAverage CPU cycles per function call\n" + "---------------------------------------------\n"); + + /* Run each test twice. Results from the first warm-up round are ignored. */ + for (i = 0; i < 2; i++) { + uint64_t tot_cycles = 0; + + for (j = 0, k = 1; j < gbl_args->num_bench; k++) { + int ret; + uint64_t c1, c2; + const char *desc; + + /* Run selected test indefinitely */ + if (args->appl.bench_idx && + (j + 1) != args->appl.bench_idx) { + j++; + continue; + } else if (args->appl.bench_idx && + (j + 1) == args->appl.bench_idx) { + run_indef(args, j); + return 0; + } + + desc = args->bench[j].desc != NULL ? + args->bench[j].desc : + args->bench[j].name; + + /* Skip unsupported tests */ + if (args->bench[j].cond != NULL && !args->bench[j].cond()) { + j++; + k = 0; + if (i > 0) + printf("[%02d] odp_%-26s: n/a\n", j, desc); + continue; + } + + if (args->bench[j].init != NULL) + args->bench[j].init(); + + c1 = odp_cpu_cycles(); + ret = args->bench[j].run(); + c2 = odp_cpu_cycles(); + + if (args->bench[j].term != NULL) + args->bench[j].term(); + + if (!ret) { + ODPH_ERR("Benchmark odp_%s failed\n", desc); + args->bench_failed = 1; + return -1; + } + + tot_cycles += odp_cpu_cycles_diff(c2, c1); + + if (k >= args->appl.test_cycles) { + double cycles; + + /** Each benchmark runs internally TEST_REPEAT_COUNT times. */ + cycles = ((double)tot_cycles) / + (args->appl.test_cycles * + TEST_REPEAT_COUNT); + + /* No print from warm-up round */ + if (i > 0) + printf("[%02d] odp_%-26s: %8.1f\n", j + 1, desc, cycles); + + j++; + k = 0; + tot_cycles = 0; + } + } + } + printf("\n"); + + return 0; +} + +static void allocate_test_buffers(odp_buffer_t buf[], int num) +{ + int num_buf = 0; + + while (num_buf < num) { + int ret; + + ret = odp_buffer_alloc_multi(gbl_args->pool, &buf[num_buf], num - num_buf); + if (ret < 0) + ODPH_ABORT("Allocating test buffers failed\n"); + + num_buf += ret; + } +} + +static void alloc_buffers_multi(void) +{ + allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size); +} + +static void create_buffers(void) +{ + allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT); +} + +static void create_events(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + + allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT); + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + gbl_args->event_tbl[i] = odp_buffer_to_event(buf_tbl[i]); +} + +static void create_events_multi(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + + allocate_test_buffers(gbl_args->buf_tbl, + TEST_REPEAT_COUNT * gbl_args->appl.burst_size); + + for (int i = 0; i < TEST_REPEAT_COUNT * gbl_args->appl.burst_size; i++) + gbl_args->event_tbl[i] = odp_buffer_to_event(buf_tbl[i]); +} + +static void free_buffers(void) +{ + odp_buffer_free_multi(gbl_args->buf_tbl, TEST_REPEAT_COUNT); +} + +static void free_buffers_multi(void) +{ + odp_buffer_free_multi(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size); +} + +static int check_uarea(void) +{ + return !!gbl_args->uarea_size; +} + +static int check_flow_aware(void) +{ + return !!gbl_args->max_flow_id; +} + +static int buffer_from_event(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_event_t *event_tbl = gbl_args->event_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + buf_tbl[i] = odp_buffer_from_event(event_tbl[i]); + + return i; +} + +static int buffer_to_event(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_event_t *event_tbl = gbl_args->event_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + event_tbl[i] = odp_buffer_to_event(buf_tbl[i]); + + return i; +} + +static int buffer_addr(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + void **ptr_tbl = gbl_args->ptr_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + ptr_tbl[i] = odp_buffer_addr(buf_tbl[i]); + + return i; +} + +static int buffer_size(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + uint32_t ret = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + ret += odp_buffer_size(buf_tbl[i]); + + return ret; +} + +static int buffer_user_area(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + void **ptr_tbl = gbl_args->ptr_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + ptr_tbl[i] = odp_buffer_user_area(buf_tbl[i]); + + return i; +} + +static int buffer_pool(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_pool_t *pool_tbl = gbl_args->pool_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + pool_tbl[i] = odp_buffer_pool(buf_tbl[i]); + + return i; +} + +static int buffer_alloc(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_pool_t pool = gbl_args->pool; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + buf_tbl[i] = odp_buffer_alloc(pool); + + return i; +} + +static int buffer_alloc_multi(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_pool_t pool = gbl_args->pool; + int burst_size = gbl_args->appl.burst_size; + int num = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + num += odp_buffer_alloc_multi(pool, &buf_tbl[num], burst_size); + + return num; +} + +static int buffer_free(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_buffer_free(buf_tbl[i]); + + return i; +} + +static int buffer_free_multi(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + int burst_size = gbl_args->appl.burst_size; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_buffer_free_multi(&buf_tbl[i * burst_size], burst_size); + + return i; +} + +static int buffer_alloc_free(void) +{ + odp_pool_t pool = gbl_args->pool; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) { + odp_buffer_t buf = odp_buffer_alloc(pool); + + if (odp_unlikely(buf == ODP_BUFFER_INVALID)) + return 0; + + odp_buffer_free(buf); + } + return i; +} + +static int buffer_alloc_free_multi(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + odp_pool_t pool = gbl_args->pool; + int burst_size = gbl_args->appl.burst_size; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) { + int num = odp_buffer_alloc_multi(pool, buf_tbl, burst_size); + + if (odp_unlikely(num < 1)) + return 0; + + odp_buffer_free_multi(buf_tbl, num); + } + return i; +} + +static int buffer_is_valid(void) +{ + odp_buffer_t *buf_tbl = gbl_args->buf_tbl; + uint32_t ret = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + ret += odp_buffer_is_valid(buf_tbl[i]); + + return ret; +} + +static int event_type(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + event_type_tbl[i] = odp_event_type(event_tbl[i]); + + return i; +} + +static int event_subtype(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + odp_event_subtype_t *event_subtype_tbl = gbl_args->event_subtype_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + event_subtype_tbl[i] = odp_event_subtype(event_tbl[i]); + + return i; +} + +static int event_types(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl; + odp_event_subtype_t *event_subtype_tbl = gbl_args->event_subtype_tbl; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + event_type_tbl[i] = odp_event_types(event_tbl[i], &event_subtype_tbl[i]); + + return i; +} + +static int event_type_multi(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + odp_event_type_t *event_type_tbl = gbl_args->event_type_tbl; + int burst_size = gbl_args->appl.burst_size; + uint32_t ret = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + ret += odp_event_type_multi(&event_tbl[i * burst_size], burst_size, + &event_type_tbl[i]); + + return ret; +} + +static int event_is_valid(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + + uint32_t ret = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + ret += odp_event_is_valid(event_tbl[i]); + + return ret; +} + +static int event_free(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_event_free(event_tbl[i]); + + return i; +} + +static int event_free_multi(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + int burst_size = gbl_args->appl.burst_size; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_event_free_multi(&event_tbl[i * burst_size], burst_size); + + return i; +} + +static int event_free_sp(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + int burst_size = gbl_args->appl.burst_size; + int i; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_event_free_sp(&event_tbl[i * burst_size], burst_size); + + return i; +} + +static int event_flow_id(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + uint32_t ret = 0; + + for (int i = 0; i < TEST_REPEAT_COUNT; i++) + ret += odp_event_flow_id(event_tbl[i]); + + return !ret; +} + +static int event_flow_id_set(void) +{ + odp_event_t *event_tbl = gbl_args->event_tbl; + int i = 0; + + for (i = 0; i < TEST_REPEAT_COUNT; i++) + odp_event_flow_id_set(event_tbl[i], 0); + + return i; +} + +/** + * Print usage information + */ +static void usage(char *progname) +{ + printf("\n" + "OpenDataPlane Buffer/Event API microbenchmarks.\n" + "\n" + "Usage: %s OPTIONS\n" + " E.g. %s\n" + "\n" + "Optional OPTIONS:\n" + " -b, --burst <num> Test burst size.\n" + " -c, --cache_size <num> Pool cache size.\n" + " -i, --index <idx> Benchmark index to run indefinitely.\n" + " -t, --test_cycles <num> Run each test 'num' times (default %d).\n" + " -h, --help Display help and exit.\n\n" + "\n", NO_PATH(progname), NO_PATH(progname), TEST_CYCLES); +} + +/** + * Parse and store the command line arguments + * + * @param argc argument count + * @param argv[] argument vector + * @param appl_args Store application arguments here + */ +static void parse_args(int argc, char *argv[], appl_args_t *appl_args) +{ + int opt; + int long_index; + static const struct option longopts[] = { + {"burst", required_argument, NULL, 'b'}, + {"cache_size", required_argument, NULL, 'c'}, + {"index", required_argument, NULL, 'i'}, + {"test_cycles", required_argument, NULL, 't'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + static const char *shortopts = "c:b:i:t:h"; + + appl_args->bench_idx = 0; /* Run all benchmarks */ + appl_args->burst_size = TEST_DEF_BURST; + appl_args->cache_size = -1; + appl_args->test_cycles = TEST_CYCLES; + + while (1) { + opt = getopt_long(argc, argv, shortopts, longopts, &long_index); + + if (opt == -1) + break; /* No more options */ + + switch (opt) { + case 'c': + appl_args->cache_size = atoi(optarg); + break; + case 'b': + appl_args->burst_size = atoi(optarg); + break; + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + case 'i': + appl_args->bench_idx = atoi(optarg); + break; + case 't': + appl_args->test_cycles = atoi(optarg); + break; + default: + break; + } + } + + if (appl_args->burst_size < 1 || + appl_args->burst_size > TEST_MAX_BURST) { + printf("Invalid burst size (max %d)\n", TEST_MAX_BURST); + exit(EXIT_FAILURE); + } + + if (appl_args->test_cycles < 1) { + printf("Invalid test cycle repeat count: %d\n", appl_args->test_cycles); + exit(EXIT_FAILURE); + } + + optind = 1; /* Reset 'extern optind' from the getopt lib */ +} + +/** + * Print system and application info + */ +static void print_info(void) +{ + odp_sys_info_print(); + + printf("\n" + "odp_bench_buffer options\n" + "------------------------\n"); + + printf("Burst size: %d\n", gbl_args->appl.burst_size); + printf("Buffer size: %d\n", gbl_args->buf_size); + printf("CPU mask: %s\n", gbl_args->cpumask_str); + if (gbl_args->appl.cache_size < 0) + printf("Pool cache size: default\n"); + else + printf("Pool cache size: %d\n", gbl_args->appl.cache_size); + printf("Test cycles: %d\n", gbl_args->appl.test_cycles); + printf("\n"); +} + +/** + * Test functions + */ +bench_info_t test_suite[] = { + BENCH_INFO(buffer_from_event, create_events, free_buffers, NULL), + BENCH_INFO(buffer_to_event, create_buffers, free_buffers, NULL), + BENCH_INFO(buffer_addr, create_buffers, free_buffers, NULL), + BENCH_INFO(buffer_size, create_buffers, free_buffers, NULL), + BENCH_INFO_COND(buffer_user_area, create_buffers, free_buffers, NULL, check_uarea), + BENCH_INFO(buffer_pool, create_buffers, free_buffers, NULL), + BENCH_INFO(buffer_alloc, NULL, free_buffers, NULL), + BENCH_INFO(buffer_alloc_multi, NULL, free_buffers_multi, NULL), + BENCH_INFO(buffer_free, create_buffers, NULL, NULL), + BENCH_INFO(buffer_free_multi, alloc_buffers_multi, NULL, NULL), + BENCH_INFO(buffer_alloc_free, NULL, NULL, NULL), + BENCH_INFO(buffer_alloc_free_multi, NULL, NULL, NULL), + BENCH_INFO(buffer_is_valid, create_buffers, free_buffers, NULL), + BENCH_INFO(event_type, create_events, free_buffers, NULL), + BENCH_INFO(event_subtype, create_buffers, free_buffers, NULL), + BENCH_INFO(event_types, create_buffers, free_buffers, NULL), + BENCH_INFO(event_type_multi, create_events_multi, free_buffers_multi, NULL), + BENCH_INFO(event_is_valid, create_events, free_buffers, NULL), + BENCH_INFO(event_free, create_events, NULL, NULL), + BENCH_INFO(event_free_multi, create_events_multi, NULL, NULL), + BENCH_INFO(event_free_sp, create_events_multi, NULL, NULL), + BENCH_INFO_COND(event_flow_id, create_events, free_buffers, NULL, check_flow_aware), + BENCH_INFO_COND(event_flow_id_set, create_events, free_buffers, NULL, check_flow_aware), +}; + +/** + * ODP buffer microbenchmark application + */ +int main(int argc, char *argv[]) +{ + odph_helper_options_t helper_options; + odph_thread_t worker_thread; + odph_thread_common_param_t thr_common; + odph_thread_param_t thr_param; + int cpu; + odp_shm_t shm; + odp_cpumask_t cpumask, default_mask; + odp_schedule_capability_t sched_capa; + odp_pool_capability_t capa; + odp_pool_param_t params; + odp_instance_t instance; + odp_init_t init_param; + uint32_t buf_num; + uint8_t ret; + + /* Let helper collect its own arguments (e.g. --odph_proc) */ + argc = odph_parse_options(argc, argv); + if (odph_options(&helper_options)) { + ODPH_ERR("Error: reading ODP helper options failed\n"); + exit(EXIT_FAILURE); + } + + odp_init_param_init(&init_param); + init_param.mem_model = helper_options.mem_model; + + /* Init ODP before calling anything else */ + if (odp_init_global(&instance, &init_param, NULL)) { + ODPH_ERR("Error: ODP global init failed\n"); + exit(EXIT_FAILURE); + } + + /* Init this thread */ + if (odp_init_local(instance, ODP_THREAD_CONTROL)) { + ODPH_ERR("Error: ODP local init failed\n"); + exit(EXIT_FAILURE); + } + + /* Reserve memory for args from shared mem */ + shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE, 0); + if (shm == ODP_SHM_INVALID) { + ODPH_ERR("Error: shared mem reserve failed\n"); + exit(EXIT_FAILURE); + } + + gbl_args = odp_shm_addr(shm); + if (gbl_args == NULL) { + ODPH_ERR("Error: shared mem alloc failed\n"); + exit(EXIT_FAILURE); + } + + memset(gbl_args, 0, sizeof(args_t)); + odp_atomic_init_u32(&gbl_args->exit_thread, 0); + + gbl_args->bench = test_suite; + gbl_args->num_bench = sizeof(test_suite) / sizeof(test_suite[0]); + + /* Parse and store the application arguments */ + parse_args(argc, argv, &gbl_args->appl); + + /* Get default worker cpumask */ + if (odp_cpumask_default_worker(&default_mask, 1) != 1) { + ODPH_ERR("Error: unable to allocate worker thread\n"); + exit(EXIT_FAILURE); + } + (void)odp_cpumask_to_str(&default_mask, gbl_args->cpumask_str, + sizeof(gbl_args->cpumask_str)); + + if (odp_schedule_capability(&sched_capa)) { + ODPH_ERR("Error: schedule capability failed\n"); + exit(EXIT_FAILURE); + } + + gbl_args->max_flow_id = 0; + if (sched_capa.max_flow_id) { + odp_schedule_config_t sched_config; + + odp_schedule_config_init(&sched_config); + sched_config.max_flow_id = 1; + + if (odp_schedule_config(&sched_config)) { + ODPH_ERR("Error: schedule config failed\n"); + exit(EXIT_FAILURE); + } + gbl_args->max_flow_id = 1; + } + + if (odp_pool_capability(&capa)) { + ODPH_ERR("Error: unable to query pool capability\n"); + exit(EXIT_FAILURE); + } + + buf_num = gbl_args->appl.burst_size * TEST_REPEAT_COUNT; + + if (capa.buf.max_num && capa.buf.max_num < buf_num) { + ODPH_ERR("Error: pool size not supported (max %" PRIu32 ")\n", capa.buf.max_num); + exit(EXIT_FAILURE); + } else if (gbl_args->appl.cache_size > (int)capa.buf.max_cache_size) { + ODPH_ERR("Error: cache size not supported (max %" PRIu32 ")\n", + capa.buf.max_cache_size); + exit(EXIT_FAILURE); + } + + gbl_args->buf_size = TEST_BUF_SIZE; + if (capa.buf.max_size && capa.buf.max_size < TEST_BUF_SIZE) + gbl_args->buf_size = capa.buf.max_size; + + gbl_args->uarea_size = TEST_UAREA_SIZE < capa.buf.max_uarea_size ? + TEST_UAREA_SIZE : capa.buf.max_uarea_size; + + print_info(); + + /* Create buffer pool */ + odp_pool_param_init(¶ms); + params.buf.size = gbl_args->buf_size; + params.buf.num = buf_num; + params.buf.uarea_size = gbl_args->uarea_size; + if (gbl_args->appl.cache_size >= 0) + params.buf.cache_size = gbl_args->appl.cache_size; + params.type = ODP_POOL_BUFFER; + + gbl_args->pool = odp_pool_create("microbench", ¶ms); + if (gbl_args->pool == ODP_POOL_INVALID) { + ODPH_ERR("Error: pool create failed\n"); + exit(EXIT_FAILURE); + } + + odp_pool_print(gbl_args->pool); + + memset(&worker_thread, 0, sizeof(odph_thread_t)); + + signal(SIGINT, sig_handler); + + /* Create worker thread */ + cpu = odp_cpumask_first(&default_mask); + + odp_cpumask_zero(&cpumask); + odp_cpumask_set(&cpumask, cpu); + + odph_thread_common_param_init(&thr_common); + thr_common.instance = instance; + thr_common.cpumask = &cpumask; + thr_common.share_param = 1; + + odph_thread_param_init(&thr_param); + thr_param.start = run_benchmarks; + thr_param.arg = gbl_args; + thr_param.thr_type = ODP_THREAD_WORKER; + + odph_thread_create(&worker_thread, &thr_common, &thr_param, 1); + + odph_thread_join(&worker_thread, 1); + + ret = gbl_args->bench_failed; + + if (odp_pool_destroy(gbl_args->pool)) { + ODPH_ERR("Error: pool destroy\n"); + exit(EXIT_FAILURE); + } + + if (odp_shm_free(shm)) { + ODPH_ERR("Error: shm free\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_local()) { + ODPH_ERR("Error: term local\n"); + exit(EXIT_FAILURE); + } + + if (odp_term_global(instance)) { + ODPH_ERR("Error: term global\n"); + exit(EXIT_FAILURE); + } + + return ret; +} |