diff options
Diffstat (limited to 'test/performance')
-rw-r--r-- | test/performance/odp_bench_packet.c | 6 | ||||
-rw-r--r-- | test/performance/odp_crypto.c | 1 | ||||
-rw-r--r-- | test/performance/odp_ipsec.c | 415 | ||||
-rwxr-xr-x | test/performance/odp_ipsec_run.sh | 4 | ||||
-rw-r--r-- | test/performance/odp_pktio_ordered.c | 2 | ||||
-rw-r--r-- | test/performance/odp_random.c | 445 | ||||
-rw-r--r-- | test/performance/odp_sched_pktio.c | 3 |
7 files changed, 614 insertions, 262 deletions
diff --git a/test/performance/odp_bench_packet.c b/test/performance/odp_bench_packet.c index 0354ef9b8..23fd17bea 100644 --- a/test/performance/odp_bench_packet.c +++ b/test/performance/odp_bench_packet.c @@ -756,7 +756,7 @@ static int bench_packet_headroom(void) for (i = 0; i < TEST_REPEAT_COUNT; i++) ret += odp_packet_headroom(gbl_args->pkt_tbl[i]); - return i; + return i + ret; } static int bench_packet_tailroom(void) @@ -767,7 +767,7 @@ static int bench_packet_tailroom(void) for (i = 0; i < TEST_REPEAT_COUNT; i++) ret += odp_packet_tailroom(gbl_args->pkt_tbl[i]); - return i; + return i + ret; } static int bench_packet_tail(void) @@ -1412,7 +1412,7 @@ static int bench_packet_has_ref(void) for (i = 0; i < TEST_REPEAT_COUNT; i++) ret += odp_packet_has_ref(pkt_tbl[i]); - return i; + return i + ret; } static int bench_packet_subtype(void) diff --git a/test/performance/odp_crypto.c b/test/performance/odp_crypto.c index a26d072e9..45e770d42 100644 --- a/test/performance/odp_crypto.c +++ b/test/performance/odp_crypto.c @@ -610,7 +610,6 @@ create_session_from_config(odp_crypto_session_t *session, odp_crypto_session_param_init(¶ms); memcpy(¶ms, &config->session, sizeof(odp_crypto_session_param_t)); params.op = ODP_CRYPTO_OP_ENCODE; - params.pref_mode = ODP_CRYPTO_SYNC; /* Lookup the packet pool */ pkt_pool = odp_pool_lookup("packet_pool"); diff --git a/test/performance/odp_ipsec.c b/test/performance/odp_ipsec.c index 5f1f9d4ef..c464ba0d7 100644 --- a/test/performance/odp_ipsec.c +++ b/test/performance/odp_ipsec.c @@ -1,4 +1,6 @@ /* Copyright (c) 2018, Linaro Limited + * Copyright (c) 2022, Marvell + * Copyright (c) 2022, Nokia * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause @@ -18,11 +20,14 @@ #include <odp_api.h> #include <odp/helper/odph_api.h> +#include <inttypes.h> /** @def POOL_NUM_PKT * Number of packets in the pool */ -#define POOL_NUM_PKT 64 +#define POOL_NUM_PKT 4096 + +#define MAX_DEQUEUE_BURST 16 static uint8_t test_salt[16] = "0123456789abcdef"; @@ -97,11 +102,11 @@ typedef struct { int in_flight; /** - * Number of iteration to repeat crypto operation to get good - * average number. Specified through -i or --terations option. + * Number of packets to be IPsec processed to get good average number. + * Specified through -c or --count option. * Default is 10000. */ - int iteration_count; + int packet_count; /** * Payload size to test. If 0 set of predefined payload sizes @@ -139,6 +144,19 @@ typedef struct { * Specified through -u argument. */ int ah; + + /* + * Burst size. + * Prepare and submit as many packets for IPsec processing in each + * iteration of the loop. + */ + int burst_size; + + /* + * Use vector packet completion from IPsec APIs. + * Specified through -v or --vector argument. + */ + uint32_t vec_pkt_size; } ipsec_args_t; /* @@ -516,7 +534,7 @@ print_result(ipsec_args_t *cargs, throughput = (1000000.0 / result->elapsed) * payload_length / 1024; printf("%30.30s %15d %15d %15.3f %15.3f %15.3f %15d\n", - config->name, cargs->iteration_count, payload_length, + config->name, cargs->packet_count, payload_length, result->elapsed, result->rusage_self, result->rusage_thread, throughput); } @@ -584,28 +602,49 @@ static uint8_t test_data[] = { 0x08, 0x00, 0xfb, 0x37, 0x12, 0x34, 0x00, 0x00 }; -static odp_packet_t -make_packet(odp_pool_t pkt_pool, unsigned int payload_length) +static inline void debug_packets(int debug, odp_packet_t *pkt, int num_pkts) { - odp_packet_t pkt; + if (odp_likely(!debug)) + return; + for (int i = 0; i < num_pkts; i++) + odp_packet_print_data(pkt[i], 0, odp_packet_len(pkt[i])); +} - if (payload_length < sizeof(test_data)) - return ODP_PACKET_INVALID; +static int +make_packet_multi(odp_pool_t pkt_pool, unsigned int payload_length, + odp_packet_t pkt[], int num) +{ + int i, ret; + + ret = odp_packet_alloc_multi(pkt_pool, payload_length, pkt, num); + if (ret != num) { + ODPH_ERR("Could not allocate buffer\n"); + if (ret > 0) + odp_packet_free_sp(pkt, ret); + return -1; + } + + for (i = 0; i < num; i++) { + odp_packet_copy_from_mem(pkt[i], 0, sizeof(test_data), test_data); + odp_packet_l3_offset_set(pkt[i], 0); - pkt = odp_packet_alloc(pkt_pool, payload_length); - if (pkt == ODP_PACKET_INVALID) { - ODPH_ERR("failed to allocate buffer\n"); - return pkt; + uint8_t *mem = odp_packet_data(pkt[i]); + ((odph_ipv4hdr_t *)mem)->tot_len = odp_cpu_to_be_16(payload_length); + memset(mem + sizeof(test_data), 1, payload_length - sizeof(test_data)); } - odp_packet_copy_from_mem(pkt, 0, sizeof(test_data), test_data); - odp_packet_l3_offset_set(pkt, 0); + return 0; +} - uint8_t *mem = odp_packet_data(pkt); - ((odph_ipv4hdr_t *)mem)->tot_len = odp_cpu_to_be_16(payload_length); - memset(mem + sizeof(test_data), 1, payload_length - sizeof(test_data)); +static inline void check_ipsec_result(odp_packet_t ipsec_pkt) +{ + odp_ipsec_packet_result_t result; - return pkt; + if (odp_unlikely(odp_ipsec_result(&result, ipsec_pkt))) + ODPH_ERR("odp_ipsec_result() failed\n"); + else if (odp_unlikely(result.status.error.all)) + ODPH_ERR("IPsec processing error: %" PRIu32 "\n", + result.status.error.all); } /** @@ -619,10 +658,13 @@ run_measure_one(ipsec_args_t *cargs, time_record_t *start, time_record_t *end) { + int in_flight, pkts_allowed, num_out, num_pkts, rc = 0; + const int max_in_flight = cargs->in_flight; + const int burst_size = cargs->burst_size; + const int packet_count = cargs->packet_count; + const int debug = cargs->debug_packets; odp_ipsec_out_param_t param; odp_pool_t pkt_pool; - odp_packet_t pkt = ODP_PACKET_INVALID; - int rc = 0; pkt_pool = odp_pool_lookup("packet_pool"); if (pkt_pool == ODP_POOL_INVALID) { @@ -630,6 +672,9 @@ run_measure_one(ipsec_args_t *cargs, return -1; } + if (payload_length < sizeof(test_data)) + return -1; + int packets_sent = 0; int packets_received = 0; @@ -641,43 +686,53 @@ run_measure_one(ipsec_args_t *cargs, fill_time_record(start); - while ((packets_sent < cargs->iteration_count) || - (packets_received < cargs->iteration_count)) { - if ((packets_sent < cargs->iteration_count) && - (packets_sent - packets_received < - cargs->in_flight)) { - odp_packet_t out_pkt; - int num_out = 1; + while ((packets_sent < packet_count) || + (packets_received < packet_count)) { + num_pkts = packet_count - packets_sent; + + /* Enqueue up to burst size */ + num_pkts = num_pkts > burst_size ? burst_size : num_pkts; + + /* Enqueue up to (max in flight - current in flight) */ + in_flight = packets_sent - packets_received; + pkts_allowed = max_in_flight - in_flight; - pkt = make_packet(pkt_pool, payload_length); - if (ODP_PACKET_INVALID == pkt) + /* Enqueue either a burst of packets or skip */ + num_pkts = num_pkts > pkts_allowed ? 0 : num_pkts; + + if (odp_likely(num_pkts)) { + odp_packet_t out_pkt[num_pkts]; + odp_packet_t pkt[num_pkts]; + int i; + + if (odp_unlikely(make_packet_multi(pkt_pool, + payload_length, + pkt, + num_pkts))) return -1; - if (cargs->debug_packets) - odp_packet_print_data(pkt, 0, - odp_packet_len(pkt)); + debug_packets(debug, pkt, num_pkts); + num_out = num_pkts; - rc = odp_ipsec_out(&pkt, 1, - &out_pkt, &num_out, + rc = odp_ipsec_out(pkt, num_pkts, + out_pkt, &num_out, ¶m); - if (rc <= 0) { - ODPH_ERR("failed odp_ipsec_out: rc = %d\n", rc); - odp_packet_free(pkt); + if (odp_unlikely(rc <= 0)) { + ODPH_ERR("Failed odp_ipsec_out: rc = %d\n", rc); + odp_packet_free_sp(pkt, num_pkts); break; } - if (odp_packet_has_error(out_pkt)) { - odp_ipsec_packet_result_t result; - odp_ipsec_result(&result, out_pkt); - ODPH_ERR("Received error packet: %d\n", - result.status.error.all); - } + for (i = 0; i < num_out; i++) + check_ipsec_result(out_pkt[i]); + packets_sent += rc; packets_received += num_out; - if (cargs->debug_packets) - odp_packet_print_data(out_pkt, 0, - odp_packet_len(out_pkt)); - odp_packet_free(out_pkt); + debug_packets(debug, out_pkt, num_out); + + if (odp_unlikely(rc != num_pkts)) + odp_packet_free_sp(&pkt[rc], num_pkts - rc); + odp_packet_free_sp(out_pkt, num_out); } } @@ -686,6 +741,46 @@ run_measure_one(ipsec_args_t *cargs, return rc < 0 ? rc : 0; } +static uint32_t dequeue_burst(odp_queue_t polled_queue, + odp_event_t *events, + int max_burst) +{ + int num = 0; + + if (polled_queue != ODP_QUEUE_INVALID) { + int rc = odp_queue_deq_multi(polled_queue, + events, + max_burst); + num = odp_likely(rc >= 0) ? rc : 0; + } else { + num = odp_schedule_multi(NULL, + ODP_SCHED_NO_WAIT, + events, + max_burst); + } + return num; +} + +static inline uint32_t vec_pkt_handle(int debug, odp_event_t ev) +{ + odp_packet_vector_t vec = odp_packet_vector_from_event(ev); + uint32_t vec_size = odp_packet_vector_size(vec); + odp_packet_t *pkt_tbl; + uint32_t j; + + odp_packet_vector_tbl(vec, &pkt_tbl); + + for (j = 0; j < vec_size; j++) + check_ipsec_result(pkt_tbl[j]); + + debug_packets(debug, pkt_tbl, vec_size); + + odp_packet_free_sp(pkt_tbl, vec_size); + odp_packet_vector_free(vec); + + return vec_size; +} + static int run_measure_one_async(ipsec_args_t *cargs, odp_ipsec_sa_t sa, @@ -693,11 +788,14 @@ run_measure_one_async(ipsec_args_t *cargs, time_record_t *start, time_record_t *end) { + int in_flight, packets_allowed, num_pkts, rc = 0; + const int max_in_flight = cargs->in_flight; + const int burst_size = cargs->burst_size; + const int packet_count = cargs->packet_count; + const int debug = cargs->debug_packets; odp_ipsec_out_param_t param; odp_pool_t pkt_pool; - odp_queue_t out_queue; - odp_packet_t pkt = ODP_PACKET_INVALID; - int rc = 0; + odp_queue_t polled_queue = ODP_QUEUE_INVALID; pkt_pool = odp_pool_lookup("packet_pool"); if (pkt_pool == ODP_POOL_INVALID) { @@ -705,12 +803,17 @@ run_measure_one_async(ipsec_args_t *cargs, return -1; } - out_queue = odp_queue_lookup("ipsec-out"); - if (out_queue == ODP_QUEUE_INVALID) { - ODPH_ERR("ipsec-out queue not found\n"); - return -1; + if (cargs->poll) { + polled_queue = odp_queue_lookup("ipsec-out"); + if (polled_queue == ODP_QUEUE_INVALID) { + ODPH_ERR("ipsec-out queue not found\n"); + return -1; + } } + if (payload_length < sizeof(test_data)) + return -1; + int packets_sent = 0; int packets_received = 0; @@ -722,55 +825,78 @@ run_measure_one_async(ipsec_args_t *cargs, fill_time_record(start); - while ((packets_sent < cargs->iteration_count) || - (packets_received < cargs->iteration_count)) { - odp_event_t ev; + while ((packets_sent < packet_count) || + (packets_received < packet_count)) { + + num_pkts = packet_count - packets_sent; + + /* Enqueue up to burst size */ + num_pkts = num_pkts > burst_size ? burst_size : num_pkts; + + /* Enqueue up to (max in flight - current in flight) */ + in_flight = packets_sent - packets_received; + packets_allowed = max_in_flight - in_flight; - if ((packets_sent < cargs->iteration_count) && - (packets_sent - packets_received < - cargs->in_flight)) { - pkt = make_packet(pkt_pool, payload_length); - if (ODP_PACKET_INVALID == pkt) + if (num_pkts > 0 && num_pkts <= packets_allowed) { + odp_packet_t pkt[num_pkts]; + + if (odp_unlikely(make_packet_multi(pkt_pool, + payload_length, + pkt, + num_pkts))) return -1; - if (cargs->debug_packets) - odp_packet_print_data(pkt, 0, - odp_packet_len(pkt)); + debug_packets(debug, pkt, num_pkts); - rc = odp_ipsec_out_enq(&pkt, 1, - ¶m); - if (rc <= 0) { - ODPH_ERR("failed odp_crypto_packet_op_enq: rc = %d\n", + rc = odp_ipsec_out_enq(pkt, num_pkts, ¶m); + if (odp_unlikely(rc <= 0)) { + ODPH_ERR("Failed odp_ipsec_out_enq: rc = %d\n", rc); - odp_packet_free(pkt); + odp_packet_free_sp(pkt, num_pkts); break; } + + if (odp_unlikely(rc != num_pkts)) + odp_packet_free_sp(&pkt[rc], num_pkts - rc); + packets_sent += rc; - } + } else { + odp_packet_t pkt_out[max_in_flight]; + uint32_t i = 0; + + /* + * Dequeue packets until we can enqueue the next burst + * or until we have received all remaining packets + * when there are no more packets to be sent. + */ + while (num_pkts > packets_allowed || + (num_pkts == 0 && packets_received < packet_count)) { + odp_event_t events[MAX_DEQUEUE_BURST]; + uint32_t num; + + num = dequeue_burst(polled_queue, events, MAX_DEQUEUE_BURST); + + for (uint32_t n = 0; n < num; n++) { + if (odp_event_type(events[n]) == ODP_EVENT_PACKET_VECTOR) { + uint32_t vec_size; + + vec_size = vec_pkt_handle(debug, events[n]); + packets_received += vec_size - 1; + packets_allowed += vec_size - 1; + } else { + pkt_out[i] = odp_ipsec_packet_from_event(events[n]); + check_ipsec_result(pkt_out[i]); + i++; + } + + } + packets_received += num; + packets_allowed += num; + } + debug_packets(debug, pkt_out, i); - if (cargs->schedule) - ev = odp_schedule(NULL, - ODP_SCHED_NO_WAIT); - else - ev = odp_queue_deq(out_queue); - - while (ev != ODP_EVENT_INVALID) { - odp_packet_t out_pkt; - odp_ipsec_packet_result_t result; - - out_pkt = odp_ipsec_packet_from_event(ev); - odp_ipsec_result(&result, out_pkt); - - if (cargs->debug_packets) - odp_packet_print_data(out_pkt, 0, - odp_packet_len(out_pkt)); - odp_packet_free(out_pkt); - packets_received++; - if (cargs->schedule) - ev = odp_schedule(NULL, - ODP_SCHED_NO_WAIT); - else - ev = odp_queue_deq(out_queue); + if (i) + odp_packet_free_sp(pkt_out, i); } } @@ -843,13 +969,13 @@ run_measure_one_config(ipsec_args_t *cargs, break; count = get_elapsed_usec(&start, &end); - result.elapsed = count / cargs->iteration_count; + result.elapsed = count / cargs->packet_count; count = get_rusage_self_diff(&start, &end); - result.rusage_self = count / cargs->iteration_count; + result.rusage_self = count / cargs->packet_count; count = get_rusage_thread_diff(&start, &end); - result.rusage_thread = count / cargs->iteration_count; + result.rusage_thread = count / cargs->packet_count; print_result(cargs, payloads[i], config, &result); @@ -913,7 +1039,9 @@ static void usage(char *progname) print_config_names(" "); printf(" -d, --debug Enable dump of processed packets.\n" " -f, --flight <number> Max number of packet processed in parallel (default 1)\n" - " -i, --iterations <number> Number of iterations.\n" + " -c, --count <number> Number of packets (default 10000)\n" + " -b, --burst <number> Number of packets in one IPsec API submission (default 1)\n" + " -v, --vector <number> Enable vector packet completion from IPsec APIs with specified vector size.\n" " -l, --payload Payload length.\n" " -s, --schedule Use scheduler for completion events.\n" " -p, --poll Poll completion queue for completion events.\n" @@ -932,7 +1060,9 @@ static void parse_args(int argc, char *argv[], ipsec_args_t *cargs) {"debug", no_argument, NULL, 'd'}, {"flight", optional_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, - {"iterations", optional_argument, NULL, 'i'}, + {"count", optional_argument, NULL, 'c'}, + {"burst", optional_argument, NULL, 'b'}, + {"vector", optional_argument, NULL, 'v'}, {"payload", optional_argument, NULL, 'l'}, {"sessions", optional_argument, NULL, 'm'}, {"poll", no_argument, NULL, 'p'}, @@ -942,11 +1072,13 @@ static void parse_args(int argc, char *argv[], ipsec_args_t *cargs) {NULL, 0, NULL, 0} }; - static const char *shortopts = "+a:c:df:hi:m:nl:sptu"; + static const char *shortopts = "+a:b:c:df:hm:nl:sptuv:"; cargs->in_flight = 1; cargs->debug_packets = 0; - cargs->iteration_count = 10000; + cargs->packet_count = 10000; + cargs->burst_size = 1; + cargs->vec_pkt_size = 0; cargs->payload_length = 0; cargs->alg_config = NULL; cargs->schedule = 0; @@ -971,8 +1103,24 @@ static void parse_args(int argc, char *argv[], ipsec_args_t *cargs) case 'd': cargs->debug_packets = 1; break; - case 'i': - cargs->iteration_count = atoi(optarg); + case 'c': + cargs->packet_count = atoi(optarg); + break; + case 'b': + if (optarg == NULL) + cargs->burst_size = 32; + else + cargs->burst_size = atoi(optarg); + if (cargs->burst_size > POOL_NUM_PKT) { + printf("Invalid burst size (max allowed: %d)\n", POOL_NUM_PKT); + exit(-1); + } + break; + case 'v': + if (optarg == NULL) + cargs->vec_pkt_size = 32; + else + cargs->vec_pkt_size = atoi(optarg); break; case 'f': cargs->in_flight = atoi(optarg); @@ -1001,6 +1149,11 @@ static void parse_args(int argc, char *argv[], ipsec_args_t *cargs) } } + if (cargs->in_flight < cargs->burst_size) { + printf("-f (flight) must be greater than or equal to -b (burst)\n"); + exit(-1); + } + optind = 1; /* reset 'extern optind' from the getopt lib */ if (cargs->schedule && cargs->poll) { @@ -1012,6 +1165,7 @@ static void parse_args(int argc, char *argv[], ipsec_args_t *cargs) int main(int argc, char *argv[]) { + odp_pool_t vec_pool = ODP_POOL_INVALID; ipsec_args_t cargs; odp_pool_t pool; odp_queue_param_t qparam; @@ -1105,11 +1259,54 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (cargs.vec_pkt_size) { + if (capa.vector.max_pools < 1) { + ODPH_ERR("Vector packet pool not available"); + exit(EXIT_FAILURE); + } + + if (!ipsec_capa.vector.supported) { + ODPH_ERR("Vector packet completion not supported by IPsec.\n"); + exit(EXIT_FAILURE); + } + + if (capa.vector.max_size < cargs.vec_pkt_size) { + ODPH_ERR("Vector size larger than max size supported by vector pool.\n"); + exit(EXIT_FAILURE); + } + + if (!cargs.schedule && !cargs.poll) { + ODPH_ERR("Vector packet is not supported with sync APIs.\n"); + exit(EXIT_FAILURE); + } + + /* Create vector pool */ + odp_pool_param_init(¶m); + param.vector.num = POOL_NUM_PKT; + param.vector.max_size = cargs.vec_pkt_size; + param.type = ODP_POOL_VECTOR; + vec_pool = odp_pool_create("vector_pool", ¶m); + + if (vec_pool == ODP_POOL_INVALID) { + ODPH_ERR("Vector packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + + odp_pool_print(vec_pool); + } + odp_ipsec_config_init(&config); config.max_num_sa = 2; config.inbound.chksums.all_chksum = 0; config.outbound.all_chksum = 0; + if (vec_pool != ODP_POOL_INVALID) { + config.vector.enable = true; + config.vector.pool = vec_pool; + config.vector.max_size = cargs.vec_pkt_size; + config.vector.max_tmo_ns = ipsec_capa.vector.max_tmo_ns; + } + odp_queue_param_init(&qparam); if (cargs.schedule) { odp_schedule_config(NULL); @@ -1196,6 +1393,14 @@ int main(int argc, char *argv[]) if (cargs.schedule || cargs.poll) odp_queue_destroy(out_queue); + + if (cargs.vec_pkt_size) { + if (odp_pool_destroy(vec_pool)) { + ODPH_ERR("Error: vector pool destroy\n"); + exit(EXIT_FAILURE); + } + } + if (odp_pool_destroy(pool)) { ODPH_ERR("Error: pool destroy\n"); exit(EXIT_FAILURE); diff --git a/test/performance/odp_ipsec_run.sh b/test/performance/odp_ipsec_run.sh index 1974a7c55..2ddb48d07 100755 --- a/test/performance/odp_ipsec_run.sh +++ b/test/performance/odp_ipsec_run.sh @@ -7,9 +7,9 @@ TEST_DIR="${TEST_DIR:-$(dirname $0)}" -# Run with a small number of iterations in make check +# Run with a small number of packets in make check -$TEST_DIR/odp_ipsec${EXEEXT} -i 100 +$TEST_DIR/odp_ipsec${EXEEXT} -c 100 if [ $? -ne 0 ] ; then echo Test FAILED diff --git a/test/performance/odp_pktio_ordered.c b/test/performance/odp_pktio_ordered.c index 37a0899b6..130eb4688 100644 --- a/test/performance/odp_pktio_ordered.c +++ b/test/performance/odp_pktio_ordered.c @@ -1258,7 +1258,7 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if ((unsigned)gbl_args->appl.num_flows > capa.max_output_queues) + if ((uint32_t)gbl_args->appl.num_flows > capa.max_output_queues) gbl_args->appl.num_flows = capa.max_output_queues; } 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); } diff --git a/test/performance/odp_sched_pktio.c b/test/performance/odp_sched_pktio.c index 77c1d260f..11be9d367 100644 --- a/test/performance/odp_sched_pktio.c +++ b/test/performance/odp_sched_pktio.c @@ -862,10 +862,9 @@ static int open_pktios(test_global_t *test_global) odp_pktin_queue_param_t pktin_param; odp_pktout_queue_param_t pktout_param; odp_schedule_sync_t sched_sync; - unsigned int num_queue; + uint32_t num_queue, j; char *name; int i, num_pktio, ret; - unsigned int j; num_pktio = test_global->opt.num_pktio; num_queue = test_global->opt.num_pktio_queue; |