diff options
Diffstat (limited to 'test/performance/odp_random.c')
-rw-r--r-- | test/performance/odp_random.c | 445 |
1 files changed, 297 insertions, 148 deletions
diff --git a/test/performance/odp_random.c b/test/performance/odp_random.c index 622a58c65..46134ac0c 100644 --- a/test/performance/odp_random.c +++ b/test/performance/odp_random.c @@ -14,20 +14,52 @@ #include <odp_api.h> #include <odp/helper/odph_api.h> +#define PSEUDO_RANDOM (-1) + #define MB (1024ull * 1024ull) +typedef struct test_global_t test_global_t; + +typedef struct thread_arg_t { + test_global_t *global; + int thread_idx; + uint8_t *data; + +} thread_arg_t; + +struct test_global_t { + odp_barrier_t barrier; + odp_random_kind_t type; + uint8_t *data; + uint32_t rounds; + + thread_arg_t thread_arg[ODP_THREAD_COUNT_MAX]; + + struct { + uint64_t nsec[ODP_THREAD_COUNT_MAX]; + uint64_t sum[ODP_THREAD_COUNT_MAX]; + uint64_t min[ODP_THREAD_COUNT_MAX]; + uint64_t max[ODP_THREAD_COUNT_MAX]; + } stat; +}; + /* Command line options */ typedef struct { + int mode; int num_threads; uint32_t size; uint32_t rounds; + uint64_t delay; + } options_t; static options_t options; static const options_t options_def = { + .mode = 0, .num_threads = 1, .size = 256, .rounds = 100000, + .delay = 0, }; static void print_usage(void) @@ -37,13 +69,18 @@ static void print_usage(void) "\n" "Usage: odp_random [options]\n" "\n" + " -m, --mode Test mode select (default: 0):\n" + " 0: Data throughput\n" + " 1: Data generation latency (size: 8B by default)\n" " -t, --threads Number of worker threads (default %u)\n" " -s, --size Size of buffer in bytes (default %u)\n" " -r, --rounds Number of test rounds (default %u)\n" " Divided by 100 for ODP_RANDOM_TRUE\n" + " -d, --delay Delay (nsec) between buffer fills (default %" PRIu64 ").\n" + " Affects only latency mode.\n" " -h, --help This help\n" "\n", - options_def.num_threads, options_def.size, options_def.rounds); + options_def.num_threads, options_def.size, options_def.rounds, options_def.delay); } static int parse_options(int argc, char *argv[]) @@ -53,16 +90,19 @@ static int parse_options(int argc, char *argv[]) int ret = 0; static const struct option longopts[] = { + { "mode", required_argument, NULL, 'm' }, { "threads", required_argument, NULL, 't' }, { "size", required_argument, NULL, 's' }, { "rounds", required_argument, NULL, 'r' }, + { "delay", required_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } }; - static const char *shortopts = "+t:s:r:h"; + static const char *shortopts = "+m:t:s:r:d:h"; options = options_def; + options.size = 0; while (1) { opt = getopt_long(argc, argv, shortopts, longopts, &long_index); @@ -71,6 +111,9 @@ static int parse_options(int argc, char *argv[]) break; switch (opt) { + case 'm': + options.mode = atoi(optarg); + break; case 't': options.num_threads = atol(optarg); break; @@ -80,6 +123,9 @@ static int parse_options(int argc, char *argv[]) case 'r': options.rounds = atol(optarg); break; + case 'd': + options.delay = atol(optarg); + break; case 'h': /* fall through */ default: @@ -89,170 +135,216 @@ static int parse_options(int argc, char *argv[]) } } - if (options.size < 1) { - ODPH_ERR("Invalid size: %" PRIu32 "\n", options.size); + if (options.num_threads < 1 || options.num_threads > ODP_THREAD_COUNT_MAX) { + ODPH_ERR("Bad number of threads: %i\n", options.num_threads); return -1; } + if (options.size == 0) { + options.size = options_def.size; + + if (options.mode) + options.size = 8; + } + + printf("\nOptions:\n"); + printf("------------------------\n"); + printf(" mode: %i\n", options.mode); + printf(" threads: %i\n", options.num_threads); + printf(" size: %u\n", options.size); + printf(" rounds: %u\n", options.rounds); + printf(" delay: %" PRIu64 "\n", options.delay); + printf("\n"); + return ret; } -const char *shm_name = "odp_random_test"; +static inline void random_data_loop(odp_random_kind_t type, uint32_t rounds, + uint8_t *data, uint32_t size) +{ + uint32_t i; + int32_t ret; -typedef struct test_shm_t { - odp_barrier_t barrier; - odp_random_kind_t type; - uint64_t nsec[ODP_THREAD_COUNT_MAX]; -} test_shm_t; + if ((int)type == PSEUDO_RANDOM) { + uint64_t seed = 0; -static test_shm_t *shm_lookup(void) -{ - test_shm_t *shm = NULL; - odp_shm_t shm_hdl = odp_shm_lookup(shm_name); + for (i = 0; i < rounds; i++) { + uint32_t pos = 0; - if (shm_hdl != ODP_SHM_INVALID) - shm = (test_shm_t *)odp_shm_addr(shm_hdl); + while (pos < size) { + ret = odp_random_test_data(data + pos, size - pos, &seed); - return shm; -} + if (ret < 0) { + ODPH_ERR("odp_random_test_data() failed\n"); + exit(EXIT_FAILURE); + } -static uint32_t type_rounds(odp_random_kind_t type) -{ - switch (type) { - case ODP_RANDOM_TRUE: - return options.rounds / 100; - default: - return options.rounds; + pos += ret; + } + } + } else { + for (i = 0; i < rounds; i++) { + uint32_t pos = 0; + + while (pos < size) { + ret = odp_random_data(data + pos, size - pos, type); + + if (ret < 0) { + ODPH_ERR("odp_random_data() failed\n"); + exit(EXIT_FAILURE); + } + + pos += ret; + } + } } } -static int test_random(void *p) +static int test_random_perf(void *ptr) { - (void)p; - - uint8_t *buf, *data; - const unsigned long page = ODP_PAGE_SIZE; odp_time_t start; uint64_t nsec; - uint32_t rounds; - test_shm_t *shm = shm_lookup(); + thread_arg_t *thread_arg = ptr; + test_global_t *global = thread_arg->global; + odp_random_kind_t type = global->type; + int thread_idx = thread_arg->thread_idx; + uint8_t *data = thread_arg->data; + uint32_t size = options.size; + uint32_t rounds = global->rounds; - if (!shm) { - ODPH_ERR("Failed to look up shm %s\n", shm_name); - exit(EXIT_FAILURE); - } + /* One warm up round */ + random_data_loop(type, 1, data, size); - rounds = type_rounds(shm->type); + odp_barrier_wait(&global->barrier); - /* One extra page for alignment. */ - buf = (uint8_t *)malloc(options.size + page); - - if (!buf) { - ODPH_ERR("Memory allocation failed.\n"); - exit(EXIT_FAILURE); - } - - /* Align to start of page. */ - data = (uint8_t *)(((uintptr_t)buf + (page - 1)) & ~(page - 1)); - - odp_barrier_wait(&shm->barrier); + /* Test run */ start = odp_time_local(); - for (uint32_t i = 0; i < rounds; i++) { - uint32_t pos = 0; - - while (pos < options.size) { - int32_t n = odp_random_data(data + pos, - options.size - pos, - shm->type); - - if (n < 0) { - ODPH_ERR("odp_random_data() failed\n"); - exit(EXIT_FAILURE); - } - - pos += n; - } - } + random_data_loop(type, rounds, data, size); nsec = odp_time_diff_ns(odp_time_local(), start); - shm->nsec[odp_thread_id()] = nsec; - free(buf); + + global->stat.nsec[thread_idx] = nsec; return 0; } -static int test_random_test(void *p) +static inline void random_data_latency(test_global_t *global, int thread_idx, + uint32_t rounds, uint8_t *data, uint32_t size) { - (void)p; - - uint8_t *buf, *data; - const unsigned long page = ODP_PAGE_SIZE; - odp_time_t start; + uint32_t i; + int32_t ret; + odp_time_t t1, t2, start; uint64_t nsec; + odp_random_kind_t type = global->type; + uint64_t delay = options.delay; + uint64_t min = UINT64_MAX; + uint64_t max = 0; + uint64_t sum = 0; uint64_t seed = 0; - uint32_t rounds; - test_shm_t *shm = shm_lookup(); - - if (!shm) { - ODPH_ERR("Failed to look up shm %s\n", shm_name); - exit(EXIT_FAILURE); - } - - rounds = type_rounds(shm->type); - - /* One extra page for alignment. */ - buf = (uint8_t *)malloc(options.size + page); - - if (!buf) { - ODPH_ERR("Memory allocation failed.\n"); - exit(EXIT_FAILURE); - } - - /* Align to start of page. */ - data = (uint8_t *)(((uintptr_t)buf + (page - 1)) & ~(page - 1)); - odp_barrier_wait(&shm->barrier); start = odp_time_local(); - for (uint32_t i = 0; i < rounds; i++) { + for (i = 0; i < rounds; i++) { uint32_t pos = 0; - while (pos < options.size) { - int32_t n = odp_random_test_data(data + pos, - options.size - pos, - &seed); + if (delay) + odp_time_wait_ns(delay); - if (n < 0) { - ODPH_ERR("odp_random_data() failed\n"); - exit(EXIT_FAILURE); - } + if ((int)type == PSEUDO_RANDOM) { + t1 = odp_time_local_strict(); + while (pos < size) { + ret = odp_random_test_data(data + pos, size - pos, &seed); + + if (ret < 0) { + ODPH_ERR("odp_random_test_data() failed\n"); + exit(EXIT_FAILURE); + } - pos += n; + pos += ret; + } + t2 = odp_time_local_strict(); + } else { + t1 = odp_time_local_strict(); + while (pos < size) { + ret = odp_random_data(data + pos, size - pos, type); + + if (ret < 0) { + ODPH_ERR("odp_random_data() failed\n"); + exit(EXIT_FAILURE); + } + + pos += ret; + } + t2 = odp_time_local_strict(); } + + nsec = odp_time_diff_ns(t2, t1); + sum += nsec; + + if (nsec > max) + max = nsec; + if (nsec < min) + min = nsec; } nsec = odp_time_diff_ns(odp_time_local(), start); - shm->nsec[odp_thread_id()] = nsec; - free(buf); + + global->stat.nsec[thread_idx] = nsec; + global->stat.sum[thread_idx] = sum; + global->stat.min[thread_idx] = min; + global->stat.max[thread_idx] = max; +} + +static int test_random_latency(void *ptr) +{ + thread_arg_t *thread_arg = ptr; + test_global_t *global = thread_arg->global; + odp_random_kind_t type = global->type; + int thread_idx = thread_arg->thread_idx; + uint8_t *data = thread_arg->data; + uint32_t size = options.size; + uint32_t rounds = global->rounds; + + /* One warm up round */ + random_data_loop(type, 1, data, size); + + odp_barrier_wait(&global->barrier); + + /* Test run */ + random_data_latency(global, thread_idx, rounds, data, size); return 0; } -static void test_type(odp_instance_t instance, test_shm_t *shm, - odp_random_kind_t type) +static uint32_t type_rounds(odp_random_kind_t type) +{ + switch (type) { + case ODP_RANDOM_TRUE: + return options.rounds / 100; + default: + return options.rounds; + } +} + +static void test_type(odp_instance_t instance, test_global_t *global, odp_random_kind_t type) { - memset(shm, 0, sizeof(test_shm_t)); - shm->type = type; - odp_barrier_init(&shm->barrier, options.num_threads); + int i; + int num_threads = options.num_threads; + uint32_t rounds = type_rounds(type); + uint32_t size = options.size; + + memset(&global->stat, 0, sizeof(global->stat)); + global->type = type; + global->rounds = rounds; + odp_barrier_init(&global->barrier, num_threads); odp_cpumask_t cpumask; odph_thread_common_param_t thr_common; - odph_thread_param_t thr_param; - odph_thread_t thr_worker[options.num_threads]; + odph_thread_param_t thr_param[num_threads]; + odph_thread_t thr_worker[num_threads]; - if (odp_cpumask_default_worker(&cpumask, options.num_threads) != - options.num_threads) { + if (odp_cpumask_default_worker(&cpumask, num_threads) != num_threads) { ODPH_ERR("Failed to get default CPU mask.\n"); exit(EXIT_FAILURE); } @@ -260,35 +352,36 @@ static void test_type(odp_instance_t instance, test_shm_t *shm, 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.thr_type = ODP_THREAD_WORKER; - thr_param.start = test_random; + for (i = 0; i < num_threads; i++) { + odph_thread_param_init(&thr_param[i]); + thr_param[i].thr_type = ODP_THREAD_WORKER; + thr_param[i].arg = &global->thread_arg[i]; - if (type == (odp_random_kind_t)-1) - thr_param.start = test_random_test; + if (options.mode == 0) + thr_param[i].start = test_random_perf; + else + thr_param[i].start = test_random_latency; + } memset(&thr_worker, 0, sizeof(thr_worker)); - if (odph_thread_create(thr_worker, &thr_common, &thr_param, - options.num_threads) != options.num_threads) { + if (odph_thread_create(thr_worker, &thr_common, thr_param, num_threads) != num_threads) { ODPH_ERR("Failed to create worker threads.\n"); exit(EXIT_FAILURE); } - if (odph_thread_join(thr_worker, options.num_threads) != - options.num_threads) { + if (odph_thread_join(thr_worker, num_threads) != num_threads) { ODPH_ERR("Failed to join worker threads.\n"); exit(EXIT_FAILURE); } double mb, seconds, nsec = 0; - for (int i = 0; i < ODP_THREAD_COUNT_MAX; i++) - nsec += shm->nsec[i]; + for (i = 0; i < num_threads; i++) + nsec += global->stat.nsec[i]; - nsec /= options.num_threads; + nsec /= num_threads; switch (type) { case ODP_RANDOM_BASIC: @@ -304,25 +397,53 @@ static void test_type(odp_instance_t instance, test_shm_t *shm, printf("odp_random_test_data\n"); } - uint32_t rounds = type_rounds(type); - printf("--------------------\n"); - printf("threads: %d size: %u B rounds: %u ", options.num_threads, - options.size, rounds); - mb = (uint64_t)options.num_threads * (uint64_t)options.size * - (uint64_t)rounds; + printf("threads: %d size: %u B rounds: %u ", num_threads, size, rounds); + mb = (uint64_t)num_threads * (uint64_t)size * (uint64_t)rounds; mb /= MB; seconds = (double)nsec / (double)ODP_TIME_SEC_IN_NS; printf("MB: %.3f seconds: %.3f ", mb, seconds); printf("MB/s: %.3f ", mb / seconds); - printf("MB/s/thread: %.3f", mb / seconds / (double)options.num_threads); - printf("\n\n"); + printf("MB/s/thread: %.3f\n", mb / seconds / (double)num_threads); + + if (options.mode) { + double ave; + uint64_t min = UINT64_MAX; + uint64_t max = 0; + uint64_t sum = 0; + + printf(" latency (nsec)\n"); + printf(" thread min max ave\n"); + for (i = 0; i < num_threads; i++) { + ave = (double)global->stat.sum[i] / rounds; + sum += global->stat.sum[i]; + + if (global->stat.min[i] < min) + min = global->stat.min[i]; + + if (global->stat.max[i] > max) + max = global->stat.max[i]; + + printf("%8i %8" PRIu64 " %8" PRIu64 " %10.1f\n", i, global->stat.min[i], + global->stat.max[i], ave); + } + + printf(" all %8" PRIu64 " %8" PRIu64 " %10.1f\n", + min, max, ((double)sum / rounds) / num_threads); + } + + printf("\n"); } int main(int argc, char **argv) { odp_instance_t instance; odp_init_t init; + odp_shm_t shm_glb, shm_data; + test_global_t *global; + int num_threads, i; + uint64_t tot_size, size; + uint8_t *addr; if (parse_options(argc, argv)) exit(EXIT_FAILURE); @@ -352,31 +473,59 @@ int main(int argc, char **argv) odp_sys_info_print(); - test_shm_t *shm = NULL; - odp_shm_t shm_hdl = odp_shm_reserve(shm_name, sizeof(test_shm_t), 64, - 0); + global = NULL; + shm_glb = odp_shm_reserve("test_globals", sizeof(test_global_t), ODP_CACHE_LINE_SIZE, 0); + + if (shm_glb != ODP_SHM_INVALID) + global = (test_global_t *)odp_shm_addr(shm_glb); + + if (!global) { + ODPH_ERR("Failed to reserve shm\n"); + exit(EXIT_FAILURE); + } + + memset(global, 0, sizeof(test_global_t)); + + num_threads = options.num_threads; + addr = NULL; + size = ODP_CACHE_LINE_SIZE + ODP_CACHE_LINE_ROUNDUP(options.size); + tot_size = num_threads * size; + shm_data = odp_shm_reserve("test_data", tot_size, ODP_CACHE_LINE_SIZE, 0); - if (shm_hdl != ODP_SHM_INVALID) - shm = (test_shm_t *)odp_shm_addr(shm_hdl); + if (shm_data != ODP_SHM_INVALID) + addr = odp_shm_addr(shm_data); - if (!shm) { - ODPH_ERR("Failed to reserve shm %s\n", shm_name); + if (!addr) { + ODPH_ERR("Failed to reserve shm: size %" PRIu64 " bytes\n", tot_size); exit(EXIT_FAILURE); } + for (i = 0; i < num_threads; i++) { + global->thread_arg[i].global = global; + global->thread_arg[i].thread_idx = i; + global->thread_arg[i].data = addr + i * size; + } + + odp_shm_print_all(); + switch (odp_random_max_kind()) { case ODP_RANDOM_TRUE: - test_type(instance, shm, ODP_RANDOM_TRUE); + test_type(instance, global, ODP_RANDOM_TRUE); /* fall through */ case ODP_RANDOM_CRYPTO: - test_type(instance, shm, ODP_RANDOM_CRYPTO); + test_type(instance, global, ODP_RANDOM_CRYPTO); /* fall through */ default: - test_type(instance, shm, ODP_RANDOM_BASIC); - test_type(instance, shm, -1); + test_type(instance, global, ODP_RANDOM_BASIC); + test_type(instance, global, PSEUDO_RANDOM); + } + + if (odp_shm_free(shm_data)) { + ODPH_ERR("odp_shm_free() failed\n"); + exit(EXIT_FAILURE); } - if (odp_shm_free(shm_hdl)) { + if (odp_shm_free(shm_glb)) { ODPH_ERR("odp_shm_free() failed\n"); exit(EXIT_FAILURE); } |