23#include <odp/helper/odph_api.h>
25#include <export_results.h>
27#define MAX_STASHES (32)
29typedef struct test_options_t {
39typedef struct test_stat_t {
48typedef struct test_global_t {
50 test_options_t options;
57 test_common_options_t common_options;
61static void print_usage(
void)
64 "Stash performance test\n"
66 "Usage: odp_stash_perf [options]\n"
68 " -c, --num_cpu <num> Number of worker threads. Default: 1\n"
69 " -n, --num_stash <num> Number of stashes. Default: 1\n"
70 " -b, --burst_size <num> Max number of objects per stash call. Default: 1\n"
71 " -s, --stash_size <num> Stash size. Default: 1000\n"
72 " -r, --num_round <num> Number of rounds. Default: 1000\n"
73 " -m, --strict Strict size stash\n"
74 " -h, --help This help\n"
78static int parse_options(
int argc,
char *argv[], test_options_t *test_options)
83 static const struct option longopts[] = {
84 {
"num_cpu", required_argument, NULL,
'c' },
85 {
"num_stash", required_argument, NULL,
'n' },
86 {
"burst_size", required_argument, NULL,
'b' },
87 {
"stash_size", required_argument, NULL,
's' },
88 {
"num_round", required_argument, NULL,
'r' },
89 {
"strict", no_argument, NULL,
'm' },
90 {
"help", no_argument, NULL,
'h' },
94 static const char *shortopts =
"+c:n:b:s:r:mh";
96 test_options->num_cpu = 1;
97 test_options->num_stash = 1;
98 test_options->max_burst = 1;
99 test_options->stash_size = 1000;
100 test_options->num_round = 1000;
101 test_options->strict = 0;
104 opt = getopt_long(argc, argv, shortopts, longopts, NULL);
111 test_options->num_cpu = atoi(optarg);
114 test_options->num_stash = atoi(optarg);
117 test_options->max_burst = atoi(optarg);
120 test_options->stash_size = atoi(optarg);
123 test_options->num_round = atoi(optarg);
126 test_options->strict = 1;
137 if (test_options->num_stash > MAX_STASHES) {
138 ODPH_ERR(
"Too many stashes %u. Test maximum %u.\n",
139 test_options->num_stash, MAX_STASHES);
146static int create_stashes(test_global_t *global)
150 test_options_t *test_options = &global->options;
152 uint32_t num_stash = test_options->num_stash;
153 uint32_t num_round = test_options->num_round;
159 printf(
"\nTesting %s stashes\n",
160 test_options->strict == 0 ?
"NORMAL" :
"STRICT_SIZE");
161 printf(
" num rounds %u\n", num_round);
162 printf(
" num stashes %u\n", num_stash);
163 printf(
" stash size %u\n", test_options->stash_size);
164 printf(
" max burst size %u\n", test_options->max_burst);
167 ODPH_ERR(
"Get stash capability failed\n");
171 if (test_options->stash_size > stash_capa.
max_num_obj) {
172 ODPH_ERR(
"Max stash size supported %" PRIu64
"\n",
177 if (test_options->num_stash > stash_capa.
max_stashes) {
178 ODPH_ERR(
"Max stash supported %u\n", stash_capa.
max_stashes);
182 for (i = 0; i < num_stash; i++) {
186 stash_param.
num_obj = test_options->stash_size;
187 stash_param.
obj_size =
sizeof(uint32_t);
192 ODPH_ERR(
"Stash create failed\n");
196 num_remain = test_options->stash_size;
199 if (num_stored < 0) {
200 ODPH_ERR(
"Error: Stash put failed\n");
203 num_remain -= num_stored;
204 }
while (num_remain);
210static int destroy_stashes(test_global_t *global)
213 test_options_t *test_options = &global->options;
214 uint32_t num_stash = test_options->num_stash;
218 for (uint32_t i = 0; i < num_stash; i++) {
222 ODPH_ERR(
"Error: Stash get failed %u\n", i);
228 ODPH_ERR(
"Stash destroy failed\n");
236static int run_test(
void *arg)
238 uint64_t c1, c2, cycles, nsec;
245 test_global_t *global = arg;
246 test_options_t *test_options = &global->options;
248 uint64_t num_retry = 0;
250 uint32_t num_stash = test_options->num_stash;
251 uint32_t num_round = test_options->num_round;
255 uint32_t max_burst = test_options->max_burst;
256 uint32_t *tmp = malloc(
sizeof(uint32_t) * max_burst);
259 ODPH_ERR(
"Error: malloc failed\n");
264 stat = &global->stat[thr];
272 for (rounds = 0; rounds < num_round; rounds++) {
273 stash = global->stash[i++];
283 ODPH_ERR(
"Error: Stash get failed\n");
287 num_remain = num_obj;
290 if (num_stored < 0) {
291 ODPH_ERR(
"Error: Stash put failed\n");
296 if (num_stored != num_remain)
299 num_remain -= num_stored;
300 }
while (num_remain);
310 stat->rounds = rounds;
313 stat->cycles = cycles;
314 stat->num_retry = num_retry;
320static int start_workers(test_global_t *global)
322 odph_thread_common_param_t thr_common;
323 odph_thread_param_t thr_param;
326 test_options_t *test_options = &global->options;
327 int num_cpu = test_options->num_cpu;
331 if (num_cpu && ret != num_cpu) {
332 ODPH_ERR(
"Error: Too many workers. Max supported %i\n.", ret);
339 test_options->num_cpu = num_cpu;
342 printf(
" num workers %u\n\n", num_cpu);
346 odph_thread_common_param_init(&thr_common);
347 thr_common.instance = global->instance;
348 thr_common.cpumask = &cpumask;
349 thr_common.share_param = 1;
351 odph_thread_param_init(&thr_param);
352 thr_param.start = run_test;
353 thr_param.arg = global;
356 if (odph_thread_create(global->thread_tbl, &thr_common, &thr_param,
363static int output_results(test_global_t *global)
366 double rounds_ave, ops_ave, nsec_ave, cycles_ave, retry_ave;
367 test_options_t *test_options = &global->options;
368 int num_cpu = test_options->num_cpu;
369 uint64_t rounds_sum = 0;
370 uint64_t ops_sum = 0;
371 uint64_t nsec_sum = 0;
372 uint64_t cycles_sum = 0;
373 uint64_t retry_sum = 0;
377 rounds_sum += global->stat[i].rounds;
378 ops_sum += global->stat[i].ops;
379 nsec_sum += global->stat[i].nsec;
380 cycles_sum += global->stat[i].cycles;
381 retry_sum += global->stat[i].num_retry;
384 if (rounds_sum == 0) {
385 printf(
"No results.\n");
389 rounds_ave = rounds_sum / num_cpu;
390 ops_ave = ops_sum / num_cpu;
391 nsec_ave = nsec_sum / num_cpu;
392 cycles_ave = cycles_sum / num_cpu;
393 retry_ave = retry_sum / num_cpu;
396 printf(
"RESULTS - per thread (Million ops per sec):\n");
397 printf(
"----------------------------------------------\n");
398 printf(
" 1 2 3 4 5 6 7 8 9 10");
401 if (global->stat[i].rounds) {
405 printf(
"%6.1f ", (1000.0 * global->stat[i].ops) /
406 global->stat[i].nsec);
412 printf(
"RESULTS - per thread average (%i threads):\n", num_cpu);
413 printf(
"------------------------------------------\n");
414 printf(
" duration: %.3f msec\n", nsec_ave / 1000000);
415 printf(
" num cycles: %.3f M\n", cycles_ave / 1000000);
416 printf(
" ops per get: %.3f\n", ops_ave / rounds_ave);
417 printf(
" cycles per ops: %.3f\n", cycles_ave / ops_ave);
418 printf(
" retries per sec: %.3f k\n",
419 (1000000.0 * retry_ave) / nsec_ave);
420 printf(
" ops per sec: %.3f M\n\n",
421 (1000.0 * ops_ave) / nsec_ave);
423 printf(
"TOTAL ops per sec: %.3f M\n\n",
424 (1000.0 * ops_sum) / nsec_ave);
426 if (global->common_options.is_export) {
427 if (test_common_write(
"duration (msec),num cycles (M),ops per get,"
428 "cycles per ops,retries per sec (k),ops per sec (M),"
429 "total ops per sec (M)\n")) {
430 ODPH_ERR(
"Export failed\n");
431 test_common_write_term();
435 if (test_common_write(
"%f,%f,%f,%f,%f,%f,%f\n",
436 nsec_ave / 1000000, cycles_ave / 1000000,
437 ops_ave / rounds_ave, cycles_ave / ops_ave,
438 (1000000.0 * retry_ave) / nsec_ave,
439 (1000.0 * ops_ave) / nsec_ave,
440 (1000.0 * ops_sum) / nsec_ave)) {
441 ODPH_ERR(
"Export failed\n");
442 test_common_write_term();
446 test_common_write_term();
452int main(
int argc,
char **argv)
454 odph_helper_options_t helper_options;
458 test_global_t *global;
459 test_common_options_t common_options;
463 argc = odph_parse_options(argc, argv);
464 if (odph_options(&helper_options)) {
465 ODPH_ERR(
"Error: Reading ODP helper options failed.\n");
469 argc = test_common_parse_options(argc, argv);
470 if (test_common_options(&common_options)) {
471 ODPH_ERR(
"Error: Reading test options failed\n");
485 init.
mem_model = helper_options.mem_model;
489 ODPH_ERR(
"Error: Global init failed.\n");
495 ODPH_ERR(
"Error: Local init failed.\n");
500 ODP_CACHE_LINE_SIZE, 0);
502 ODPH_ERR(
"Error: Shared mem reserve failed.\n");
507 if (global == NULL) {
508 ODPH_ERR(
"Error: Shared mem alloc failed\n");
512 memset(global, 0,
sizeof(test_global_t));
514 global->common_options = common_options;
516 if (parse_options(argc, argv, &global->options))
521 global->instance = instance;
523 if (create_stashes(global)) {
524 ODPH_ERR(
"Error: Create stashes failed.\n");
529 if (start_workers(global)) {
530 ODPH_ERR(
"Error: Test start failed.\n");
536 odph_thread_join(global->thread_tbl, global->options.num_cpu);
538 if (output_results(global)) {
544 if (destroy_stashes(global)) {
545 ODPH_ERR(
"Error: Destroy stashes failed.\n");
550 ODPH_ERR(
"Error: Shared mem free failed.\n");
555 ODPH_ERR(
"Error: term local failed.\n");
560 ODPH_ERR(
"Error: term global 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.
uint64_t odp_cpu_cycles_diff(uint64_t c2, uint64_t c1)
CPU cycle count difference.
uint64_t odp_cpu_cycles(void)
Current CPU cycle count.
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.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
#define ODP_SHM_INVALID
Invalid shared memory block.
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.
#define ODP_STASH_INVALID
Invalid stash handle.
void odp_stash_param_init(odp_stash_param_t *param)
Initialize stash params.
int odp_stash_destroy(odp_stash_t stash)
Destroy a stash.
int32_t odp_stash_put_u32(odp_stash_t stash, const uint32_t val[], int32_t num)
Put 32-bit integers into a stash.
int odp_stash_capability(odp_stash_capability_t *capa, odp_stash_type_t type)
Query stash capabilities.
int32_t odp_stash_get_u32(odp_stash_t stash, uint32_t val[], int32_t num)
Get 32-bit integers from a stash.
odp_stash_t odp_stash_create(const char *name, const odp_stash_param_t *param)
Create a stash.
@ ODP_STASH_TYPE_DEFAULT
The default stash type.
void odp_sys_info_print(void)
Print system info.
#define ODP_THREAD_COUNT_MAX
Maximum number of threads supported in build time.
int odp_thread_id(void)
Get thread identifier.
@ ODP_THREAD_WORKER
Worker thread.
odp_time_t odp_time_local(void)
Current local time.
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.
Stash capabilities (per stash type)
uint32_t max_stashes
Maximum number of stashes of this type.
uint64_t max_num_obj
Maximum common number of object handles per stash for any object size.
odp_bool_t strict_size
Strict size.
uint32_t obj_size
Object handle size in bytes.
uint64_t num_obj
Number of object handles.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_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()
struct odp_feature_t::@174 feat
Individual feature bits.
uint32_t schedule
Scheduler APIs, e.g., odp_schedule_xxx()
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()