diff mbox

[5/5] example: test program that measures speed of ODP crypto operations

Message ID 1410397827-2758-6-git-send-email-victor.kamensky@linaro.org
State New
Headers show

Commit Message

vkamensky Sept. 11, 2014, 1:10 a.m. UTC
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

Comments

Anders Roxell Sept. 11, 2014, 10:52 a.m. UTC | #1
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(&params, &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(&params, 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(&params, 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(&params, &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
Anders Roxell Sept. 11, 2014, 11:07 a.m. UTC | #2
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(&params, &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(&params, 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(&params, 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(&params, &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 mbox

Patch

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(&params, &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(&params, 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(&params, 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(&params, &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");
+}