20 #include <odp/helper/odph_api.h>
22 #define PSEUDO_RANDOM (-1)
24 #define MB (1024ull * 1024ull)
26 typedef struct test_global_t test_global_t;
28 typedef struct thread_arg_t {
29 test_global_t *global;
35 struct test_global_t {
62 static options_t options;
63 static const options_t options_def = {
72 static void print_usage(
void)
75 "random data performance test\n"
77 "Usage: odp_random [options]\n"
79 " -m, --mode Test mode select (default: 0):\n"
80 " 0: Data throughput\n"
81 " 1: Data generation latency (size: 8B by default)\n"
82 " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default 1.\n"
83 " -s, --size Size of buffer in bytes. Default %u.\n"
84 " -r, --rounds Number of test rounds. Default %u.\n"
85 " Divided by 100 for ODP_RANDOM_TRUE.\n"
86 " -t, --time Target test duration (msec). 0: use rounds from -r option. Default %u.\n"
87 " Based on a measurement on one thread. Test duration may be\n"
88 " significantly longer with multiple threads.\n"
89 " -d, --delay Delay (nsec) between buffer fills. Default %" PRIu64
".\n"
90 " Affects only latency mode.\n"
91 " -h, --help This help.\n"
93 options_def.size, options_def.rounds, options_def.msec, options_def.delay);
96 static int parse_options(
int argc,
char *argv[])
101 static const struct option longopts[] = {
102 {
"mode", required_argument, NULL,
'm' },
103 {
"num_cpu", required_argument, NULL,
'c' },
104 {
"size", required_argument, NULL,
's' },
105 {
"rounds", required_argument, NULL,
'r' },
106 {
"time", required_argument, NULL,
't' },
107 {
"delay", required_argument, NULL,
'd' },
108 {
"help", no_argument, NULL,
'h' },
112 static const char *shortopts =
"+m:c:s:r:t:d:h";
114 options = options_def;
118 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
125 options.mode = atoi(optarg);
128 options.num_threads = atol(optarg);
131 options.size = atol(optarg);
134 options.rounds = atol(optarg);
137 options.msec = atol(optarg);
140 options.delay = atol(optarg);
152 ODPH_ERR(
"Bad number of threads: %i\n", options.num_threads);
156 if (options.size == 0) {
157 options.size = options_def.size;
163 printf(
"\nOptions:\n");
164 printf(
"------------------------\n");
165 printf(
" mode: %i\n", options.mode);
166 printf(
" num_cpu: %i\n", options.num_threads);
167 printf(
" size: %u\n", options.size);
168 printf(
" rounds: %u\n", options.rounds);
169 printf(
" time: %u\n", options.msec);
170 printf(
" delay: %" PRIu64
"\n", options.delay);
177 uint8_t *data, uint32_t size)
182 if ((
int)type == PSEUDO_RANDOM) {
185 for (i = 0; i < rounds; i++) {
192 ODPH_ERR(
"odp_random_test_data() failed\n");
200 for (i = 0; i < rounds; i++) {
207 ODPH_ERR(
"odp_random_data() failed\n");
217 static int test_random_perf(
void *ptr)
221 thread_arg_t *thread_arg = ptr;
222 test_global_t *global = thread_arg->global;
224 int thread_idx = thread_arg->thread_idx;
225 uint8_t *data = thread_arg->data;
226 uint32_t size = options.size;
227 uint32_t rounds = global->rounds;
230 random_data_loop(type, 1, data, size);
237 random_data_loop(type, rounds, data, size);
241 global->stat.nsec[thread_idx] = nsec;
246 static inline void random_data_latency(test_global_t *global,
int thread_idx,
247 uint32_t rounds, uint8_t *data, uint32_t size)
254 uint64_t delay = options.delay;
255 uint64_t min = UINT64_MAX;
262 for (i = 0; i < rounds; i++) {
268 if ((
int)type == PSEUDO_RANDOM) {
274 ODPH_ERR(
"odp_random_test_data() failed\n");
287 ODPH_ERR(
"odp_random_data() failed\n");
307 global->stat.nsec[thread_idx] = nsec;
308 global->stat.sum[thread_idx] = sum;
309 global->stat.min[thread_idx] = min;
310 global->stat.max[thread_idx] = max;
313 static int test_random_latency(
void *ptr)
315 thread_arg_t *thread_arg = ptr;
316 test_global_t *global = thread_arg->global;
318 int thread_idx = thread_arg->thread_idx;
319 uint8_t *data = thread_arg->data;
320 uint32_t size = options.size;
321 uint32_t rounds = global->rounds;
324 random_data_loop(type, 1, data, size);
329 random_data_latency(global, thread_idx, rounds, data, size);
336 uint32_t rounds = options.rounds;
351 uint8_t *buf = (uint8_t *)malloc(options.size);
354 ODPH_ERR(
"malloc() failed\n");
359 random_data_loop(type, 1, buf, options.size);
361 uint32_t r = 1, tr = 0;
368 random_data_latency(global, 0, r, buf, options.size);
370 random_data_loop(type, r, buf, options.size);
383 return ODPH_MAX(1u, rounds);
390 int num_threads = options.num_threads;
391 uint32_t size = options.size;
394 rounds = type_rounds(global, type);
396 memset(&global->stat, 0,
sizeof(global->stat));
397 global->rounds = rounds;
401 odph_thread_common_param_t thr_common;
402 odph_thread_param_t thr_param[num_threads];
403 odph_thread_t thr_worker[num_threads];
406 ODPH_ERR(
"Failed to get default CPU mask.\n");
410 odph_thread_common_param_init(&thr_common);
411 thr_common.instance = instance;
412 thr_common.cpumask = &cpumask;
414 for (i = 0; i < num_threads; i++) {
415 odph_thread_param_init(&thr_param[i]);
417 thr_param[i].arg = &global->thread_arg[i];
419 if (options.mode == 0)
420 thr_param[i].start = test_random_perf;
422 thr_param[i].start = test_random_latency;
425 memset(&thr_worker, 0,
sizeof(thr_worker));
427 if (odph_thread_create(thr_worker, &thr_common, thr_param, num_threads) != num_threads) {
428 ODPH_ERR(
"Failed to create worker threads.\n");
432 odph_thread_join_result_t res[num_threads];
434 if (odph_thread_join_result(thr_worker, res, num_threads) != num_threads) {
435 ODPH_ERR(
"Failed to join worker threads.\n");
439 for (i = 0; i < num_threads; i++) {
440 if (res[i].is_sig || res[i].ret != 0) {
441 ODPH_ERR(
"Worker thread failure%s: %d\n", res[i].is_sig ?
442 " (signaled)" :
"", res[i].ret);
447 double mb, seconds, nsec = 0;
449 for (i = 0; i < num_threads; i++)
450 nsec += global->stat.nsec[i];
456 printf(
"ODP_RANDOM_BASIC\n");
459 printf(
"ODP_RANDOM_CRYPTO\n");
462 printf(
"ODP_RANDOM_TRUE\n");
465 printf(
"odp_random_test_data\n");
468 printf(
"--------------------\n");
469 printf(
"threads: %d size: %u B rounds: %u ", num_threads, size, rounds);
470 mb = (uint64_t)num_threads * (uint64_t)size * (uint64_t)rounds;
473 printf(
"MB: %.3f seconds: %.3f ", mb, seconds);
474 printf(
"MB/s: %.3f ", mb / seconds);
475 printf(
"MB/s/thread: %.3f\n", mb / seconds / (
double)num_threads);
479 uint64_t min = UINT64_MAX;
483 printf(
" latency (nsec)\n");
484 printf(
" thread min max ave\n");
485 for (i = 0; i < num_threads; i++) {
486 ave = (double)global->stat.sum[i] / rounds;
487 sum += global->stat.sum[i];
489 if (global->stat.min[i] < min)
490 min = global->stat.min[i];
492 if (global->stat.max[i] > max)
493 max = global->stat.max[i];
495 printf(
"%8i %8" PRIu64
" %8" PRIu64
" %10.1f\n", i, global->stat.min[i],
496 global->stat.max[i], ave);
499 printf(
" all %8" PRIu64
" %8" PRIu64
" %10.1f\n",
500 min, max, ((
double)sum / rounds) / num_threads);
506 int main(
int argc,
char **argv)
508 odph_helper_options_t helper_options;
512 test_global_t *global;
514 uint64_t tot_size, size;
518 argc = odph_parse_options(argc, argv);
520 if (odph_options(&helper_options)) {
521 ODPH_ERR(
"Failed to read ODP helper options.\n");
525 if (parse_options(argc, argv))
538 init.
mem_model = helper_options.mem_model;
542 ODPH_ERR(
"Global init failed.\n");
548 ODPH_ERR(
"Local init failed.\n");
555 shm_glb =
odp_shm_reserve(
"test_globals",
sizeof(test_global_t), ODP_CACHE_LINE_SIZE, 0);
561 ODPH_ERR(
"Failed to reserve shm\n");
565 memset(global, 0,
sizeof(test_global_t));
567 num_threads = options.num_threads;
570 tot_size = num_threads * size;
571 shm_data =
odp_shm_reserve(
"test_data", tot_size, ODP_CACHE_LINE_SIZE, 0);
577 ODPH_ERR(
"Failed to reserve shm: size %" PRIu64
" bytes\n", tot_size);
581 for (i = 0; i < num_threads; i++) {
582 global->thread_arg[i].global = global;
583 global->thread_arg[i].thread_idx = i;
584 global->thread_arg[i].data = addr + i * size;
596 test_type(instance, global, PSEUDO_RANDOM);
600 ODPH_ERR(
"odp_shm_free() failed\n");
605 ODPH_ERR(
"odp_shm_free() failed\n");
610 ODPH_ERR(
"Local terminate failed.\n");
615 ODPH_ERR(
"Global terminate failed.\n");
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define ODP_CACHE_LINE_ROUNDUP(x)
Round up to cache line size.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
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_random_kind_t odp_random_max_kind(void)
Query random max kind.
int32_t odp_random_data(uint8_t *buf, uint32_t len, odp_random_kind_t kind)
Generate random byte data.
odp_random_kind_t
Random kind selector.
int32_t odp_random_test_data(uint8_t *buf, uint32_t len, uint64_t *seed)
Generate repeatable random data for testing purposes.
@ ODP_RANDOM_BASIC
Basic random, presumably pseudo-random generated by SW.
@ ODP_RANDOM_TRUE
True random, generated from a HW entropy source.
@ ODP_RANDOM_CRYPTO
Cryptographic quality random.
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.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
#define ODP_TIME_SEC_IN_NS
A second in nanoseconds.
void odp_time_wait_ns(uint64_t ns)
Wait the specified number of nanoseconds.
odp_time_t odp_time_local(void)
Current local time.
odp_time_t odp_time_add_ns(odp_time_t time, uint64_t ns)
Add nanoseconds into time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
odp_time_t odp_time_local_strict(void)
Current local time (strict)
int odp_time_cmp(odp_time_t t2, odp_time_t t1)
Compare two times.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_xxx()
uint32_t stash
Stash APIs, e.g., odp_stash_xxx()
uint32_t crypto
Crypto APIs, e.g., odp_crypto_xxx()
uint32_t ipsec
IPsec APIs, e.g., odp_ipsec_xxx()
uint32_t timer
Timer APIs, e.g., odp_timer_xxx(), odp_timeout_xxx()
uint32_t cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
uint32_t schedule
Scheduler APIs, e.g., odp_schedule_xxx()
struct odp_feature_t::@148 feat
Individual feature bits.
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()