Message ID | 1410397827-2758-6-git-send-email-victor.kamensky@linaro.org |
---|---|
State | New |
Headers | show |
On 2014-09-10 18:10, Victor Kamensky wrote: > Sample test code that measures speed of ODP crypto operations. > o measures operation elapsed, cpu time, and throughput > o supports multiple algorithms > o supports multiple payload sizes > o support synch and async crypto operation modes > > Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org> > --- > configure.ac | 1 + > example/Makefile.am | 2 +- > example/cspeed/Makefile.am | 6 + > example/cspeed/odp_cspeed.c | 918 ++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 926 insertions(+), 1 deletion(-) > create mode 100644 example/cspeed/Makefile.am > create mode 100644 example/cspeed/odp_cspeed.c > > diff --git a/configure.ac b/configure.ac > index b1fc859..0592334 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -153,6 +153,7 @@ AC_CONFIG_FILES([Makefile > platform/linux-keystone2/Makefile > platform/linux-dpdk/Makefile > example/Makefile > + example/cspeed/Makefile > example/generator/Makefile > example/l2fwd/Makefile > example/odp_example/Makefile > diff --git a/example/Makefile.am b/example/Makefile.am > index 01a3305..d7fb80a 100644 > --- a/example/Makefile.am > +++ b/example/Makefile.am > @@ -1 +1 @@ > -SUBDIRS = generator l2fwd odp_example packet packet_netmap timer > +SUBDIRS = cspeed generator l2fwd odp_example packet packet_netmap timer > diff --git a/example/cspeed/Makefile.am b/example/cspeed/Makefile.am > new file mode 100644 > index 0000000..9b0b2ee > --- /dev/null > +++ b/example/cspeed/Makefile.am > @@ -0,0 +1,6 @@ > +include $(top_srcdir)/example/Makefile.inc > + > +bin_PROGRAMS = odp_cspeed > +odp_cspeed_LDFLAGS = $(AM_LDFLAGS) -static > + > +dist_odp_cspeed_SOURCES = odp_cspeed.c > diff --git a/example/cspeed/odp_cspeed.c b/example/cspeed/odp_cspeed.c > new file mode 100644 > index 0000000..8e59180 > --- /dev/null > +++ b/example/cspeed/odp_cspeed.c > @@ -0,0 +1,918 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#ifndef _GNU_SOURCE > +#define _GNU_SOURCE > +#endif /* _GNU_SOURCE */ > + > +#include <stdlib.h> > +#include <string.h> > +#include <getopt.h> > +#include <unistd.h> > +#include <sys/time.h> > +#include <sys/resource.h> > + > +#include <odp.h> > + > + > +#define cspeed_error(fmt, ...) \ > + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \ > + __LINE__, __func__, ##__VA_ARGS__) > + > + > +/** @def SHM_PKT_POOL_SIZE > + * @brief Size of the shared memory block > + */ > +#define SHM_PKT_POOL_SIZE (512*2048*2) > + > + > +/** @def SHM_PKT_POOL_BUF_SIZE > + * @brief Buffer size of the packet pool buffer > + */ > +#define SHM_PKT_POOL_BUF_SIZE (1024 * 32) > + > + > +static uint8_t test_iv[8] = "01234567"; > + > + > +static uint8_t test_key16[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, > + 0x06, 0x07, 0x08, 0x09, 0x0a, > + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, > + 0x10, > +}; > + > + > +static uint8_t test_key24[24] = { 0x01, 0x02, 0x03, 0x04, 0x05, > + 0x06, 0x07, 0x08, 0x09, 0x0a, > + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, > + 0x10, 0x11, 0x12, 0x13, 0x14, > + 0x15, 0x16, 0x17, 0x18 > +}; > + > +/** > + * Structure that holds template for session create call > + * for different algorithms supported by test > + */ > +typedef struct { > + const char *name; /**< Algorithm name */ > + odp_crypto_session_params_t session; /**< Prefilled crypto session params */ > + unsigned int hash_adjust; /**< Size of hash */ > +} cspeed_alg_config_t; > + > + > +/** > + * Parsed command line cspeed arguments. Describes test configuration. > + */ > +typedef struct { > + /** > + * If non zero prints content of packets. Enabled by -d or > + * --debug option. > + */ > + int debug_packets; > + > + /** > + * If non zero Try to run crypto operation in place. Note some > + * implementation may not support such mode. Enabled by -n or > + * --inplace option. > + */ > + int in_place; > + > + /** > + * If non zeor output of previous operation taken as input for > + * next encrypt operations. Enabled by -r or --reuse option. > + */ > + int reuse_packet; > + > + /** > + * Maxiumum number of outstanding encryption requests. Note code > + * poll for results over queue and if nothing is available it can > + * submit more encryption requests up to maximum number specified by > + * this option. Specified through -f or --flight option. > + */ > + int in_flight; > + > + /** > + * Number of core to run on. Currently is not used. > + */ > + int core_count; > + > + /** > + * Number of iteration to repeat crypto operation to get good > + * average number. Specified through -i or --terations option. > + * Default is 10000. > + */ > + int iteration_count; > + > + /** > + * Maxium sessions. Currently is not used. > + */ > + int max_sessions; > + > + /** > + * Payload size to test. If 0 set of predefined payload sizes > + * is tested. Specified through -p or --payload option. > + */ > + int payload_size; > + > + /** > + * Pointer to selected algorithm to test. If NULL all available > + * alogorthims are tested. Name of algorithm is passed through > + * -a or --algorithm option. > + */ > + cspeed_alg_config_t *alg_config; > +} cspeed_args_t; > + > + > +/* > + * Helper structure that holds averages for test of one algorithm > + * for given payload size. > + */ > +typedef struct { > + /** > + * Elapsed time for one crypto operation. > + */ > + double elapsed; > + > + /** > + * CPU time spent pre one crypto operation by whole process > + * i.e include current and all other threads in process. > + * It is filled with 'getrusage(RUSAGE_SELF, ...)' call. > + */ > + double rusage_self; > + > + /** > + * CPU time spent per one crypto operation by current thread > + * only. It is filled with 'getrusage(RUSAGE_THREAD, ...)' > + * call. > + */ > + double rusage_thread; > +} cspeed_run_result_t; > + > + > +/** > + * Structure holds one snap to misc times of current process. > + */ > +typedef struct { > + struct timeval tv; /**< Elapsed time */ > + struct rusage ru_self; /**< Rusage value for whole process */ > + struct rusage ru_thread; /**< Rusage value for current thread */ > +} time_record_t; > + > + > +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs); > +static void usage(char *progname); > + > +/** > + * Set of predefined payloads. Make sure that maximum payload > + * size is not bigger than SHM_PKT_POOL_BUF_SIZE. May relax when > + * implementation start support segmented buffers/packets. > + */ > +static unsigned int payloads[] = { > + 16, > + 64, > + 256, > + 1024, > + 8192, > + 16384 > +}; > + > +/** > + * Set of known algorithms to test > + */ > +static cspeed_alg_config_t algs_config[] = { > + { > + .name = "3des-cbs-null", > + .session = { > + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, > + .cipher_key = { > + .data = test_key24, > + .length = sizeof(test_key24) > + }, > + .iv = { > + .data = test_iv, > + .length = 8, > + }, > + .auth_alg = ODP_AUTH_ALG_NULL > + }, > + }, > + { > + .name = "3des-cbs-hmac-md5-96", > + .session = { > + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, > + .cipher_key = { > + .data = test_key24, > + .length = sizeof(test_key24) > + }, > + .iv = { > + .data = test_iv, > + .length = 8, > + }, > + .auth_alg = ODP_AUTH_ALG_MD5_96, > + .auth_key = { > + .data = test_key16, > + .length = sizeof(test_key16) > + } > + }, > + .hash_adjust = 12 > + }, > + { > + .name ="null-hmac-md5-96", > + .session = { > + .cipher_alg = ODP_CIPHER_ALG_NULL, > + .auth_alg = ODP_AUTH_ALG_MD5_96, > + .auth_key = { > + .data = test_key16, > + .length = sizeof(test_key16) > + } > + }, > + .hash_adjust = 12 > + }, > +}; > + > + > +/** > + * Find corresponding config for given name. Returns NULL > + * if config for given name is not found. > + */ > +static cspeed_alg_config_t * > +find_config_by_name(const char *name) { > + unsigned int i; > + cspeed_alg_config_t *ret = NULL; > + > + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { > + if (strcmp(algs_config[i].name, name) == 0) { > + ret = algs_config+i; > + break; > + } > + } > + return ret; > +} > + > + > +/** > + * Helper function that prints list of algorithms that this > + * test understands. > + */ > +static void > +print_config_names(const char *prefix) { > + unsigned int i; > + > + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { > + printf("%s %s\n", prefix, algs_config[i].name); > + } > +} > + > + > +/** > + * Snap current time values and put them into 'rec'. > + */ > +static void > +fill_time_record(time_record_t *rec) > +{ > + gettimeofday(&rec->tv, NULL); > + getrusage(RUSAGE_SELF, &rec->ru_self); > + getrusage(RUSAGE_THREAD, &rec->ru_thread); > +} > + > + > +/** > + * Calculated CPU time difference for given two rusage structures. > + * Note it adds user space and system time together. > + */ > +static unsigned long long > +get_rusage_diff (struct rusage *start, struct rusage *end) > +{ > + unsigned long long rusage_diff; > + unsigned long long rusage_start; > + unsigned long long rusage_end; > + > + rusage_start = (start->ru_utime.tv_sec * 1000000) + > + (start->ru_utime.tv_usec); > + rusage_start += (start->ru_stime.tv_sec * 1000000) + > + (start->ru_stime.tv_usec); > + > + rusage_end = (end->ru_utime.tv_sec * 1000000) + > + (end->ru_utime.tv_usec); > + rusage_end += (end->ru_stime.tv_sec * 1000000) + > + (end->ru_stime.tv_usec); > + > + rusage_diff = rusage_end - rusage_start; > + > + return rusage_diff; > +} > + > + > +/** > + * Get diff for RUSAGE_SELF (whole process) between two time snap > + * records. > + */ > +static unsigned long long > +get_rusage_self_diff (time_record_t *start, time_record_t *end) > +{ > + return get_rusage_diff(&start->ru_self, &end->ru_self); > +} > + > + > +/** > + * Get diff for RUSAGE_THREAD (current thread only) between two > + * time snap records. > + */ > +static unsigned long long > +get_rusage_thread_diff (time_record_t *start, time_record_t *end) > +{ > + return get_rusage_diff(&start->ru_thread, &end->ru_thread); > +} > + > + > +/** > + * Get diff of elapsed time between two time snap records > + */ > +static unsigned long long > +get_elapsed_usec (time_record_t *start, time_record_t *end) > +{ > + unsigned long long s; > + unsigned long long e; > + > + s = (start->tv.tv_sec * 1000000) + > + (start->tv.tv_usec); > + e = (end->tv.tv_sec * 1000000) + > + (end->tv.tv_usec); > + > + return e - s; > +} > + > +#define REPORT_HEADER "\n%30.30s %15s %15s %15s %15s %15s %15s\n" > +#define REPORT_LINE "%30.30s %15d %15d %15.3f %15.3f %15.3f %15d\n" > + > + > +/** > + * Print header line for our report. > + */ > +static void > +print_result_header(void) > +{ > + printf(REPORT_HEADER, > + "algorithm", "avg over #", "payload (bytes)", "elapsed (us)", > + "rusg self (us)", "rusg thrd (us)", "throughput (Kb)"); > +} > + > + > +/** > + * Print one line of our report. > + */ > +static void > +print_result(cspeed_args_t *cargs, > + unsigned int payload_size, > + cspeed_alg_config_t *config, > + cspeed_run_result_t *result) > +{ > + unsigned int throughput; > + throughput = (1000000.0 / result->elapsed) * payload_size / 1024; > + printf(REPORT_LINE, > + config->name, cargs->iteration_count, payload_size, > + result->elapsed, result->rusage_self, result->rusage_thread, > + throughput); > +} > + > + > +/** > + * Print piece of memory with given size. > + */ > +static void > +print_memory (const char *msg, > + const unsigned char *ptr, > + unsigned int len) > +{ > + unsigned i, j; > + char c; > + char line[81]; > + char *p; > + > + if (msg) { > + printf("\n%s (bytes size = %d)", msg, len); > + } > + > + for (i=0; i < len; i+=16) { > + p = line; > + sprintf(p, "\n%04x ", i); p +=8; > + > + for (j = 0; j < 16; j++) { > + if (i+j == len) break; > + > + sprintf(p, " %02x", (ptr)[i+j]); p += 3; > + } > + > + for (; j < 16; j++) { sprintf(p, " "); p += 3; } > + > + sprintf(p, " "); p += 3; > + > + for (j = 0; j < 16; j++) { > + if (i+j == len) break; > + c = (ptr)[i+j]; > + *p++ = (' ' <= c && c <= '~') ? c : '.'; > + } > + > + *p = '\0'; > + printf("%s", line); > + } > + printf("\n"); > +} > + > + > +/** > + * Create ODP crypto session for given config. > + */ > +static int > +create_session_from_config(odp_crypto_session_t *session, > + cspeed_alg_config_t *config) > +{ > + odp_crypto_session_params_t params; > + enum odp_crypto_ses_create_err ses_create_rc; > + odp_buffer_pool_t pkt_pool; > + odp_queue_t out_queue; > + > + int rc = 0; > + > + memcpy(¶ms, &config->session, sizeof(odp_crypto_session_params_t)); > + params.op = ODP_CRYPTO_OP_ENCODE; > + params.pref_mode = ODP_CRYPTO_SYNC; > + > + if (!rc) { > + /* Lookup the packet pool */ > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > + cspeed_error("Error: 'packet_pool' buffer pull not found\n"); > + rc = -1; > + } else { > + params.output_pool = pkt_pool; > + } > + } > + > + > + if (!rc) { > + out_queue = odp_queue_lookup("crypto-out"); > + if (out_queue == ODP_QUEUE_INVALID) { > + cspeed_error("Error: 'crypto-out' queue not found\n"); > + rc = -1; > + } else { > + params.compl_queue = out_queue; > + } > + /* > + * Uncomment below for generic implementation if inline > + * encryption is desired. Note ks2 implementation cannot > + * deal with that. > + */ > + /* params.compl_queue = ODP_QUEUE_INVALID; */ > + } > + > + if (!rc) { > + /* > + * Prefered synchronous session create for now, but it could be > + * ignored by implementation > + */ > + if (odp_crypto_session_create(¶ms, session, > + &ses_create_rc)) { > + cspeed_error("Error: ODP crypto session create failed.\n"); > + rc = -1; > + } > + } > + > + > + return rc; > +} > + > + > +/** > + * Run measurement iterations for given config and payload size. > + * Result of run returned in 'result' out parameter. > + */ > +static int > +run_measure_one(cspeed_args_t *cargs, > + cspeed_alg_config_t *config, > + odp_crypto_session_t *session, > + unsigned int payload_size, > + cspeed_run_result_t *result) > +{ > + odp_crypto_op_params_t params; > + > + odp_buffer_pool_t pkt_pool; > + odp_queue_t out_queue; > + odp_packet_t pkt; > + odp_buffer_t buf; > + > + bool posted = 0; > + int rc = 0; > + > + > + if (!rc) { > + /* Lookup the packet pool */ > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > + cspeed_error("Error: pkt_pool not found\n"); > + rc = -1; > + } > + } > + > + if (!rc) { > + out_queue = odp_queue_lookup("crypto-out"); > + if (out_queue == ODP_QUEUE_INVALID) { > + cspeed_error("Error: 'crypto-out' queue not found\n"); > + rc = -1; > + } > + } > + > + if (!rc) { > + buf = odp_buffer_alloc(pkt_pool); > + if (buf == ODP_BUFFER_INVALID) { > + cspeed_error("Error: failed to allocate buffer\n"); > + rc = -1; > + } else { > + pkt = odp_packet_from_buffer(buf); > + odp_packet_set_len(pkt, payload_size); > + { > + void *mem = odp_packet_start(pkt); > + memset(mem, 1, payload_size); > + } > + } > + } > + > + if (!rc) { > + time_record_t start, end; > + int packets_sent = 0; > + int packets_received = 0; > + > + /* Initialize parameters block */ > + memset(¶ms, 0, sizeof(params)); > + params.session = *session; > + params.cipher_range.offset = 0; > + params.cipher_range.length = payload_size; > + /* > + * Uncomment following line if hash itself have > + * to be encrypted. Note ks2 cannot do that > + */ > + /* params.cipher_range.length += config->hash_adjust; */ > + params.auth_range.offset = 0; > + params.auth_range.length = payload_size; > + params.hash_result_offset = payload_size; > + > + if (cargs->reuse_packet) { > + params.pkt = pkt; > + params.out_pkt = cargs->in_place ? pkt : > + ODP_PACKET_INVALID; > + } > + > + fill_time_record(&start); > + > + while ((packets_sent < cargs->iteration_count) || > + (packets_received < cargs->iteration_count)) { > + void *mem; > + > + if ((packets_sent < cargs->iteration_count) && > + (packets_sent - packets_received < cargs->in_flight)) { > + > + > + if (!cargs->reuse_packet) { > + /* > + * For in place test we use just one statically allocated > + * buffer. For now in place test we have to allocate and > + * initialize packet every time. Note we leaked one > + * packet here. > + */ > + if (!cargs->in_place) { > + buf = odp_buffer_alloc(pkt_pool); > + if (buf == ODP_BUFFER_INVALID) { > + cspeed_error("Error: failed to allocate buffer\n"); > + rc = -1; Value stored to rc never read. > + } else { > + pkt = odp_packet_from_buffer(buf); > + odp_packet_set_len(pkt, payload_size); > + { > + void *mem = > + odp_packet_start(pkt); > + memset(mem, 1, payload_size); > + } > + } > + } > + > + params.pkt = pkt; > + params.out_pkt = cargs->in_place ? pkt : > + ODP_PACKET_INVALID; > + } > + > + > + if (cargs->debug_packets) { > + mem = odp_packet_start(params.pkt); > + print_memory("Packet before encryption:", > + mem, payload_size); > + } > + > + rc = odp_crypto_operation(¶ms, &posted, > + odp_buffer_from_packet(pkt)); > + if (rc) { > + cspeed_error("Error: failed odp_crypto_operation: rc = %d\n", rc); > + } else { > + packets_sent++; > + } > + } > + > + if (!posted) { > + if (cargs->debug_packets) { > + mem = odp_packet_start(params.out_pkt); > + print_memory("Imediately encrypted packet", > + mem, payload_size + config->hash_adjust); > + } > + if (!cargs->in_place) { > + if (cargs->reuse_packet) { > + params.pkt = params.out_pkt; > + params.out_pkt = ODP_PACKET_INVALID; > + } else { > + odp_buffer_free(params.out_pkt); > + } > + } > + } else { > + odp_buffer_t completion; > + odp_packet_t out_pkt; > + > + completion = odp_queue_deq(out_queue); > + > + while (completion != ODP_BUFFER_INVALID) { > + out_pkt = odp_crypto_get_operation_compl_packet(completion); > + > + if (cargs->debug_packets) { > + mem = odp_packet_start(out_pkt); > + print_memory("Receieved encrypted packet", > + mem, payload_size + config->hash_adjust); > + } > + if (!cargs->in_place) { > + if (cargs->reuse_packet) { > + params.pkt = out_pkt; > + params.out_pkt = ODP_PACKET_INVALID; > + } else { > + odp_buffer_free(out_pkt); > + } > + } > + packets_received++; > + > + completion = odp_queue_deq(out_queue); > + }; > + > + } > + } > + > + fill_time_record(&end); > + > + { > + double count; > + > + count = get_elapsed_usec(&start, &end); > + result->elapsed = count / > + cargs->iteration_count; > + > + count = get_rusage_self_diff(&start, &end); > + result->rusage_self = count / > + cargs->iteration_count; > + > + count = get_rusage_thread_diff(&start, &end); > + result->rusage_thread = count / > + cargs->iteration_count; > + } > + } > + return rc; > +} > + > + > +/** > + * Process one algorithm. Note if paload size is specicified it is > + * only one run. Or iterate over set of predefined payloads. > + */ > +static int > +run_measure_one_config(cspeed_args_t *cargs, > + cspeed_alg_config_t *config) > +{ > + cspeed_run_result_t result; > + odp_crypto_session_t session; > + int rc = 0; > + > + if (create_session_from_config(&session, config)) { > + rc = -1; > + } can't we remove the above and say only: int rc = create_session_from_config(&session, config); > + > + if (!rc) { > + if (cargs->payload_size) { > + rc = run_measure_one(cargs, config, &session, > + cargs->payload_size, &result); > + if (!rc){ > + print_result_header(); > + print_result(cargs, cargs->payload_size, > + config, &result); > + } > + } else { > + unsigned int i; > + > + print_result_header(); > + for (i = 0; > + i < sizeof(payloads)/sizeof(unsigned int); > + i++) { > + rc = run_measure_one(cargs, config, &session, > + payloads[i], &result); > + if(rc) { > + break; > + } else { > + print_result(cargs, payloads[i], > + config, &result); > + } > + } > + } > + } > + > + > + // destroy session > + if (session != ODP_CRYPTO_SESSION_INVALID) { > + odp_crypto_session_destroy(session); > + } > + return rc; > +} > + > + > +int main(int argc, char *argv[]) > +{ > + int thr_id; > + cspeed_args_t cargs; > + odp_buffer_pool_t pool; > + odp_queue_t out_queue; > + void *pool_base; > + > + /* Init ODP before calling anything else */ > + if (odp_init_global()) { > + cspeed_error("Error: ODP global init failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + /* Parse and store the application arguments */ > + parse_args(argc, argv, &cargs); > + > + /* Init this thread */ > + thr_id = odp_thread_create(0); > + odp_init_local(thr_id); > + > + /* Create packet pool */ > + pool_base = odp_shm_reserve("shm_packet_pool", > + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); > + if (pool_base == NULL) { > + cspeed_error("Error: packet pool mem alloc failed.\n"); > + exit(EXIT_FAILURE); > + } > + > + pool = odp_buffer_pool_create("packet_pool", pool_base, > + SHM_PKT_POOL_SIZE, > + SHM_PKT_POOL_BUF_SIZE, > + ODP_CACHE_LINE_SIZE, > + ODP_BUFFER_TYPE_PACKET); > + if (pool == ODP_BUFFER_POOL_INVALID) { > + cspeed_error("Error: packet pool create failed.\n"); > + exit(EXIT_FAILURE); > + } > + /* odp_buffer_pool_print(pool); */ > + > + out_queue = odp_queue_create("crypto-out",ODP_QUEUE_TYPE_POLL, NULL); > + if (out_queue == ODP_QUEUE_INVALID) { > + cspeed_error("Can't create out crypto queue\n"); > + exit(EXIT_FAILURE); > + } > + > + if (cargs.alg_config) { > + run_measure_one_config(&cargs, cargs.alg_config); > + } else { > + unsigned int i; > + for (i = 0; > + i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); > + i++) { > + run_measure_one_config(&cargs, algs_config + i); > + } > + } > + > + return 0; > +} > + > + > +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs) > +{ > + int opt; > + int long_index; > + static struct option longopts[] = { > + {"algorithm", optional_argument, NULL, 'a'}, > + {"count", optional_argument, NULL, 'c'}, > + {"debug", no_argument, NULL, 'd'}, > + {"flight", optional_argument, NULL, 'f'}, > + {"help", no_argument, NULL, 'h'}, /* return 'h' */ > + {"iterations", optional_argument, NULL, 'i'}, > + {"inplace", no_argument, NULL, 'n'}, > + {"payload", optional_argument, NULL, 'p'}, > + {"sessions", optional_argument, NULL, 'm'}, > + {"reuse", no_argument, NULL, 'r'}, > + {NULL, 0, NULL, 0} > + }; > + > + cargs->in_place = 0; > + cargs->in_flight = 1; > + cargs->debug_packets = 0; > + cargs->core_count = 1; > + cargs->iteration_count = 10000; > + cargs->payload_size = 0; > + cargs->alg_config = NULL; > + > + while (1) { > + opt = getopt_long(argc, argv, "+a:c:df:hi:m:np:r", > + longopts, &long_index); > + > + if (opt == -1) > + break; /* No more options */ > + > + switch (opt) { > + case 'a': > + cargs->alg_config = find_config_by_name(optarg); > + if (!cargs->alg_config) { > + printf("cannot test crypto '%s' configuration\n", optarg); > + usage(argv[0]); > + exit(-1); > + } > + case 'c': > + cargs->core_count = atoi(optarg); > + break; > + case 'd': > + cargs->debug_packets = 1; > + break; > + case 'i': > + cargs->iteration_count = atoi(optarg); > + break; > + case 'f': > + cargs->in_flight = atoi(optarg); > + break; > + case 'h': > + usage(argv[0]); > + exit(EXIT_SUCCESS); > + break; > + case 'm': > + cargs->max_sessions = atoi(optarg); > + break; > + case 'n': > + cargs->in_place = 1; > + break; > + case 'p': > + cargs->payload_size = atoi(optarg); > + break; > + case 'r': > + cargs->reuse_packet = 1; > + break; > + default: > + break; > + } > + } > + > + optind = 1; /* reset 'extern optind' from the getopt lib */ > + > + if ((cargs->in_flight > 1) && cargs->reuse_packet) { cargs->reuse_packet can be uninitialised when it is evaluated here. Cheers, Anders > + printf("-f (in flight > 1) and -r (reuse packet) options are not compatible\n"); > + usage(argv[0]); > + exit(-1); > + } > + > + if ((cargs->in_flight > 1) && cargs->in_place) { > + printf("-f (in flight > 1) and -n (in place) options are not compatible\n"); > + usage(argv[0]); > + exit(-1); > + } > + > +} > + > + > +/** > + * Prinf usage information > + */ > +static void usage(char *progname) > +{ > + printf("\n" > + "Usage: %s OPTIONS\n" > + " E.g. %s -i 100000\n" > + "\n" > + "OpenDataPlane crypto speed measure.\n" > + "Optional OPTIONS\n" > + " -a, --algorithm <name> Specify algorithm name (default all)\n" > + " Supported values are:\n", > + progname, progname); > + > + print_config_names(" "); > + printf(" -c, --count <number> Core count. (NOT used)\n" > + " -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" > + " -n, --inplace Encrypt on place (ks2 does not support this).\n" > + " -p, --payload Payload size.\n" > + " -r, --reuse Output encrypted packet is passed as input\n" > + " to next encrypt iteration.\n" > + " -h, --help Display help and exit.\n" > + "\n"); > +} > -- > 1.8.1.4 > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > http://lists.linaro.org/mailman/listinfo/lng-odp
On 2014-09-11 12:52, Anders Roxell wrote: > On 2014-09-10 18:10, Victor Kamensky wrote: > > Sample test code that measures speed of ODP crypto operations. > > o measures operation elapsed, cpu time, and throughput > > o supports multiple algorithms > > o supports multiple payload sizes > > o support synch and async crypto operation modes > > > > Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org> > > --- > > configure.ac | 1 + > > example/Makefile.am | 2 +- > > example/cspeed/Makefile.am | 6 + > > example/cspeed/odp_cspeed.c | 918 ++++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 926 insertions(+), 1 deletion(-) > > create mode 100644 example/cspeed/Makefile.am > > create mode 100644 example/cspeed/odp_cspeed.c > > > > diff --git a/configure.ac b/configure.ac > > index b1fc859..0592334 100644 > > --- a/configure.ac > > +++ b/configure.ac > > @@ -153,6 +153,7 @@ AC_CONFIG_FILES([Makefile > > platform/linux-keystone2/Makefile > > platform/linux-dpdk/Makefile > > example/Makefile > > + example/cspeed/Makefile > > example/generator/Makefile > > example/l2fwd/Makefile > > example/odp_example/Makefile > > diff --git a/example/Makefile.am b/example/Makefile.am > > index 01a3305..d7fb80a 100644 > > --- a/example/Makefile.am > > +++ b/example/Makefile.am > > @@ -1 +1 @@ > > -SUBDIRS = generator l2fwd odp_example packet packet_netmap timer > > +SUBDIRS = cspeed generator l2fwd odp_example packet packet_netmap timer > > diff --git a/example/cspeed/Makefile.am b/example/cspeed/Makefile.am > > new file mode 100644 > > index 0000000..9b0b2ee > > --- /dev/null > > +++ b/example/cspeed/Makefile.am > > @@ -0,0 +1,6 @@ > > +include $(top_srcdir)/example/Makefile.inc > > + > > +bin_PROGRAMS = odp_cspeed > > +odp_cspeed_LDFLAGS = $(AM_LDFLAGS) -static > > + > > +dist_odp_cspeed_SOURCES = odp_cspeed.c > > diff --git a/example/cspeed/odp_cspeed.c b/example/cspeed/odp_cspeed.c > > new file mode 100644 > > index 0000000..8e59180 > > --- /dev/null > > +++ b/example/cspeed/odp_cspeed.c > > @@ -0,0 +1,918 @@ > > +/* Copyright (c) 2014, Linaro Limited > > + * All rights reserved. > > + * > > + * SPDX-License-Identifier: BSD-3-Clause > > + */ > > + > > +#ifndef _GNU_SOURCE > > +#define _GNU_SOURCE > > +#endif /* _GNU_SOURCE */ > > + > > +#include <stdlib.h> > > +#include <string.h> > > +#include <getopt.h> > > +#include <unistd.h> > > +#include <sys/time.h> > > +#include <sys/resource.h> > > + > > +#include <odp.h> > > + > > + > > +#define cspeed_error(fmt, ...) \ > > + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \ > > + __LINE__, __func__, ##__VA_ARGS__) > > + > > + > > +/** @def SHM_PKT_POOL_SIZE > > + * @brief Size of the shared memory block > > + */ > > +#define SHM_PKT_POOL_SIZE (512*2048*2) > > + > > + > > +/** @def SHM_PKT_POOL_BUF_SIZE > > + * @brief Buffer size of the packet pool buffer > > + */ > > +#define SHM_PKT_POOL_BUF_SIZE (1024 * 32) > > + > > + > > +static uint8_t test_iv[8] = "01234567"; > > + > > + > > +static uint8_t test_key16[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, > > + 0x06, 0x07, 0x08, 0x09, 0x0a, > > + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, > > + 0x10, > > +}; > > + > > + > > +static uint8_t test_key24[24] = { 0x01, 0x02, 0x03, 0x04, 0x05, > > + 0x06, 0x07, 0x08, 0x09, 0x0a, > > + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, > > + 0x10, 0x11, 0x12, 0x13, 0x14, > > + 0x15, 0x16, 0x17, 0x18 > > +}; > > + > > +/** > > + * Structure that holds template for session create call > > + * for different algorithms supported by test > > + */ > > +typedef struct { > > + const char *name; /**< Algorithm name */ > > + odp_crypto_session_params_t session; /**< Prefilled crypto session params */ > > + unsigned int hash_adjust; /**< Size of hash */ > > +} cspeed_alg_config_t; > > + > > + > > +/** > > + * Parsed command line cspeed arguments. Describes test configuration. > > + */ > > +typedef struct { > > + /** > > + * If non zero prints content of packets. Enabled by -d or > > + * --debug option. > > + */ > > + int debug_packets; > > + > > + /** > > + * If non zero Try to run crypto operation in place. Note some > > + * implementation may not support such mode. Enabled by -n or > > + * --inplace option. > > + */ > > + int in_place; > > + > > + /** > > + * If non zeor output of previous operation taken as input for > > + * next encrypt operations. Enabled by -r or --reuse option. > > + */ > > + int reuse_packet; > > + > > + /** > > + * Maxiumum number of outstanding encryption requests. Note code > > + * poll for results over queue and if nothing is available it can > > + * submit more encryption requests up to maximum number specified by > > + * this option. Specified through -f or --flight option. > > + */ > > + int in_flight; > > + > > + /** > > + * Number of core to run on. Currently is not used. > > + */ > > + int core_count; > > + > > + /** > > + * Number of iteration to repeat crypto operation to get good > > + * average number. Specified through -i or --terations option. > > + * Default is 10000. > > + */ > > + int iteration_count; > > + > > + /** > > + * Maxium sessions. Currently is not used. > > + */ > > + int max_sessions; > > + > > + /** > > + * Payload size to test. If 0 set of predefined payload sizes > > + * is tested. Specified through -p or --payload option. > > + */ > > + int payload_size; > > + > > + /** > > + * Pointer to selected algorithm to test. If NULL all available > > + * alogorthims are tested. Name of algorithm is passed through > > + * -a or --algorithm option. > > + */ > > + cspeed_alg_config_t *alg_config; > > +} cspeed_args_t; > > + > > + > > +/* > > + * Helper structure that holds averages for test of one algorithm > > + * for given payload size. > > + */ > > +typedef struct { > > + /** > > + * Elapsed time for one crypto operation. > > + */ > > + double elapsed; > > + > > + /** > > + * CPU time spent pre one crypto operation by whole process > > + * i.e include current and all other threads in process. > > + * It is filled with 'getrusage(RUSAGE_SELF, ...)' call. > > + */ > > + double rusage_self; > > + > > + /** > > + * CPU time spent per one crypto operation by current thread > > + * only. It is filled with 'getrusage(RUSAGE_THREAD, ...)' > > + * call. > > + */ > > + double rusage_thread; > > +} cspeed_run_result_t; > > + > > + > > +/** > > + * Structure holds one snap to misc times of current process. > > + */ > > +typedef struct { > > + struct timeval tv; /**< Elapsed time */ > > + struct rusage ru_self; /**< Rusage value for whole process */ > > + struct rusage ru_thread; /**< Rusage value for current thread */ > > +} time_record_t; > > + > > + > > +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs); > > +static void usage(char *progname); > > + > > +/** > > + * Set of predefined payloads. Make sure that maximum payload > > + * size is not bigger than SHM_PKT_POOL_BUF_SIZE. May relax when > > + * implementation start support segmented buffers/packets. > > + */ > > +static unsigned int payloads[] = { > > + 16, > > + 64, > > + 256, > > + 1024, > > + 8192, > > + 16384 > > +}; > > + > > +/** > > + * Set of known algorithms to test > > + */ > > +static cspeed_alg_config_t algs_config[] = { > > + { > > + .name = "3des-cbs-null", > > + .session = { > > + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, > > + .cipher_key = { > > + .data = test_key24, > > + .length = sizeof(test_key24) > > + }, > > + .iv = { > > + .data = test_iv, > > + .length = 8, > > + }, > > + .auth_alg = ODP_AUTH_ALG_NULL > > + }, > > + }, > > + { > > + .name = "3des-cbs-hmac-md5-96", > > + .session = { > > + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, > > + .cipher_key = { > > + .data = test_key24, > > + .length = sizeof(test_key24) > > + }, > > + .iv = { > > + .data = test_iv, > > + .length = 8, > > + }, > > + .auth_alg = ODP_AUTH_ALG_MD5_96, > > + .auth_key = { > > + .data = test_key16, > > + .length = sizeof(test_key16) > > + } > > + }, > > + .hash_adjust = 12 > > + }, > > + { > > + .name ="null-hmac-md5-96", > > + .session = { > > + .cipher_alg = ODP_CIPHER_ALG_NULL, > > + .auth_alg = ODP_AUTH_ALG_MD5_96, > > + .auth_key = { > > + .data = test_key16, > > + .length = sizeof(test_key16) > > + } > > + }, > > + .hash_adjust = 12 > > + }, > > +}; > > + > > + > > +/** > > + * Find corresponding config for given name. Returns NULL > > + * if config for given name is not found. > > + */ > > +static cspeed_alg_config_t * > > +find_config_by_name(const char *name) { > > + unsigned int i; > > + cspeed_alg_config_t *ret = NULL; > > + > > + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { > > + if (strcmp(algs_config[i].name, name) == 0) { > > + ret = algs_config+i; > > + break; > > + } > > + } > > + return ret; > > +} > > + > > + > > +/** > > + * Helper function that prints list of algorithms that this > > + * test understands. > > + */ > > +static void > > +print_config_names(const char *prefix) { > > + unsigned int i; > > + > > + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { > > + printf("%s %s\n", prefix, algs_config[i].name); > > + } > > +} > > + > > + > > +/** > > + * Snap current time values and put them into 'rec'. > > + */ > > +static void > > +fill_time_record(time_record_t *rec) > > +{ > > + gettimeofday(&rec->tv, NULL); > > + getrusage(RUSAGE_SELF, &rec->ru_self); > > + getrusage(RUSAGE_THREAD, &rec->ru_thread); > > +} > > + > > + > > +/** > > + * Calculated CPU time difference for given two rusage structures. > > + * Note it adds user space and system time together. > > + */ > > +static unsigned long long > > +get_rusage_diff (struct rusage *start, struct rusage *end) > > +{ > > + unsigned long long rusage_diff; > > + unsigned long long rusage_start; > > + unsigned long long rusage_end; > > + > > + rusage_start = (start->ru_utime.tv_sec * 1000000) + > > + (start->ru_utime.tv_usec); > > + rusage_start += (start->ru_stime.tv_sec * 1000000) + > > + (start->ru_stime.tv_usec); > > + > > + rusage_end = (end->ru_utime.tv_sec * 1000000) + > > + (end->ru_utime.tv_usec); > > + rusage_end += (end->ru_stime.tv_sec * 1000000) + > > + (end->ru_stime.tv_usec); > > + > > + rusage_diff = rusage_end - rusage_start; > > + > > + return rusage_diff; > > +} > > + > > + > > +/** > > + * Get diff for RUSAGE_SELF (whole process) between two time snap > > + * records. > > + */ > > +static unsigned long long > > +get_rusage_self_diff (time_record_t *start, time_record_t *end) > > +{ > > + return get_rusage_diff(&start->ru_self, &end->ru_self); > > +} > > + > > + > > +/** > > + * Get diff for RUSAGE_THREAD (current thread only) between two > > + * time snap records. > > + */ > > +static unsigned long long > > +get_rusage_thread_diff (time_record_t *start, time_record_t *end) > > +{ > > + return get_rusage_diff(&start->ru_thread, &end->ru_thread); > > +} > > + > > + > > +/** > > + * Get diff of elapsed time between two time snap records > > + */ > > +static unsigned long long > > +get_elapsed_usec (time_record_t *start, time_record_t *end) > > +{ > > + unsigned long long s; > > + unsigned long long e; > > + > > + s = (start->tv.tv_sec * 1000000) + > > + (start->tv.tv_usec); > > + e = (end->tv.tv_sec * 1000000) + > > + (end->tv.tv_usec); > > + > > + return e - s; > > +} > > + > > +#define REPORT_HEADER "\n%30.30s %15s %15s %15s %15s %15s %15s\n" > > +#define REPORT_LINE "%30.30s %15d %15d %15.3f %15.3f %15.3f %15d\n" > > + > > + > > +/** > > + * Print header line for our report. > > + */ > > +static void > > +print_result_header(void) > > +{ > > + printf(REPORT_HEADER, > > + "algorithm", "avg over #", "payload (bytes)", "elapsed (us)", > > + "rusg self (us)", "rusg thrd (us)", "throughput (Kb)"); > > +} > > + > > + > > +/** > > + * Print one line of our report. > > + */ > > +static void > > +print_result(cspeed_args_t *cargs, > > + unsigned int payload_size, > > + cspeed_alg_config_t *config, > > + cspeed_run_result_t *result) > > +{ > > + unsigned int throughput; > > + throughput = (1000000.0 / result->elapsed) * payload_size / 1024; > > + printf(REPORT_LINE, > > + config->name, cargs->iteration_count, payload_size, > > + result->elapsed, result->rusage_self, result->rusage_thread, > > + throughput); > > +} > > + > > + > > +/** > > + * Print piece of memory with given size. > > + */ > > +static void > > +print_memory (const char *msg, > > + const unsigned char *ptr, > > + unsigned int len) > > +{ > > + unsigned i, j; > > + char c; > > + char line[81]; > > + char *p; > > + > > + if (msg) { > > + printf("\n%s (bytes size = %d)", msg, len); > > + } > > + > > + for (i=0; i < len; i+=16) { > > + p = line; > > + sprintf(p, "\n%04x ", i); p +=8; > > + > > + for (j = 0; j < 16; j++) { > > + if (i+j == len) break; > > + > > + sprintf(p, " %02x", (ptr)[i+j]); p += 3; > > + } > > + > > + for (; j < 16; j++) { sprintf(p, " "); p += 3; } > > + > > + sprintf(p, " "); p += 3; > > + > > + for (j = 0; j < 16; j++) { > > + if (i+j == len) break; > > + c = (ptr)[i+j]; > > + *p++ = (' ' <= c && c <= '~') ? c : '.'; > > + } > > + > > + *p = '\0'; > > + printf("%s", line); > > + } > > + printf("\n"); > > +} > > + > > + > > +/** > > + * Create ODP crypto session for given config. > > + */ > > +static int > > +create_session_from_config(odp_crypto_session_t *session, > > + cspeed_alg_config_t *config) > > +{ > > + odp_crypto_session_params_t params; > > + enum odp_crypto_ses_create_err ses_create_rc; > > + odp_buffer_pool_t pkt_pool; > > + odp_queue_t out_queue; > > + > > + int rc = 0; > > + > > + memcpy(¶ms, &config->session, sizeof(odp_crypto_session_params_t)); > > + params.op = ODP_CRYPTO_OP_ENCODE; > > + params.pref_mode = ODP_CRYPTO_SYNC; > > + > > + if (!rc) { > > + /* Lookup the packet pool */ > > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > > + cspeed_error("Error: 'packet_pool' buffer pull not found\n"); > > + rc = -1; > > + } else { > > + params.output_pool = pkt_pool; > > + } > > + } > > + > > + > > + if (!rc) { > > + out_queue = odp_queue_lookup("crypto-out"); > > + if (out_queue == ODP_QUEUE_INVALID) { > > + cspeed_error("Error: 'crypto-out' queue not found\n"); > > + rc = -1; > > + } else { > > + params.compl_queue = out_queue; > > + } > > + /* > > + * Uncomment below for generic implementation if inline > > + * encryption is desired. Note ks2 implementation cannot > > + * deal with that. > > + */ > > + /* params.compl_queue = ODP_QUEUE_INVALID; */ > > + } > > + > > + if (!rc) { > > + /* > > + * Prefered synchronous session create for now, but it could be > > + * ignored by implementation > > + */ > > + if (odp_crypto_session_create(¶ms, session, > > + &ses_create_rc)) { > > + cspeed_error("Error: ODP crypto session create failed.\n"); > > + rc = -1; > > + } > > + } > > + > > + > > + return rc; > > +} > > + > > + > > +/** > > + * Run measurement iterations for given config and payload size. > > + * Result of run returned in 'result' out parameter. > > + */ > > +static int > > +run_measure_one(cspeed_args_t *cargs, > > + cspeed_alg_config_t *config, > > + odp_crypto_session_t *session, > > + unsigned int payload_size, > > + cspeed_run_result_t *result) > > +{ > > + odp_crypto_op_params_t params; > > + > > + odp_buffer_pool_t pkt_pool; > > + odp_queue_t out_queue; > > + odp_packet_t pkt; > > + odp_buffer_t buf; > > + > > + bool posted = 0; > > + int rc = 0; > > + > > + > > + if (!rc) { > > + /* Lookup the packet pool */ > > + pkt_pool = odp_buffer_pool_lookup("packet_pool"); > > + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { > > + cspeed_error("Error: pkt_pool not found\n"); > > + rc = -1; > > + } > > + } > > + > > + if (!rc) { > > + out_queue = odp_queue_lookup("crypto-out"); > > + if (out_queue == ODP_QUEUE_INVALID) { > > + cspeed_error("Error: 'crypto-out' queue not found\n"); > > + rc = -1; > > + } > > + } > > + > > + if (!rc) { > > + buf = odp_buffer_alloc(pkt_pool); > > + if (buf == ODP_BUFFER_INVALID) { > > + cspeed_error("Error: failed to allocate buffer\n"); > > + rc = -1; > > + } else { > > + pkt = odp_packet_from_buffer(buf); > > + odp_packet_set_len(pkt, payload_size); > > + { > > + void *mem = odp_packet_start(pkt); > > + memset(mem, 1, payload_size); > > + } > > + } > > + } > > + > > + if (!rc) { > > + time_record_t start, end; > > + int packets_sent = 0; > > + int packets_received = 0; > > + > > + /* Initialize parameters block */ > > + memset(¶ms, 0, sizeof(params)); > > + params.session = *session; > > + params.cipher_range.offset = 0; > > + params.cipher_range.length = payload_size; > > + /* > > + * Uncomment following line if hash itself have > > + * to be encrypted. Note ks2 cannot do that > > + */ > > + /* params.cipher_range.length += config->hash_adjust; */ > > + params.auth_range.offset = 0; > > + params.auth_range.length = payload_size; > > + params.hash_result_offset = payload_size; > > + > > + if (cargs->reuse_packet) { > > + params.pkt = pkt; > > + params.out_pkt = cargs->in_place ? pkt : > > + ODP_PACKET_INVALID; > > + } > > + > > + fill_time_record(&start); > > + > > + while ((packets_sent < cargs->iteration_count) || > > + (packets_received < cargs->iteration_count)) { > > + void *mem; > > + > > + if ((packets_sent < cargs->iteration_count) && > > + (packets_sent - packets_received < cargs->in_flight)) { > > + > > + > > + if (!cargs->reuse_packet) { > > + /* > > + * For in place test we use just one statically allocated > > + * buffer. For now in place test we have to allocate and > > + * initialize packet every time. Note we leaked one > > + * packet here. > > + */ > > + if (!cargs->in_place) { > > + buf = odp_buffer_alloc(pkt_pool); > > + if (buf == ODP_BUFFER_INVALID) { > > + cspeed_error("Error: failed to allocate buffer\n"); > > + rc = -1; > > Value stored to rc never read. > > > + } else { > > + pkt = odp_packet_from_buffer(buf); > > + odp_packet_set_len(pkt, payload_size); > > + { > > + void *mem = > > + odp_packet_start(pkt); > > + memset(mem, 1, payload_size); > > + } > > + } > > + } > > + > > + params.pkt = pkt; > > + params.out_pkt = cargs->in_place ? pkt : > > + ODP_PACKET_INVALID; > > + } > > + > > + > > + if (cargs->debug_packets) { > > + mem = odp_packet_start(params.pkt); > > + print_memory("Packet before encryption:", > > + mem, payload_size); > > + } > > + > > + rc = odp_crypto_operation(¶ms, &posted, > > + odp_buffer_from_packet(pkt)); > > + if (rc) { > > + cspeed_error("Error: failed odp_crypto_operation: rc = %d\n", rc); > > + } else { > > + packets_sent++; > > + } > > + } > > + > > + if (!posted) { > > + if (cargs->debug_packets) { > > + mem = odp_packet_start(params.out_pkt); > > + print_memory("Imediately encrypted packet", > > + mem, payload_size + config->hash_adjust); > > + } > > + if (!cargs->in_place) { > > + if (cargs->reuse_packet) { > > + params.pkt = params.out_pkt; > > + params.out_pkt = ODP_PACKET_INVALID; > > + } else { > > + odp_buffer_free(params.out_pkt); > > + } > > + } > > + } else { > > + odp_buffer_t completion; > > + odp_packet_t out_pkt; > > + > > + completion = odp_queue_deq(out_queue); > > + > > + while (completion != ODP_BUFFER_INVALID) { > > + out_pkt = odp_crypto_get_operation_compl_packet(completion); > > + > > + if (cargs->debug_packets) { > > + mem = odp_packet_start(out_pkt); > > + print_memory("Receieved encrypted packet", > > + mem, payload_size + config->hash_adjust); > > + } > > + if (!cargs->in_place) { > > + if (cargs->reuse_packet) { > > + params.pkt = out_pkt; > > + params.out_pkt = ODP_PACKET_INVALID; > > + } else { > > + odp_buffer_free(out_pkt); > > + } > > + } > > + packets_received++; > > + > > + completion = odp_queue_deq(out_queue); > > + }; > > + > > + } > > + } > > + > > + fill_time_record(&end); > > + > > + { > > + double count; > > + > > + count = get_elapsed_usec(&start, &end); > > + result->elapsed = count / > > + cargs->iteration_count; > > + > > + count = get_rusage_self_diff(&start, &end); > > + result->rusage_self = count / > > + cargs->iteration_count; > > + > > + count = get_rusage_thread_diff(&start, &end); > > + result->rusage_thread = count / > > + cargs->iteration_count; > > + } > > + } > > + return rc; > > +} > > + > > + > > +/** > > + * Process one algorithm. Note if paload size is specicified it is > > + * only one run. Or iterate over set of predefined payloads. > > + */ > > +static int > > +run_measure_one_config(cspeed_args_t *cargs, > > + cspeed_alg_config_t *config) > > +{ > > + cspeed_run_result_t result; > > + odp_crypto_session_t session; > > + int rc = 0; > > + > > + if (create_session_from_config(&session, config)) { > > + rc = -1; > > + } > > can't we remove the above and say only: > > int rc = create_session_from_config(&session, config); > > > + > > + if (!rc) { > > + if (cargs->payload_size) { > > + rc = run_measure_one(cargs, config, &session, > > + cargs->payload_size, &result); > > + if (!rc){ > > + print_result_header(); > > + print_result(cargs, cargs->payload_size, > > + config, &result); > > + } > > + } else { > > + unsigned int i; > > + > > + print_result_header(); > > + for (i = 0; > > + i < sizeof(payloads)/sizeof(unsigned int); > > + i++) { > > + rc = run_measure_one(cargs, config, &session, > > + payloads[i], &result); > > + if(rc) { > > + break; > > + } else { > > + print_result(cargs, payloads[i], > > + config, &result); > > + } > > + } > > + } > > + } > > + > > + > > + // destroy session > > + if (session != ODP_CRYPTO_SESSION_INVALID) { I forgot to ask about this, session can be uninitialised when we compare compare if session != ODP_CRYPTO_SESSION_INVALID I think right? Cheers, Anders > > + odp_crypto_session_destroy(session); > > + } > > + return rc; > > +} > > + > > + > > +int main(int argc, char *argv[]) > > +{ > > + int thr_id; > > + cspeed_args_t cargs; > > + odp_buffer_pool_t pool; > > + odp_queue_t out_queue; > > + void *pool_base; > > + > > + /* Init ODP before calling anything else */ > > + if (odp_init_global()) { > > + cspeed_error("Error: ODP global init failed.\n"); > > + exit(EXIT_FAILURE); > > + } > > + > > + /* Parse and store the application arguments */ > > + parse_args(argc, argv, &cargs); > > + > > + /* Init this thread */ > > + thr_id = odp_thread_create(0); > > + odp_init_local(thr_id); > > + > > + /* Create packet pool */ > > + pool_base = odp_shm_reserve("shm_packet_pool", > > + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); > > + if (pool_base == NULL) { > > + cspeed_error("Error: packet pool mem alloc failed.\n"); > > + exit(EXIT_FAILURE); > > + } > > + > > + pool = odp_buffer_pool_create("packet_pool", pool_base, > > + SHM_PKT_POOL_SIZE, > > + SHM_PKT_POOL_BUF_SIZE, > > + ODP_CACHE_LINE_SIZE, > > + ODP_BUFFER_TYPE_PACKET); > > + if (pool == ODP_BUFFER_POOL_INVALID) { > > + cspeed_error("Error: packet pool create failed.\n"); > > + exit(EXIT_FAILURE); > > + } > > + /* odp_buffer_pool_print(pool); */ > > + > > + out_queue = odp_queue_create("crypto-out",ODP_QUEUE_TYPE_POLL, NULL); > > + if (out_queue == ODP_QUEUE_INVALID) { > > + cspeed_error("Can't create out crypto queue\n"); > > + exit(EXIT_FAILURE); > > + } > > + > > + if (cargs.alg_config) { > > + run_measure_one_config(&cargs, cargs.alg_config); > > + } else { > > + unsigned int i; > > + for (i = 0; > > + i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); > > + i++) { > > + run_measure_one_config(&cargs, algs_config + i); > > + } > > + } > > + > > + return 0; > > +} > > + > > + > > +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs) > > +{ > > + int opt; > > + int long_index; > > + static struct option longopts[] = { > > + {"algorithm", optional_argument, NULL, 'a'}, > > + {"count", optional_argument, NULL, 'c'}, > > + {"debug", no_argument, NULL, 'd'}, > > + {"flight", optional_argument, NULL, 'f'}, > > + {"help", no_argument, NULL, 'h'}, /* return 'h' */ > > + {"iterations", optional_argument, NULL, 'i'}, > > + {"inplace", no_argument, NULL, 'n'}, > > + {"payload", optional_argument, NULL, 'p'}, > > + {"sessions", optional_argument, NULL, 'm'}, > > + {"reuse", no_argument, NULL, 'r'}, > > + {NULL, 0, NULL, 0} > > + }; > > + > > + cargs->in_place = 0; > > + cargs->in_flight = 1; > > + cargs->debug_packets = 0; > > + cargs->core_count = 1; > > + cargs->iteration_count = 10000; > > + cargs->payload_size = 0; > > + cargs->alg_config = NULL; > > + > > + while (1) { > > + opt = getopt_long(argc, argv, "+a:c:df:hi:m:np:r", > > + longopts, &long_index); > > + > > + if (opt == -1) > > + break; /* No more options */ > > + > > + switch (opt) { > > + case 'a': > > + cargs->alg_config = find_config_by_name(optarg); > > + if (!cargs->alg_config) { > > + printf("cannot test crypto '%s' configuration\n", optarg); > > + usage(argv[0]); > > + exit(-1); > > + } > > + case 'c': > > + cargs->core_count = atoi(optarg); > > + break; > > + case 'd': > > + cargs->debug_packets = 1; > > + break; > > + case 'i': > > + cargs->iteration_count = atoi(optarg); > > + break; > > + case 'f': > > + cargs->in_flight = atoi(optarg); > > + break; > > + case 'h': > > + usage(argv[0]); > > + exit(EXIT_SUCCESS); > > + break; > > + case 'm': > > + cargs->max_sessions = atoi(optarg); > > + break; > > + case 'n': > > + cargs->in_place = 1; > > + break; > > + case 'p': > > + cargs->payload_size = atoi(optarg); > > + break; > > + case 'r': > > + cargs->reuse_packet = 1; > > + break; > > + default: > > + break; > > + } > > + } > > + > > + optind = 1; /* reset 'extern optind' from the getopt lib */ > > + > > + if ((cargs->in_flight > 1) && cargs->reuse_packet) { > > cargs->reuse_packet can be uninitialised when it is evaluated here. > > > Cheers, > Anders > > > + printf("-f (in flight > 1) and -r (reuse packet) options are not compatible\n"); > > + usage(argv[0]); > > + exit(-1); > > + } > > + > > + if ((cargs->in_flight > 1) && cargs->in_place) { > > + printf("-f (in flight > 1) and -n (in place) options are not compatible\n"); > > + usage(argv[0]); > > + exit(-1); > > + } > > + > > +} > > + > > + > > +/** > > + * Prinf usage information > > + */ > > +static void usage(char *progname) > > +{ > > + printf("\n" > > + "Usage: %s OPTIONS\n" > > + " E.g. %s -i 100000\n" > > + "\n" > > + "OpenDataPlane crypto speed measure.\n" > > + "Optional OPTIONS\n" > > + " -a, --algorithm <name> Specify algorithm name (default all)\n" > > + " Supported values are:\n", > > + progname, progname); > > + > > + print_config_names(" "); > > + printf(" -c, --count <number> Core count. (NOT used)\n" > > + " -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" > > + " -n, --inplace Encrypt on place (ks2 does not support this).\n" > > + " -p, --payload Payload size.\n" > > + " -r, --reuse Output encrypted packet is passed as input\n" > > + " to next encrypt iteration.\n" > > + " -h, --help Display help and exit.\n" > > + "\n"); > > +} > > -- > > 1.8.1.4 > > > > > > _______________________________________________ > > lng-odp mailing list > > lng-odp@lists.linaro.org > > http://lists.linaro.org/mailman/listinfo/lng-odp
diff --git a/configure.ac b/configure.ac index b1fc859..0592334 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,7 @@ AC_CONFIG_FILES([Makefile platform/linux-keystone2/Makefile platform/linux-dpdk/Makefile example/Makefile + example/cspeed/Makefile example/generator/Makefile example/l2fwd/Makefile example/odp_example/Makefile diff --git a/example/Makefile.am b/example/Makefile.am index 01a3305..d7fb80a 100644 --- a/example/Makefile.am +++ b/example/Makefile.am @@ -1 +1 @@ -SUBDIRS = generator l2fwd odp_example packet packet_netmap timer +SUBDIRS = cspeed generator l2fwd odp_example packet packet_netmap timer diff --git a/example/cspeed/Makefile.am b/example/cspeed/Makefile.am new file mode 100644 index 0000000..9b0b2ee --- /dev/null +++ b/example/cspeed/Makefile.am @@ -0,0 +1,6 @@ +include $(top_srcdir)/example/Makefile.inc + +bin_PROGRAMS = odp_cspeed +odp_cspeed_LDFLAGS = $(AM_LDFLAGS) -static + +dist_odp_cspeed_SOURCES = odp_cspeed.c diff --git a/example/cspeed/odp_cspeed.c b/example/cspeed/odp_cspeed.c new file mode 100644 index 0000000..8e59180 --- /dev/null +++ b/example/cspeed/odp_cspeed.c @@ -0,0 +1,918 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif /* _GNU_SOURCE */ + +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <odp.h> + + +#define cspeed_error(fmt, ...) \ + fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, \ + __LINE__, __func__, ##__VA_ARGS__) + + +/** @def SHM_PKT_POOL_SIZE + * @brief Size of the shared memory block + */ +#define SHM_PKT_POOL_SIZE (512*2048*2) + + +/** @def SHM_PKT_POOL_BUF_SIZE + * @brief Buffer size of the packet pool buffer + */ +#define SHM_PKT_POOL_BUF_SIZE (1024 * 32) + + +static uint8_t test_iv[8] = "01234567"; + + +static uint8_t test_key16[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, +}; + + +static uint8_t test_key24[24] = { 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18 +}; + +/** + * Structure that holds template for session create call + * for different algorithms supported by test + */ +typedef struct { + const char *name; /**< Algorithm name */ + odp_crypto_session_params_t session; /**< Prefilled crypto session params */ + unsigned int hash_adjust; /**< Size of hash */ +} cspeed_alg_config_t; + + +/** + * Parsed command line cspeed arguments. Describes test configuration. + */ +typedef struct { + /** + * If non zero prints content of packets. Enabled by -d or + * --debug option. + */ + int debug_packets; + + /** + * If non zero Try to run crypto operation in place. Note some + * implementation may not support such mode. Enabled by -n or + * --inplace option. + */ + int in_place; + + /** + * If non zeor output of previous operation taken as input for + * next encrypt operations. Enabled by -r or --reuse option. + */ + int reuse_packet; + + /** + * Maxiumum number of outstanding encryption requests. Note code + * poll for results over queue and if nothing is available it can + * submit more encryption requests up to maximum number specified by + * this option. Specified through -f or --flight option. + */ + int in_flight; + + /** + * Number of core to run on. Currently is not used. + */ + int core_count; + + /** + * Number of iteration to repeat crypto operation to get good + * average number. Specified through -i or --terations option. + * Default is 10000. + */ + int iteration_count; + + /** + * Maxium sessions. Currently is not used. + */ + int max_sessions; + + /** + * Payload size to test. If 0 set of predefined payload sizes + * is tested. Specified through -p or --payload option. + */ + int payload_size; + + /** + * Pointer to selected algorithm to test. If NULL all available + * alogorthims are tested. Name of algorithm is passed through + * -a or --algorithm option. + */ + cspeed_alg_config_t *alg_config; +} cspeed_args_t; + + +/* + * Helper structure that holds averages for test of one algorithm + * for given payload size. + */ +typedef struct { + /** + * Elapsed time for one crypto operation. + */ + double elapsed; + + /** + * CPU time spent pre one crypto operation by whole process + * i.e include current and all other threads in process. + * It is filled with 'getrusage(RUSAGE_SELF, ...)' call. + */ + double rusage_self; + + /** + * CPU time spent per one crypto operation by current thread + * only. It is filled with 'getrusage(RUSAGE_THREAD, ...)' + * call. + */ + double rusage_thread; +} cspeed_run_result_t; + + +/** + * Structure holds one snap to misc times of current process. + */ +typedef struct { + struct timeval tv; /**< Elapsed time */ + struct rusage ru_self; /**< Rusage value for whole process */ + struct rusage ru_thread; /**< Rusage value for current thread */ +} time_record_t; + + +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs); +static void usage(char *progname); + +/** + * Set of predefined payloads. Make sure that maximum payload + * size is not bigger than SHM_PKT_POOL_BUF_SIZE. May relax when + * implementation start support segmented buffers/packets. + */ +static unsigned int payloads[] = { + 16, + 64, + 256, + 1024, + 8192, + 16384 +}; + +/** + * Set of known algorithms to test + */ +static cspeed_alg_config_t algs_config[] = { + { + .name = "3des-cbs-null", + .session = { + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, + .cipher_key = { + .data = test_key24, + .length = sizeof(test_key24) + }, + .iv = { + .data = test_iv, + .length = 8, + }, + .auth_alg = ODP_AUTH_ALG_NULL + }, + }, + { + .name = "3des-cbs-hmac-md5-96", + .session = { + .cipher_alg = ODP_CIPHER_ALG_3DES_CBC, + .cipher_key = { + .data = test_key24, + .length = sizeof(test_key24) + }, + .iv = { + .data = test_iv, + .length = 8, + }, + .auth_alg = ODP_AUTH_ALG_MD5_96, + .auth_key = { + .data = test_key16, + .length = sizeof(test_key16) + } + }, + .hash_adjust = 12 + }, + { + .name ="null-hmac-md5-96", + .session = { + .cipher_alg = ODP_CIPHER_ALG_NULL, + .auth_alg = ODP_AUTH_ALG_MD5_96, + .auth_key = { + .data = test_key16, + .length = sizeof(test_key16) + } + }, + .hash_adjust = 12 + }, +}; + + +/** + * Find corresponding config for given name. Returns NULL + * if config for given name is not found. + */ +static cspeed_alg_config_t * +find_config_by_name(const char *name) { + unsigned int i; + cspeed_alg_config_t *ret = NULL; + + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { + if (strcmp(algs_config[i].name, name) == 0) { + ret = algs_config+i; + break; + } + } + return ret; +} + + +/** + * Helper function that prints list of algorithms that this + * test understands. + */ +static void +print_config_names(const char *prefix) { + unsigned int i; + + for (i = 0; i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); i++) { + printf("%s %s\n", prefix, algs_config[i].name); + } +} + + +/** + * Snap current time values and put them into 'rec'. + */ +static void +fill_time_record(time_record_t *rec) +{ + gettimeofday(&rec->tv, NULL); + getrusage(RUSAGE_SELF, &rec->ru_self); + getrusage(RUSAGE_THREAD, &rec->ru_thread); +} + + +/** + * Calculated CPU time difference for given two rusage structures. + * Note it adds user space and system time together. + */ +static unsigned long long +get_rusage_diff (struct rusage *start, struct rusage *end) +{ + unsigned long long rusage_diff; + unsigned long long rusage_start; + unsigned long long rusage_end; + + rusage_start = (start->ru_utime.tv_sec * 1000000) + + (start->ru_utime.tv_usec); + rusage_start += (start->ru_stime.tv_sec * 1000000) + + (start->ru_stime.tv_usec); + + rusage_end = (end->ru_utime.tv_sec * 1000000) + + (end->ru_utime.tv_usec); + rusage_end += (end->ru_stime.tv_sec * 1000000) + + (end->ru_stime.tv_usec); + + rusage_diff = rusage_end - rusage_start; + + return rusage_diff; +} + + +/** + * Get diff for RUSAGE_SELF (whole process) between two time snap + * records. + */ +static unsigned long long +get_rusage_self_diff (time_record_t *start, time_record_t *end) +{ + return get_rusage_diff(&start->ru_self, &end->ru_self); +} + + +/** + * Get diff for RUSAGE_THREAD (current thread only) between two + * time snap records. + */ +static unsigned long long +get_rusage_thread_diff (time_record_t *start, time_record_t *end) +{ + return get_rusage_diff(&start->ru_thread, &end->ru_thread); +} + + +/** + * Get diff of elapsed time between two time snap records + */ +static unsigned long long +get_elapsed_usec (time_record_t *start, time_record_t *end) +{ + unsigned long long s; + unsigned long long e; + + s = (start->tv.tv_sec * 1000000) + + (start->tv.tv_usec); + e = (end->tv.tv_sec * 1000000) + + (end->tv.tv_usec); + + return e - s; +} + +#define REPORT_HEADER "\n%30.30s %15s %15s %15s %15s %15s %15s\n" +#define REPORT_LINE "%30.30s %15d %15d %15.3f %15.3f %15.3f %15d\n" + + +/** + * Print header line for our report. + */ +static void +print_result_header(void) +{ + printf(REPORT_HEADER, + "algorithm", "avg over #", "payload (bytes)", "elapsed (us)", + "rusg self (us)", "rusg thrd (us)", "throughput (Kb)"); +} + + +/** + * Print one line of our report. + */ +static void +print_result(cspeed_args_t *cargs, + unsigned int payload_size, + cspeed_alg_config_t *config, + cspeed_run_result_t *result) +{ + unsigned int throughput; + throughput = (1000000.0 / result->elapsed) * payload_size / 1024; + printf(REPORT_LINE, + config->name, cargs->iteration_count, payload_size, + result->elapsed, result->rusage_self, result->rusage_thread, + throughput); +} + + +/** + * Print piece of memory with given size. + */ +static void +print_memory (const char *msg, + const unsigned char *ptr, + unsigned int len) +{ + unsigned i, j; + char c; + char line[81]; + char *p; + + if (msg) { + printf("\n%s (bytes size = %d)", msg, len); + } + + for (i=0; i < len; i+=16) { + p = line; + sprintf(p, "\n%04x ", i); p +=8; + + for (j = 0; j < 16; j++) { + if (i+j == len) break; + + sprintf(p, " %02x", (ptr)[i+j]); p += 3; + } + + for (; j < 16; j++) { sprintf(p, " "); p += 3; } + + sprintf(p, " "); p += 3; + + for (j = 0; j < 16; j++) { + if (i+j == len) break; + c = (ptr)[i+j]; + *p++ = (' ' <= c && c <= '~') ? c : '.'; + } + + *p = '\0'; + printf("%s", line); + } + printf("\n"); +} + + +/** + * Create ODP crypto session for given config. + */ +static int +create_session_from_config(odp_crypto_session_t *session, + cspeed_alg_config_t *config) +{ + odp_crypto_session_params_t params; + enum odp_crypto_ses_create_err ses_create_rc; + odp_buffer_pool_t pkt_pool; + odp_queue_t out_queue; + + int rc = 0; + + memcpy(¶ms, &config->session, sizeof(odp_crypto_session_params_t)); + params.op = ODP_CRYPTO_OP_ENCODE; + params.pref_mode = ODP_CRYPTO_SYNC; + + if (!rc) { + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + cspeed_error("Error: 'packet_pool' buffer pull not found\n"); + rc = -1; + } else { + params.output_pool = pkt_pool; + } + } + + + if (!rc) { + out_queue = odp_queue_lookup("crypto-out"); + if (out_queue == ODP_QUEUE_INVALID) { + cspeed_error("Error: 'crypto-out' queue not found\n"); + rc = -1; + } else { + params.compl_queue = out_queue; + } + /* + * Uncomment below for generic implementation if inline + * encryption is desired. Note ks2 implementation cannot + * deal with that. + */ + /* params.compl_queue = ODP_QUEUE_INVALID; */ + } + + if (!rc) { + /* + * Prefered synchronous session create for now, but it could be + * ignored by implementation + */ + if (odp_crypto_session_create(¶ms, session, + &ses_create_rc)) { + cspeed_error("Error: ODP crypto session create failed.\n"); + rc = -1; + } + } + + + return rc; +} + + +/** + * Run measurement iterations for given config and payload size. + * Result of run returned in 'result' out parameter. + */ +static int +run_measure_one(cspeed_args_t *cargs, + cspeed_alg_config_t *config, + odp_crypto_session_t *session, + unsigned int payload_size, + cspeed_run_result_t *result) +{ + odp_crypto_op_params_t params; + + odp_buffer_pool_t pkt_pool; + odp_queue_t out_queue; + odp_packet_t pkt; + odp_buffer_t buf; + + bool posted = 0; + int rc = 0; + + + if (!rc) { + /* Lookup the packet pool */ + pkt_pool = odp_buffer_pool_lookup("packet_pool"); + if (pkt_pool == ODP_BUFFER_POOL_INVALID) { + cspeed_error("Error: pkt_pool not found\n"); + rc = -1; + } + } + + if (!rc) { + out_queue = odp_queue_lookup("crypto-out"); + if (out_queue == ODP_QUEUE_INVALID) { + cspeed_error("Error: 'crypto-out' queue not found\n"); + rc = -1; + } + } + + if (!rc) { + buf = odp_buffer_alloc(pkt_pool); + if (buf == ODP_BUFFER_INVALID) { + cspeed_error("Error: failed to allocate buffer\n"); + rc = -1; + } else { + pkt = odp_packet_from_buffer(buf); + odp_packet_set_len(pkt, payload_size); + { + void *mem = odp_packet_start(pkt); + memset(mem, 1, payload_size); + } + } + } + + if (!rc) { + time_record_t start, end; + int packets_sent = 0; + int packets_received = 0; + + /* Initialize parameters block */ + memset(¶ms, 0, sizeof(params)); + params.session = *session; + params.cipher_range.offset = 0; + params.cipher_range.length = payload_size; + /* + * Uncomment following line if hash itself have + * to be encrypted. Note ks2 cannot do that + */ + /* params.cipher_range.length += config->hash_adjust; */ + params.auth_range.offset = 0; + params.auth_range.length = payload_size; + params.hash_result_offset = payload_size; + + if (cargs->reuse_packet) { + params.pkt = pkt; + params.out_pkt = cargs->in_place ? pkt : + ODP_PACKET_INVALID; + } + + fill_time_record(&start); + + while ((packets_sent < cargs->iteration_count) || + (packets_received < cargs->iteration_count)) { + void *mem; + + if ((packets_sent < cargs->iteration_count) && + (packets_sent - packets_received < cargs->in_flight)) { + + + if (!cargs->reuse_packet) { + /* + * For in place test we use just one statically allocated + * buffer. For now in place test we have to allocate and + * initialize packet every time. Note we leaked one + * packet here. + */ + if (!cargs->in_place) { + buf = odp_buffer_alloc(pkt_pool); + if (buf == ODP_BUFFER_INVALID) { + cspeed_error("Error: failed to allocate buffer\n"); + rc = -1; + } else { + pkt = odp_packet_from_buffer(buf); + odp_packet_set_len(pkt, payload_size); + { + void *mem = + odp_packet_start(pkt); + memset(mem, 1, payload_size); + } + } + } + + params.pkt = pkt; + params.out_pkt = cargs->in_place ? pkt : + ODP_PACKET_INVALID; + } + + + if (cargs->debug_packets) { + mem = odp_packet_start(params.pkt); + print_memory("Packet before encryption:", + mem, payload_size); + } + + rc = odp_crypto_operation(¶ms, &posted, + odp_buffer_from_packet(pkt)); + if (rc) { + cspeed_error("Error: failed odp_crypto_operation: rc = %d\n", rc); + } else { + packets_sent++; + } + } + + if (!posted) { + if (cargs->debug_packets) { + mem = odp_packet_start(params.out_pkt); + print_memory("Imediately encrypted packet", + mem, payload_size + config->hash_adjust); + } + if (!cargs->in_place) { + if (cargs->reuse_packet) { + params.pkt = params.out_pkt; + params.out_pkt = ODP_PACKET_INVALID; + } else { + odp_buffer_free(params.out_pkt); + } + } + } else { + odp_buffer_t completion; + odp_packet_t out_pkt; + + completion = odp_queue_deq(out_queue); + + while (completion != ODP_BUFFER_INVALID) { + out_pkt = odp_crypto_get_operation_compl_packet(completion); + + if (cargs->debug_packets) { + mem = odp_packet_start(out_pkt); + print_memory("Receieved encrypted packet", + mem, payload_size + config->hash_adjust); + } + if (!cargs->in_place) { + if (cargs->reuse_packet) { + params.pkt = out_pkt; + params.out_pkt = ODP_PACKET_INVALID; + } else { + odp_buffer_free(out_pkt); + } + } + packets_received++; + + completion = odp_queue_deq(out_queue); + }; + + } + } + + fill_time_record(&end); + + { + double count; + + count = get_elapsed_usec(&start, &end); + result->elapsed = count / + cargs->iteration_count; + + count = get_rusage_self_diff(&start, &end); + result->rusage_self = count / + cargs->iteration_count; + + count = get_rusage_thread_diff(&start, &end); + result->rusage_thread = count / + cargs->iteration_count; + } + } + return rc; +} + + +/** + * Process one algorithm. Note if paload size is specicified it is + * only one run. Or iterate over set of predefined payloads. + */ +static int +run_measure_one_config(cspeed_args_t *cargs, + cspeed_alg_config_t *config) +{ + cspeed_run_result_t result; + odp_crypto_session_t session; + int rc = 0; + + if (create_session_from_config(&session, config)) { + rc = -1; + } + + if (!rc) { + if (cargs->payload_size) { + rc = run_measure_one(cargs, config, &session, + cargs->payload_size, &result); + if (!rc){ + print_result_header(); + print_result(cargs, cargs->payload_size, + config, &result); + } + } else { + unsigned int i; + + print_result_header(); + for (i = 0; + i < sizeof(payloads)/sizeof(unsigned int); + i++) { + rc = run_measure_one(cargs, config, &session, + payloads[i], &result); + if(rc) { + break; + } else { + print_result(cargs, payloads[i], + config, &result); + } + } + } + } + + + // destroy session + if (session != ODP_CRYPTO_SESSION_INVALID) { + odp_crypto_session_destroy(session); + } + return rc; +} + + +int main(int argc, char *argv[]) +{ + int thr_id; + cspeed_args_t cargs; + odp_buffer_pool_t pool; + odp_queue_t out_queue; + void *pool_base; + + /* Init ODP before calling anything else */ + if (odp_init_global()) { + cspeed_error("Error: ODP global init failed.\n"); + exit(EXIT_FAILURE); + } + + /* Parse and store the application arguments */ + parse_args(argc, argv, &cargs); + + /* Init this thread */ + thr_id = odp_thread_create(0); + odp_init_local(thr_id); + + /* Create packet pool */ + pool_base = odp_shm_reserve("shm_packet_pool", + SHM_PKT_POOL_SIZE, ODP_CACHE_LINE_SIZE); + if (pool_base == NULL) { + cspeed_error("Error: packet pool mem alloc failed.\n"); + exit(EXIT_FAILURE); + } + + pool = odp_buffer_pool_create("packet_pool", pool_base, + SHM_PKT_POOL_SIZE, + SHM_PKT_POOL_BUF_SIZE, + ODP_CACHE_LINE_SIZE, + ODP_BUFFER_TYPE_PACKET); + if (pool == ODP_BUFFER_POOL_INVALID) { + cspeed_error("Error: packet pool create failed.\n"); + exit(EXIT_FAILURE); + } + /* odp_buffer_pool_print(pool); */ + + out_queue = odp_queue_create("crypto-out",ODP_QUEUE_TYPE_POLL, NULL); + if (out_queue == ODP_QUEUE_INVALID) { + cspeed_error("Can't create out crypto queue\n"); + exit(EXIT_FAILURE); + } + + if (cargs.alg_config) { + run_measure_one_config(&cargs, cargs.alg_config); + } else { + unsigned int i; + for (i = 0; + i < sizeof(algs_config)/sizeof(cspeed_alg_config_t); + i++) { + run_measure_one_config(&cargs, algs_config + i); + } + } + + return 0; +} + + +static void parse_args(int argc, char *argv[], cspeed_args_t *cargs) +{ + int opt; + int long_index; + static struct option longopts[] = { + {"algorithm", optional_argument, NULL, 'a'}, + {"count", optional_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"flight", optional_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, /* return 'h' */ + {"iterations", optional_argument, NULL, 'i'}, + {"inplace", no_argument, NULL, 'n'}, + {"payload", optional_argument, NULL, 'p'}, + {"sessions", optional_argument, NULL, 'm'}, + {"reuse", no_argument, NULL, 'r'}, + {NULL, 0, NULL, 0} + }; + + cargs->in_place = 0; + cargs->in_flight = 1; + cargs->debug_packets = 0; + cargs->core_count = 1; + cargs->iteration_count = 10000; + cargs->payload_size = 0; + cargs->alg_config = NULL; + + while (1) { + opt = getopt_long(argc, argv, "+a:c:df:hi:m:np:r", + longopts, &long_index); + + if (opt == -1) + break; /* No more options */ + + switch (opt) { + case 'a': + cargs->alg_config = find_config_by_name(optarg); + if (!cargs->alg_config) { + printf("cannot test crypto '%s' configuration\n", optarg); + usage(argv[0]); + exit(-1); + } + case 'c': + cargs->core_count = atoi(optarg); + break; + case 'd': + cargs->debug_packets = 1; + break; + case 'i': + cargs->iteration_count = atoi(optarg); + break; + case 'f': + cargs->in_flight = atoi(optarg); + break; + case 'h': + usage(argv[0]); + exit(EXIT_SUCCESS); + break; + case 'm': + cargs->max_sessions = atoi(optarg); + break; + case 'n': + cargs->in_place = 1; + break; + case 'p': + cargs->payload_size = atoi(optarg); + break; + case 'r': + cargs->reuse_packet = 1; + break; + default: + break; + } + } + + optind = 1; /* reset 'extern optind' from the getopt lib */ + + if ((cargs->in_flight > 1) && cargs->reuse_packet) { + printf("-f (in flight > 1) and -r (reuse packet) options are not compatible\n"); + usage(argv[0]); + exit(-1); + } + + if ((cargs->in_flight > 1) && cargs->in_place) { + printf("-f (in flight > 1) and -n (in place) options are not compatible\n"); + usage(argv[0]); + exit(-1); + } + +} + + +/** + * Prinf usage information + */ +static void usage(char *progname) +{ + printf("\n" + "Usage: %s OPTIONS\n" + " E.g. %s -i 100000\n" + "\n" + "OpenDataPlane crypto speed measure.\n" + "Optional OPTIONS\n" + " -a, --algorithm <name> Specify algorithm name (default all)\n" + " Supported values are:\n", + progname, progname); + + print_config_names(" "); + printf(" -c, --count <number> Core count. (NOT used)\n" + " -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" + " -n, --inplace Encrypt on place (ks2 does not support this).\n" + " -p, --payload Payload size.\n" + " -r, --reuse Output encrypted packet is passed as input\n" + " to next encrypt iteration.\n" + " -h, --help Display help and exit.\n" + "\n"); +}
Sample test code that measures speed of ODP crypto operations. o measures operation elapsed, cpu time, and throughput o supports multiple algorithms o supports multiple payload sizes o support synch and async crypto operation modes Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org> --- configure.ac | 1 + example/Makefile.am | 2 +- example/cspeed/Makefile.am | 6 + example/cspeed/odp_cspeed.c | 918 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 926 insertions(+), 1 deletion(-) create mode 100644 example/cspeed/Makefile.am create mode 100644 example/cspeed/odp_cspeed.c