#include <odp/helper/odph_api.h>
#include <bench_common.h>
#include <export_results.h>
#include <getopt.h>
#include <inttypes.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define TEST_BUF_SIZE 1024
#define TEST_UAREA_SIZE 8
#define TEST_REPEAT_COUNT 1000
#define TEST_ROUNDS 100u
#define TEST_MAX_BURST 64
#define TEST_DEF_BURST 8
#define TEST_MAX_BENCH 40
#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
strrchr((file_name), '/') + 1 : (file_name))
#define BENCH_INFO(run_fn, init_fn, term_fn, alt_name) \
{.name = #run_fn, .run = run_fn, .init = init_fn, .term = term_fn, .desc = alt_name}
#define BENCH_INFO_COND(run_fn, init_fn, term_fn, alt_name, cond_fn) \
{.name = #run_fn, .run = run_fn, .init = init_fn, .term = term_fn, .desc = alt_name, \
.cond = cond_fn}
#define BENCH_INFO_TM(run_fn, init_fn, term_fn, cond_fn) \
{.name = #run_fn, .run = run_fn, .init = init_fn, .term = term_fn, .cond = cond_fn,\
.max_rounds = 0}
typedef enum {
M_TPUT,
M_LATENCY
} meas_mode_t;
typedef struct {
int bench_idx;
int burst_size;
int cache_size;
int time;
meas_mode_t mode;
uint32_t rounds;
} appl_args_t;
typedef struct {
appl_args_t appl;
struct {
union {
bench_suite_t b;
bench_tm_suite_t t;
};
int *retval;
void *args;
int (*suite_fn)(void *args);
int (*export_fn)(void *data);
} suite;
uint32_t buf_size;
uint32_t uarea_size;
uint32_t max_flow_id;
odp_event_t event_tbl[TEST_REPEAT_COUNT * TEST_MAX_BURST];
void *ptr_tbl[TEST_REPEAT_COUNT];
union{
double b[TEST_MAX_BENCH];
bench_tm_result_t t[TEST_MAX_BENCH];
} result;
} args_t;
static args_t *gbl_args;
{
if (gbl_args == NULL)
return;
}
static void allocate_test_buffers(
odp_buffer_t buf[],
int num)
{
int num_buf = 0;
while (num_buf < num) {
int ret;
if (ret < 0)
ODPH_ABORT("Allocating test buffers failed\n");
num_buf += ret;
}
}
static void create_buffers(void)
{
allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
}
static void create_buffers_multi(void)
{
allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT * gbl_args->appl.burst_size);
}
static void create_events(void)
{
allocate_test_buffers(gbl_args->buf_tbl, TEST_REPEAT_COUNT);
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
}
static void create_events_multi(void)
{
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++)
}
static void free_buffers(void)
{
}
static void free_buffers_multi(void)
{
}
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)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_from_event_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_from_event()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_from_event_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
&event_tbl[i * burst_size], burst_size);
return i;
}
static int buffer_from_event_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_from_event_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
&event_tbl[i * burst_size], burst_size);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_to_event(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_to_event_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_to_event()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_to_event_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
&event_tbl[i * burst_size], burst_size);
return i;
}
static int buffer_to_event_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_to_event_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
&event_tbl[i * burst_size], burst_size);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_addr(void)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_addr_tm(bench_tm_result_t *res, int repeat_count)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_addr()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_size(void)
{
uint32_t ret = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
return ret;
}
static int buffer_size_tm(bench_tm_result_t *res, int repeat_count)
{
uint32_t ret = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_size()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return ret;
}
static int buffer_user_area(void)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_user_area_tm(bench_tm_result_t *res, int repeat_count)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_user_area()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_pool(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_pool_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_pool()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_alloc(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_alloc_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_alloc()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_alloc_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int num = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
return num;
}
static int buffer_alloc_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int num = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_alloc_multi()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return num;
}
static int buffer_free(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_free_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_free()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_free_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int buffer_free_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_free_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_alloc_free(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++) {
return 0;
}
return i;
}
static int buffer_alloc_free_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_alloc()/_free()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_alloc_free_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++) {
return 0;
}
return i;
}
static int buffer_alloc_free_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_alloc_multi()/_free_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
ODPH_ASSERT(num >= 1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int buffer_is_valid(void)
{
uint32_t ret = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
return ret;
}
static int buffer_is_valid_tm(bench_tm_result_t *res, int repeat_count)
{
uint32_t ret = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_buffer_is_valid()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return ret;
}
static int event_type(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_type_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_type()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_subtype(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_subtype_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_subtype()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_types(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_types_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_types()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_types_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
&event_type_tbl[i * burst_size],
&event_subtype_tbl[i * burst_size], burst_size);
return i;
}
static int event_types_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_types_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
&event_type_tbl[i * burst_size],
&event_subtype_tbl[i * burst_size], burst_size);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_types_multi_no_sub(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
&event_type_tbl[i * burst_size], NULL, burst_size);
return i;
}
static int event_types_multi_no_sub_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_types_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
&event_type_tbl[i * burst_size], NULL, burst_size);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_type_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
uint32_t ret = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
&event_type_tbl[i]);
return ret;
}
static int event_type_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
uint32_t ret = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_type_multi()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
&event_type_tbl[i]);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return ret;
}
static int event_pool(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_pool_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_pool()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_user_area(void)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_user_area_tm(bench_tm_result_t *res, int repeat_count)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_user_area()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_user_area_and_flag(void)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int ret = 0;
int flag;
for (int i = 0; i < TEST_REPEAT_COUNT; i++) {
ret += flag;
}
return ret;
}
static int event_user_area_and_flag_tm(bench_tm_result_t *res, int repeat_count)
{
void **ptr_tbl = gbl_args->ptr_tbl;
int ret = 0;
int flag;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_user_area_and_flag()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
ret += flag;
}
return ret;
}
static int event_is_valid(void)
{
uint32_t ret = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
return ret;
}
static int event_is_valid_tm(bench_tm_result_t *res, int repeat_count)
{
uint32_t ret = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_is_valid()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return ret;
}
static int event_free(void)
{
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_free_tm(bench_tm_result_t *res, int repeat_count)
{
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_free()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_free_multi(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_free_multi_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_free_multi()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_free_sp(void)
{
int burst_size = gbl_args->appl.burst_size;
int i;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_free_sp_tm(bench_tm_result_t *res, int repeat_count)
{
int burst_size = gbl_args->appl.burst_size;
int i;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_free_sp()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
static int event_flow_id(void)
{
uint32_t ret = 0;
for (int i = 0; i < TEST_REPEAT_COUNT; i++)
return !ret;
}
static int event_flow_id_tm(bench_tm_result_t *res, int repeat_count)
{
uint32_t ret = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_flow_id()");
bench_tm_stamp_t s1, s2;
for (int i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return !ret;
}
static int event_flow_id_set(void)
{
int i = 0;
for (i = 0; i < TEST_REPEAT_COUNT; i++)
return i;
}
static int event_flow_id_set_tm(bench_tm_result_t *res, int repeat_count)
{
int i = 0;
const uint8_t id1 = bench_tm_func_register(res, "odp_event_flow_id_set()");
bench_tm_stamp_t s1, s2;
for (i = 0; i < repeat_count; i++) {
bench_tm_now(res, &s1);
bench_tm_now(res, &s2);
bench_tm_func_record(&s2, &s1, res, id1);
}
return i;
}
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"
" -r, --rounds <num> Run each test case 'num' times (default %u).\n"
" -t, --time <opt> Time measurement. 0: measure CPU cycles (default), 1: measure time\n"
" -m, --mode <mode> Measurement mode. 0: measure throughput, track average execution\n"
" time (default), 1: measure latency, track function minimum and\n"
" maximum in addition to average execution time.\n"
" -h, --help Display help and exit.\n\n"
"\n", NO_PATH(progname), NO_PATH(progname), TEST_ROUNDS);
}
static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
{
int opt;
static const struct option longopts[] = {
{"burst", required_argument, NULL, 'b'},
{"cache_size", required_argument, NULL, 'c'},
{"index", required_argument, NULL, 'i'},
{"rounds", required_argument, NULL, 'r'},
{"time", required_argument, NULL, 't'},
{"mode", required_argument, NULL, 'm'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
static const char *shortopts = "c:b:i:r:t:m:h";
appl_args->bench_idx = 0;
appl_args->burst_size = TEST_DEF_BURST;
appl_args->cache_size = -1;
appl_args->rounds = TEST_ROUNDS;
appl_args->time = 0;
appl_args->mode = M_TPUT;
while (1) {
opt = getopt_long(argc, argv, shortopts, longopts, NULL);
if (opt == -1)
break;
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 'r':
appl_args->rounds = atoi(optarg);
break;
case 't':
appl_args->time = atoi(optarg);
break;
case 'm':
appl_args->mode = 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->rounds < 1) {
printf("Invalid number test rounds: %d\n", appl_args->rounds);
exit(EXIT_FAILURE);
}
if (appl_args->mode != M_TPUT && appl_args->mode != M_LATENCY) {
printf("Invalid measurement mode: %d\n", appl_args->mode);
exit(EXIT_FAILURE);
}
optind = 1;
}
static void print_info(void)
{
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("Measurement unit: %s\n", gbl_args->appl.time ? "nsec" : "CPU cycles");
printf("Test rounds: %u\n", gbl_args->appl.rounds);
printf("Measurement mode: %s\n", gbl_args->appl.mode == M_TPUT ? "throughput" : "latency");
printf("\n");
}
static int bench_buffer_tm_export(void *data)
{
args_t *gbl_args = data;
bench_tm_result_t *res;
uint64_t num;
int ret = 0;
const char *unit = gbl_args->appl.time ? "nsec" : "cpu cycles";
if (test_common_write("function name,min %s per function call,"
"average %s per function call,"
"max %s per function call\n", unit, unit, unit)) {
ret = -1;
goto exit;
}
for (uint32_t i = 0; i < gbl_args->suite.t.num_bench; i++) {
res = &gbl_args->suite.t.result[i];
for (int j = 0; j < res->num; j++) {
num = res->func[j].num ? res->func[j].num : 1;
if (test_common_write("%s,%" PRIu64 ",%" PRIu64 ",%" PRIu64 "\n",
res->func[j].name,
bench_tm_to_u64(res, &res->func[j].min),
bench_tm_to_u64(res, &res->func[j].tot) / num,
bench_tm_to_u64(res, &res->func[j].max))) {
ret = -1;
goto exit;
}
}
}
exit:
test_common_write_term();
return ret;
}
static int bench_buffer_export(void *data)
{
args_t *gbl_args = data;
int ret = 0;
if (test_common_write("%s", gbl_args->appl.time ?
"function name,average nsec per function call\n" :
"function name,average cpu cycles per function call\n")) {
ret = -1;
goto exit;
}
for (int i = 0; i < gbl_args->suite.b.num_bench; i++) {
if (test_common_write("odp_%s,%f\n", gbl_args->suite.b.bench[i].desc != NULL ?
gbl_args->suite.b.bench[i].desc :
gbl_args->suite.b.bench[i].name,
gbl_args->suite.b.result[i])) {
ret = -1;
goto exit;
}
}
exit:
test_common_write_term();
return ret;
}
bench_info_t test_suite[] = {
BENCH_INFO(buffer_from_event, create_events, free_buffers, NULL),
BENCH_INFO(buffer_from_event_multi, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO(buffer_to_event, create_buffers, free_buffers, NULL),
BENCH_INFO(buffer_to_event_multi, create_buffers_multi, free_buffers_multi, 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, create_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_events, free_buffers, NULL),
BENCH_INFO(event_types, create_events, free_buffers, NULL),
BENCH_INFO(event_types_multi, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO(event_types_multi_no_sub, create_events_multi, free_buffers_multi,
"event_types_multi (no sub)"),
BENCH_INFO(event_type_multi, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO(event_pool, create_events, free_buffers, NULL),
BENCH_INFO_COND(event_user_area, create_events, free_buffers, NULL, check_uarea),
BENCH_INFO_COND(event_user_area_and_flag, create_events, free_buffers, NULL, check_uarea),
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),
};
"Result array is too small to hold all the results");
bench_tm_info_t test_suite_tm[] = {
BENCH_INFO_TM(buffer_from_event_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(buffer_from_event_multi_tm, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO_TM(buffer_to_event_tm, create_buffers, free_buffers, NULL),
BENCH_INFO_TM(buffer_to_event_multi_tm, create_buffers_multi, free_buffers_multi, NULL),
BENCH_INFO_TM(buffer_addr_tm, create_buffers, free_buffers, NULL),
BENCH_INFO_TM(buffer_size_tm, create_buffers, free_buffers, NULL),
BENCH_INFO_TM(buffer_user_area_tm, create_buffers, free_buffers, check_uarea),
BENCH_INFO_TM(buffer_pool_tm, create_buffers, free_buffers, NULL),
BENCH_INFO_TM(buffer_alloc_tm, NULL, free_buffers, NULL),
BENCH_INFO_TM(buffer_alloc_multi_tm, NULL, free_buffers_multi, NULL),
BENCH_INFO_TM(buffer_free_tm, create_buffers, NULL, NULL),
BENCH_INFO_TM(buffer_free_multi_tm, create_buffers_multi, NULL, NULL),
BENCH_INFO_TM(buffer_alloc_free_tm, NULL, NULL, NULL),
BENCH_INFO_TM(buffer_alloc_free_multi_tm, NULL, NULL, NULL),
BENCH_INFO_TM(buffer_is_valid_tm, create_buffers, free_buffers, NULL),
BENCH_INFO_TM(event_type_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(event_subtype_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(event_types_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(event_types_multi_tm, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO_TM(event_types_multi_no_sub_tm, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO_TM(event_type_multi_tm, create_events_multi, free_buffers_multi, NULL),
BENCH_INFO_TM(event_pool_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(event_user_area_tm, create_events, free_buffers, check_uarea),
BENCH_INFO_TM(event_user_area_and_flag_tm, create_events, free_buffers, check_uarea),
BENCH_INFO_TM(event_is_valid_tm, create_events, free_buffers, NULL),
BENCH_INFO_TM(event_free_tm, create_events, NULL, NULL),
BENCH_INFO_TM(event_free_multi_tm, create_events_multi, NULL, NULL),
BENCH_INFO_TM(event_free_sp_tm, create_events_multi, NULL, NULL),
BENCH_INFO_TM(event_flow_id_tm, create_events, free_buffers, check_flow_aware),
BENCH_INFO_TM(event_flow_id_set_tm, create_events, free_buffers, check_flow_aware),
};
"Result array is too small to hold all the results");
static void init_suite(args_t *gbl_args,
odp_bool_t is_export)
{
if (gbl_args->appl.mode == M_LATENCY) {
bench_tm_suite_init(&gbl_args->suite.t);
gbl_args->suite.t.bench = test_suite_tm;
gbl_args->suite.t.num_bench = ODPH_ARRAY_SIZE(test_suite_tm);
gbl_args->suite.t.rounds = TEST_REPEAT_COUNT;
gbl_args->suite.t.bench_idx = gbl_args->appl.bench_idx;
gbl_args->suite.t.measure_time = !!gbl_args->appl.time;
gbl_args->suite.exit = &gbl_args->suite.t.exit_worker;
gbl_args->suite.retval = &gbl_args->suite.t.retval;
gbl_args->suite.args = &gbl_args->suite.t;
gbl_args->suite.suite_fn = bench_tm_run;
gbl_args->suite.export_fn = bench_buffer_tm_export;
if (is_export)
gbl_args->suite.t.result = gbl_args->result.t;
} else {
bench_suite_init(&gbl_args->suite.b);
gbl_args->suite.b.bench = test_suite;
gbl_args->suite.b.num_bench = ODPH_ARRAY_SIZE(test_suite);
gbl_args->suite.b.indef_idx = gbl_args->appl.bench_idx;
gbl_args->suite.b.rounds = gbl_args->appl.rounds;
gbl_args->suite.b.repeat_count = TEST_REPEAT_COUNT;
gbl_args->suite.b.measure_time = !!gbl_args->appl.time;
gbl_args->suite.exit = &gbl_args->suite.b.exit_worker;
gbl_args->suite.retval = &gbl_args->suite.b.retval;
gbl_args->suite.args = &gbl_args->suite.b;
gbl_args->suite.suite_fn = bench_run;
gbl_args->suite.export_fn = bench_buffer_export;
if (is_export)
gbl_args->suite.b.result = gbl_args->result.b;
}
}
int main(int argc, char *argv[])
{
odph_helper_options_t helper_options;
test_common_options_t common_options;
odph_thread_t worker_thread;
odph_thread_common_param_t thr_common;
odph_thread_param_t thr_param;
int cpu;
uint32_t buf_num;
uint8_t ret;
argc = odph_parse_options(argc, argv);
if (odph_options(&helper_options)) {
ODPH_ERR("Error: reading ODP helper options failed\n");
exit(EXIT_FAILURE);
}
argc = test_common_parse_options(argc, argv);
if (test_common_options(&common_options)) {
ODPH_ERR("Error: reading test options failed\n");
exit(EXIT_FAILURE);
}
init_param.
mem_model = helper_options.mem_model;
ODPH_ERR("Error: ODP global init failed\n");
exit(EXIT_FAILURE);
}
ODPH_ERR("Error: ODP local init failed\n");
exit(EXIT_FAILURE);
}
ODPH_ERR("Error: shared mem reserve failed\n");
exit(EXIT_FAILURE);
}
if (gbl_args == NULL) {
ODPH_ERR("Error: shared mem alloc failed\n");
exit(EXIT_FAILURE);
}
memset(gbl_args, 0, sizeof(args_t));
parse_args(argc, argv, &gbl_args->appl);
init_suite(gbl_args, common_options.is_export);
ODPH_ERR("Error: unable to allocate worker thread\n");
exit(EXIT_FAILURE);
}
sizeof(gbl_args->cpumask_str));
ODPH_ERR("Error: schedule capability failed\n");
exit(EXIT_FAILURE);
}
gbl_args->max_flow_id = 0;
ODPH_ERR("Error: schedule config failed\n");
exit(EXIT_FAILURE);
}
gbl_args->max_flow_id = 1;
}
ODPH_ERR("Error: unable to query pool capability\n");
exit(EXIT_FAILURE);
}
buf_num = gbl_args->appl.burst_size * TEST_REPEAT_COUNT;
ODPH_ERR(
"Error: pool size not supported (max %" PRIu32
")\n", capa.
buf.
max_num);
exit(EXIT_FAILURE);
ODPH_ERR("Error: cache size not supported (max %" PRIu32 ")\n",
exit(EXIT_FAILURE);
}
gbl_args->buf_size = TEST_BUF_SIZE;
print_info();
params.
buf.
size = gbl_args->buf_size;
if (gbl_args->appl.cache_size >= 0)
ODPH_ERR("Error: pool create failed\n");
exit(EXIT_FAILURE);
}
memset(&worker_thread, 0, sizeof(odph_thread_t));
signal(SIGINT, sig_handler);
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 = gbl_args->suite.suite_fn;
thr_param.arg = gbl_args->suite.args;
odph_thread_create(&worker_thread, &thr_common, &thr_param, 1);
odph_thread_join(&worker_thread, 1);
ret = *gbl_args->suite.retval;
if (ret == 0 && common_options.is_export) {
if (gbl_args->suite.export_fn(gbl_args)) {
ODPH_ERR("Error: Export failed\n");
ret = -1;
}
}
ODPH_ERR("Error: pool destroy\n");
exit(EXIT_FAILURE);
}
ODPH_ERR("Error: shm free\n");
exit(EXIT_FAILURE);
}
ODPH_ERR("Error: term local\n");
exit(EXIT_FAILURE);
}
ODPH_ERR("Error: term global\n");
exit(EXIT_FAILURE);
}
return ret;
}
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void * odp_buffer_user_area(odp_buffer_t buf)
Buffer user area.
uint32_t odp_buffer_size(odp_buffer_t buf)
Buffer maximum data size.
odp_event_t odp_buffer_to_event(odp_buffer_t buf)
Convert buffer handle to event.
odp_buffer_t odp_buffer_alloc(odp_pool_t pool)
Buffer alloc.
void odp_buffer_free(odp_buffer_t buf)
Buffer free.
int odp_buffer_is_valid(odp_buffer_t buf)
Check that buffer is valid.
void * odp_buffer_addr(odp_buffer_t buf)
Buffer start address.
odp_buffer_t odp_buffer_from_event(odp_event_t ev)
Get buffer handle from event.
int odp_buffer_alloc_multi(odp_pool_t pool, odp_buffer_t buf[], int num)
Allocate multiple buffers.
#define ODP_BUFFER_INVALID
Invalid buffer.
void odp_buffer_free_multi(const odp_buffer_t buf[], int num)
Free multiple buffers.
void odp_buffer_from_event_multi(odp_buffer_t buf[], const odp_event_t ev[], int num)
Convert multiple buffer events to buffer handles.
void odp_buffer_to_event_multi(const odp_buffer_t buf[], odp_event_t ev[], int num)
Convert multiple buffer handles to events.
odp_pool_t odp_buffer_pool(odp_buffer_t buf)
Buffer pool of the buffer.
#define odp_unlikely(x)
Branch unlikely taken.
#define ODP_UNUSED
Intentionally unused variables of functions.
void odp_cpumask_set(odp_cpumask_t *mask, int cpu)
Add CPU to mask.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
void odp_cpumask_zero(odp_cpumask_t *mask)
Clear entire CPU mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_free_sp(const odp_event_t event[], int num)
Free multiple events to the same pool.
void odp_event_free_multi(const odp_event_t event[], int num)
Free multiple events.
odp_event_subtype_t odp_event_subtype(odp_event_t event)
Event subtype of an event.
void odp_event_free(odp_event_t event)
Free event.
odp_pool_t odp_event_pool(odp_event_t event)
Event pool.
void odp_event_types_multi(const odp_event_t event[], odp_event_type_t type[], odp_event_subtype_t subtype[], int num)
Event types and subtypes of multiple events.
int odp_event_type_multi(const odp_event_t event[], int num, odp_event_type_t *type)
Event type of multiple events.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
odp_event_subtype_t
Event subtype.
odp_event_type_t
Event type.
void odp_event_flow_id_set(odp_event_t event, uint32_t flow_id)
Set event flow id value.
uint32_t odp_event_flow_id(odp_event_t event)
Event flow id value.
void * odp_event_user_area(odp_event_t event)
Event user area.
odp_event_type_t odp_event_types(odp_event_t event, odp_event_subtype_t *subtype)
Event type and subtype of an event.
void * odp_event_user_area_and_flag(odp_event_t event, int *flag)
Event user area and flag.
int odp_event_is_valid(odp_event_t event)
Check that event is valid.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
void odp_pool_print(odp_pool_t pool)
Print pool info.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_BUFFER
Buffer pool.
void odp_schedule_config_init(odp_schedule_config_t *config)
Initialize schedule configuration options.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
int odp_schedule_capability(odp_schedule_capability_t *capa)
Query scheduler capabilities.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
bool odp_bool_t
Boolean type.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
uint32_t max_num
Maximum number of buffers of any size.
uint32_t max_uarea_size
Maximum user area size in bytes.
uint32_t max_size
Maximum buffer data size in bytes.
struct odp_pool_capability_t::@132 buf
Buffer pool capabilities
uint32_t max_cache_size
Maximum size of thread local cache.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
struct odp_pool_param_t::@137 buf
Parameters for buffer pools.
uint32_t cache_size
Maximum number of buffers cached locally per thread.
uint32_t size
Minimum buffer size in bytes.
odp_pool_type_t type
Pool type.
uint32_t max_flow_id
Maximum flow ID per queue.
uint32_t max_flow_id
Maximum flow ID per queue.