API Reference Manual  1.45.0
odp_cpu_bench.c

Application for CPU stress testing

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2018 Linaro Limited
*/
#include <odp_api.h>
#include <odp/helper/odph_api.h>
#include <getopt.h>
#include <inttypes.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
/* Queues are divided into groups and tests packets are passed only between
* queues which belong to the same group. */
#define MAX_GROUPS 64
#define QUEUES_PER_GROUP 4
#define PKTS_PER_QUEUE 256
#define MAX_EVENT_BURST 32
#define CRC_INIT_VAL 123456789
#define PASS_PACKETS 10000
/* Default number of entries in the test lookup table */
#define DEF_LOOKUP_TBL_SIZE (1024 * 1024)
#define MAX_WORKERS \
(((ODP_THREAD_COUNT_MAX - 1) > (MAX_GROUPS * QUEUES_PER_GROUP)) ? \
(MAX_GROUPS * QUEUES_PER_GROUP) : \
(ODP_THREAD_COUNT_MAX - 1))
ODP_STATIC_ASSERT(MAX_WORKERS <= MAX_GROUPS * QUEUES_PER_GROUP,
"Not enough queues for all workers");
/* Get rid of path in filename - only for unix-type paths using '/' */
#define NO_PATH(file_name) (strrchr((file_name), '/') ? \
strrchr((file_name), '/') + 1 : (file_name))
/* Test dummy lookup table entry */
typedef struct {
uint64_t idx;
uint32_t val0;
uint32_t val1;
} lookup_entry_t;
/* Test packet */
typedef struct {
uint32_t seq;
uint32_t crc;
uint16_t group;
} test_hdr_t;
/* Parsed application arguments */
typedef struct {
uint64_t lookup_tbl_size; /* Lookup table size */
int accuracy; /* Number of seconds between stats prints */
unsigned int cpu_count; /* CPU count */
int time; /* Time in seconds to run */
} appl_args_t;
/* Statistics */
typedef union ODP_ALIGNED_CACHE {
struct {
/* Number of processed packets */
uint64_t pkts;
/* Number of dropped packets */
uint64_t dropped_pkts;
/* Time spent processing packets */
uint64_t nsec;
/* Cycles spent processing packets */
uint64_t cycles;
} s;
uint8_t padding[ODP_CACHE_LINE_SIZE];
} stats_t;
/* Thread specific data */
typedef struct thread_args_t {
stats_t stats;
uint16_t idx;
} thread_args_t;
/* Grouping of all global data */
typedef struct {
/* Thread specific arguments */
thread_args_t thread[MAX_WORKERS];
/* Barriers to synchronize main and workers */
odp_barrier_t init_barrier;
odp_barrier_t term_barrier;
/* Application (parsed) arguments */
appl_args_t appl;
/* Test queues */
odp_queue_t queue[MAX_GROUPS][QUEUES_PER_GROUP];
/* Test lookup table */
lookup_entry_t *lookup_tbl;
/* Break workers loop if set to 1 */
odp_atomic_u32_t exit_threads;
} args_t;
/* Global pointer to args */
static args_t *gbl_args;
static const uint8_t test_udp_packet[] = {
0x00, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00, 0x01,
0x02, 0x03, 0x04, 0x05, 0x08, 0x00, 0x45, 0x00,
0x02, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x40, 0x11,
0xF7, 0x7C, 0xC0, 0xA8, 0x00, 0x01, 0xC0, 0xA8,
0x00, 0x02, 0x04, 0xD2, 0x1A, 0x82, 0x02, 0x08,
0x24, 0x1E, 0xC9, 0x56, 0xB4, 0xD6, 0x4B, 0x64,
0xB3, 0x01, 0xA1, 0x97, 0x4D, 0xD1, 0xA4, 0x76,
0xF5, 0x7B, 0x27, 0x22, 0x6C, 0xA9, 0xED, 0x29,
0x6E, 0x02, 0x80, 0xF7, 0xC4, 0x2D, 0x2A, 0x96,
0x2D, 0xF6, 0x02, 0x8E, 0x89, 0x9F, 0x8C, 0xF4,
0x0D, 0xC5, 0xE5, 0x1F, 0xA1, 0x52, 0xC3, 0x4B,
0x5C, 0x4C, 0xDF, 0x14, 0x05, 0x6A, 0xA8, 0xD7,
0xAD, 0x4F, 0x22, 0xA6, 0xB8, 0xF9, 0x52, 0x5A,
0xB8, 0xF9, 0xE2, 0x2C, 0x05, 0x2A, 0x6F, 0xF2,
0xCA, 0xA1, 0xA7, 0xC3, 0x56, 0xE1, 0xDB, 0xC1,
0xDB, 0x86, 0x26, 0x55, 0xAC, 0xBE, 0xE1, 0x3D,
0x82, 0x86, 0xB9, 0xDE, 0x3E, 0xD3, 0x11, 0xAB,
0x65, 0x6A, 0xED, 0x1B, 0x60, 0xBE, 0x69, 0x71,
0xB2, 0xA8, 0x5B, 0xB1, 0x06, 0xE3, 0x48, 0x14,
0xC9, 0x13, 0x73, 0xDA, 0xBE, 0xE4, 0x7A, 0x5F,
0xC0, 0xE0, 0xCA, 0xF3, 0x7A, 0xCA, 0x3F, 0xC9,
0x4A, 0xEE, 0x47, 0x76, 0x67, 0xF0, 0x0D, 0x3F,
0x7F, 0x3D, 0x69, 0xEA, 0x39, 0x53, 0x7C, 0xE3,
0xED, 0x78, 0x79, 0x47, 0x60, 0x95, 0xCB, 0xDC,
0x26, 0x60, 0x46, 0xAC, 0x47, 0xDA, 0x4C, 0x4D,
0x0F, 0xE1, 0x68, 0x43, 0xBC, 0xCD, 0x4E, 0xFE,
0x2E, 0xD6, 0xC2, 0x6E, 0x63, 0xEA, 0xB3, 0x98,
0xCA, 0x8F, 0x7F, 0x05, 0xDF, 0x72, 0x8F, 0x6E,
0x3E, 0x6D, 0xC7, 0x94, 0x59, 0x9D, 0x15, 0x5B,
0xB8, 0x02, 0x52, 0x4F, 0x68, 0x3A, 0xF1, 0xFF,
0xA9, 0xA4, 0x30, 0x29, 0xE0, 0x1C, 0xA0, 0x1B,
0x50, 0xAB, 0xFD, 0x06, 0x84, 0xD4, 0x33, 0x51,
0x01, 0xB3, 0x5F, 0x49, 0x5F, 0x21, 0xA0, 0xA1,
0xC9, 0x08, 0xB3, 0xDF, 0x72, 0x9B, 0x5B, 0x70,
0x89, 0x96, 0x08, 0x25, 0x88, 0x1E, 0xED, 0x52,
0xDC, 0x98, 0xA0, 0xB8, 0x83, 0x2A, 0xA0, 0x90,
0x45, 0xC9, 0x77, 0xD2, 0x19, 0xD7, 0x6B, 0xAB,
0x49, 0x67, 0x7C, 0xD1, 0xE0, 0x23, 0xA2, 0x36,
0xB2, 0x91, 0x3B, 0x23, 0x3B, 0x03, 0x36, 0xAF,
0xAD, 0x81, 0xFA, 0x6F, 0x68, 0xD5, 0xBE, 0x73,
0x1D, 0x56, 0x8A, 0xE8, 0x1A, 0xB4, 0xA8, 0x7C,
0xF3, 0x82, 0x10, 0xD0, 0xF2, 0x1D, 0x9C, 0xEA,
0xAB, 0xE7, 0xEC, 0x53, 0x6D, 0x52, 0xBD, 0x29,
0x86, 0x21, 0xCE, 0xAA, 0xF3, 0x68, 0xA6, 0xEC,
0x7E, 0xCA, 0x6F, 0xEB, 0xE1, 0x81, 0x80, 0x7C,
0xF3, 0xE5, 0x22, 0xA0, 0x91, 0x08, 0xB7, 0x35,
0x15, 0x87, 0x0C, 0x77, 0x31, 0x9C, 0x2F, 0x73,
0xCE, 0x29, 0x6F, 0xC6, 0xAC, 0x9F, 0x68, 0xB8,
0x6A, 0xFC, 0xD3, 0xB5, 0x08, 0x98, 0xAE, 0xE4,
0x20, 0x84, 0x24, 0x69, 0xA5, 0xF5, 0x4A, 0x9D,
0x44, 0x26, 0x5A, 0xF9, 0x6B, 0x5E, 0x5D, 0xC8,
0x6F, 0xD4, 0x62, 0x91, 0xE5, 0x8E, 0x80, 0x05,
0xA1, 0x95, 0x09, 0xEA, 0xFE, 0x84, 0x6D, 0xC3,
0x0D, 0xD4, 0x32, 0xA4, 0x38, 0xB2, 0xF7, 0x9D,
0x58, 0xD3, 0x5D, 0x93, 0x5F, 0x67, 0x86, 0xE1,
0xAF, 0xFF, 0xE9, 0xFE, 0xF4, 0x71, 0x63, 0xE3,
0x3E, 0xE1, 0x7A, 0x80, 0x5A, 0x23, 0x4F, 0x5B,
0x54, 0x21, 0x0E, 0xE2, 0xAF, 0x01, 0x2E, 0xA4,
0xF5, 0x1F, 0x59, 0x96, 0x3E, 0x82, 0xF3, 0x44,
0xDF, 0xA6, 0x7C, 0x64, 0x5D, 0xC7, 0x79, 0xA1,
0x17, 0xE1, 0x06, 0x14, 0x3E, 0x1B, 0x46, 0xCA,
0x71, 0xC8, 0x05, 0x62, 0xD0, 0x56, 0x23, 0x9B,
0xBA, 0xFE, 0x6D, 0xA8, 0x03, 0x4C, 0x23, 0xD8,
0x98, 0x8A, 0xE8, 0x9C, 0x93, 0x8E, 0xB7, 0x24,
0x31, 0x2A, 0x81, 0x72, 0x8F, 0x13, 0xD4, 0x7E,
0xEB, 0xB1, 0xEE, 0x33, 0xD9, 0xF4, 0x96, 0x5E,
0x6C, 0x3D, 0x45, 0x9C, 0xE0, 0x71, 0xA3, 0xFA,
0x17, 0x2B, 0xC3, 0x07, 0xD6, 0x86, 0xA2, 0x06,
0xC5, 0x33, 0xF0, 0xEA, 0x25, 0x70, 0x68, 0x56,
0xD5, 0xB0
};
static void sig_handler(int signo ODP_UNUSED)
{
if (gbl_args == NULL)
return;
odp_atomic_store_u32(&gbl_args->exit_threads, 1);
}
static inline void init_packet(odp_packet_t pkt, uint32_t seq, uint16_t group)
{
odp_una_u32_t *payload;
test_hdr_t *hdr;
param.chksums.all_chksum = 0;
if (odp_packet_parse(pkt, 0, &param))
ODPH_ABORT("odp_packet_parse() failed\n");
/* Modify UDP payload and update checksum */
ODPH_UDPHDR_LEN, NULL, NULL);
*payload = seq;
if (odph_udp_chksum_set(pkt))
ODPH_ABORT("odph_udp_chksum_set() failed\n");
/* Test header is stored in user area */
hdr->seq = seq;
hdr->group = group;
CRC_INIT_VAL);
}
static inline odp_queue_t work_on_event(odp_event_t event)
{
odph_udphdr_t *udp_hdr;
test_hdr_t *hdr;
lookup_entry_t *lookup_entry;
odp_una_u32_t *payload;
uint32_t crc;
uint32_t pkt_len;
uint8_t *data;
uint32_t new_val;
uint32_t old_val;
if (odp_event_type(event) != ODP_EVENT_PACKET)
pkt = odp_packet_from_event(event);
pkt_len = odp_packet_len(pkt);
data = odp_packet_data(pkt);
crc = odp_hash_crc32c(data, pkt_len, CRC_INIT_VAL);
if (crc != hdr->crc)
ODPH_ERR("Error: Invalid packet crc\n");
param.chksums.all_chksum = 1;
if (odp_packet_parse(pkt, 0, &param)) {
ODPH_ERR("Error: odp_packet_parse() failed\n");
}
/* Modify packet data using lookup table value and sequence number, and
* update UDP checksum accordingly. */
lookup_entry = &gbl_args->lookup_tbl[(crc + hdr->seq) %
gbl_args->appl.lookup_tbl_size];
udp_hdr = odp_packet_l4_ptr(pkt, NULL);
ODPH_UDPHDR_LEN, NULL, NULL);
old_val = *payload;
*payload += lookup_entry->idx % 2 ? lookup_entry->val1 :
lookup_entry->val0;
new_val = *payload;
udp_hdr->chksum = ~(~udp_hdr->chksum + (-old_val) + new_val);
payload++;
old_val = *payload;
*payload += hdr->seq;
new_val = *payload;
udp_hdr->chksum = ~(~udp_hdr->chksum + (-old_val) + new_val);
hdr->crc = odp_hash_crc32c(data, pkt_len, CRC_INIT_VAL);
return gbl_args->queue[hdr->group][hdr->seq++ % QUEUES_PER_GROUP];
}
static int run_thread(void *arg)
{
thread_args_t *thr_args = arg;
stats_t *stats = &thr_args->stats;
odp_time_t t1, t2;
uint64_t c1, c2;
odp_barrier_wait(&gbl_args->init_barrier);
while (!odp_atomic_load_u32(&gbl_args->exit_threads)) {
odp_event_t event_tbl[MAX_EVENT_BURST];
odp_queue_t dst_queue;
int num_events;
int i;
event_tbl, MAX_EVENT_BURST);
if (num_events <= 0)
continue;
for (i = 0; i < num_events; i++) {
odp_event_t event = event_tbl[i];
dst_queue = work_on_event(event);
if (odp_unlikely(dst_queue == ODP_QUEUE_INVALID)) {
stats->s.dropped_pkts++;
continue;
}
if (odp_unlikely(odp_queue_enq(dst_queue, event))) {
ODPH_ERR("Error: odp_queue_enq() failed\n");
stats->s.dropped_pkts++;
break;
}
stats->s.pkts++;
}
}
stats->s.cycles = c2 - c1;
stats->s.nsec = odp_time_diff_ns(t2, t1);
odp_barrier_wait(&gbl_args->term_barrier);
/* Free remaining events in queues */
while (1) {
ev = odp_schedule(NULL,
if (ev == ODP_EVENT_INVALID)
break;
}
return 0;
}
/*
* Print usage information
*/
static void usage(char *progname)
{
printf("\n"
"OpenDataPlane CPU benchmarking application.\n"
"\n"
"Usage: %s [options]\n"
"\n"
" E.g. %s -c 4 -t 30\n"
"Options:\n"
" -c, --count <number> CPU count, 0=all available, default=1\n"
" -t, --time <sec> Time in seconds to run\n"
" (default is 10 second).\n"
" -a, --accuracy <sec> Time in seconds get print statistics\n"
" (default is 1 second).\n"
" -l, --lookup_tbl <num> Number of entries in dummy lookup table\n"
" (default is %d).\n"
" -h, --help Display help and exit.\n\n"
"\n", NO_PATH(progname), NO_PATH(progname), DEF_LOOKUP_TBL_SIZE);
}
static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
{
int opt;
int long_index;
static const struct option longopts[] = {
{"accuracy", required_argument, NULL, 'a'},
{"cpu", required_argument, NULL, 'c'},
{"lookup_tbl", required_argument, NULL, 'l'},
{"time", required_argument, NULL, 't'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
static const char *shortopts = "+a:c:l:t:h";
appl_args->accuracy = 1; /* Get and print pps stats second */
appl_args->cpu_count = 1;
appl_args->lookup_tbl_size = DEF_LOOKUP_TBL_SIZE;
appl_args->time = 10; /* Loop forever if time to run is 0 */
while (1) {
opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
if (opt == -1)
break; /* No more options */
switch (opt) {
case 'a':
appl_args->accuracy = atoi(optarg);
break;
case 'c':
appl_args->cpu_count = atoi(optarg);
break;
case 'l':
appl_args->lookup_tbl_size = atoi(optarg);
break;
case 't':
appl_args->time = atoi(optarg);
break;
case 'h':
usage(argv[0]);
exit(EXIT_SUCCESS);
break;
default:
break;
}
}
if (appl_args->lookup_tbl_size < 1) {
printf("At least one lookup table entry required.\n");
exit(EXIT_FAILURE);
}
}
/*
* Print statistics
*
* num_workers Number of worker threads
* thr_stats Pointers to stats storage
* duration Number of seconds to loop
*/
static int print_stats(int num_workers, stats_t **thr_stats, int duration,
int accuracy)
{
uint64_t pkts;
uint64_t dropped;
uint64_t pkts_prev = 0;
uint64_t nsec = 0;
uint64_t cycles = 0;
int i;
int elapsed = 0;
int stats_enabled = 1;
int loop_forever = (duration == 0);
if (accuracy <= 0) {
stats_enabled = 0;
accuracy = 1;
}
/* Wait for all threads to be ready*/
odp_barrier_wait(&gbl_args->init_barrier);
do {
uint64_t pps;
sleep(accuracy);
pkts = 0;
dropped = 0;
for (i = 0; i < num_workers; i++) {
pkts += thr_stats[i]->s.pkts;
dropped += thr_stats[i]->s.dropped_pkts;
}
pps = (pkts - pkts_prev) / accuracy;
if (stats_enabled) {
printf("%.2f Mpps, ", pps / 1000000.0);
printf("%" PRIu64 " dropped\n", dropped);
}
pkts_prev = pkts;
elapsed += accuracy;
} while (!odp_atomic_load_u32(&gbl_args->exit_threads) &&
(loop_forever || (elapsed < duration)));
odp_atomic_store_u32(&gbl_args->exit_threads, 1);
odp_barrier_wait(&gbl_args->term_barrier);
pkts = 0;
dropped = 0;
for (i = 0; i < num_workers; i++) {
pkts += thr_stats[i]->s.pkts;
dropped += thr_stats[i]->s.dropped_pkts;
nsec += thr_stats[i]->s.nsec;
cycles += thr_stats[i]->s.cycles;
}
printf("\nRESULTS - per thread (Million packets per sec):\n");
printf("-----------------------------------------------\n");
printf(" avg 1 2 3 4 5 6 7 8 9 10\n");
printf("%6.2f ", pkts / (nsec / 1000.0));
for (i = 0; i < num_workers; i++) {
if (i != 0 && (i % 10) == 0)
printf("\n ");
printf("%6.2f ", thr_stats[i]->s.pkts /
(thr_stats[i]->s.nsec / 1000.0));
}
printf("\n\n");
nsec /= num_workers;
printf("RESULTS - total over %i threads:\n", num_workers);
printf("----------------------------------\n");
printf(" avg packets per sec: %.3f M\n", pkts / (nsec / 1000.0));
printf(" avg cycles per packet: %" PRIu64 "\n", cycles / pkts);
printf(" dropped packets: %" PRIu64 "\n\n", dropped);
return pkts > PASS_PACKETS ? 0 : -1;
}
static void gbl_args_init(args_t *args)
{
memset(args, 0, sizeof(args_t));
odp_atomic_init_u32(&args->exit_threads, 0);
}
int main(int argc, char *argv[])
{
stats_t *stats[MAX_WORKERS];
odph_helper_options_t helper_options;
odph_thread_t thread_tbl[MAX_WORKERS];
odph_thread_common_param_t thr_common;
odph_thread_param_t thr_param[MAX_WORKERS];
odp_cpumask_t cpumask;
odp_pool_t pool;
odp_schedule_config_t schedule_config;
odp_shm_t shm;
odp_shm_t lookup_tbl_shm;
odp_instance_t instance;
odp_init_t init;
char cpumaskstr[ODP_CPUMASK_STR_SIZE];
uint32_t num_pkts;
uint32_t num_groups;
uint32_t num_queues;
uint32_t pkts_per_group;
uint32_t pkt_len;
uint32_t init_val;
unsigned int num_workers;
unsigned int i, j;
int ret = 0;
/* Let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
if (odph_options(&helper_options)) {
ODPH_ERR("Error: reading ODP helper options failed.\n");
exit(EXIT_FAILURE);
}
/* List features not to be used (may optimize performance) */
init.not_used.feat.cls = 1;
init.not_used.feat.crypto = 1;
init.not_used.feat.ipsec = 1;
init.not_used.feat.timer = 1;
init.not_used.feat.tm = 1;
init.mem_model = helper_options.mem_model;
/* Signal handler has to be registered before global init in case ODP
* implementation creates internal threads/processes. */
signal(SIGINT, sig_handler);
if (odp_init_global(&instance, &init, NULL)) {
ODPH_ERR("Error: ODP global init failed\n");
return -1;
}
ODPH_ERR("Error: ODP local init failed\n");
exit(EXIT_FAILURE);
}
shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
0);
if (shm == ODP_SHM_INVALID) {
ODPH_ERR("Error: shared mem reserve failed.\n");
exit(EXIT_FAILURE);
}
gbl_args = odp_shm_addr(shm);
if (gbl_args == NULL) {
ODPH_ERR("Error: shared mem alloc failed\n");
exit(EXIT_FAILURE);
}
gbl_args_init(gbl_args);
/* Parse and store the application arguments */
parse_args(argc, argv, &gbl_args->appl);
lookup_tbl_shm = odp_shm_reserve("lookup_tbl_shm",
sizeof(lookup_entry_t) *
gbl_args->appl.lookup_tbl_size,
ODP_CACHE_LINE_SIZE, 0);
if (lookup_tbl_shm == ODP_SHM_INVALID) {
ODPH_ERR("Error: shared mem reserve failed.\n");
exit(EXIT_FAILURE);
}
gbl_args->lookup_tbl = odp_shm_addr(lookup_tbl_shm);
if (gbl_args->lookup_tbl == NULL) {
ODPH_ERR("Error: lookup table mem alloc failed\n");
exit(EXIT_FAILURE);
}
printf("\n");
/* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
num_workers = gbl_args->appl.cpu_count;
/* Get default worker cpumask */
num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
(void)odp_cpumask_to_str(&cpumask, cpumaskstr, sizeof(cpumaskstr));
printf("num worker threads: %i\n", num_workers);
printf("first CPU: %i\n", odp_cpumask_first(&cpumask));
printf("cpu mask: %s\n", cpumaskstr);
odp_schedule_config_init(&schedule_config);
odp_schedule_config(&schedule_config);
/* Make sure a single queue can store all the packets in a group */
pkts_per_group = QUEUES_PER_GROUP * PKTS_PER_QUEUE;
if (schedule_config.queue_size &&
schedule_config.queue_size < pkts_per_group)
pkts_per_group = schedule_config.queue_size;
/* Divide queues evenly into groups */
if (schedule_config.num_queues < QUEUES_PER_GROUP) {
ODPH_ERR("Error: min %d queues required\n", QUEUES_PER_GROUP);
return -1;
}
num_queues = num_workers > schedule_config.num_queues ?
schedule_config.num_queues : num_workers;
num_groups = (num_queues + QUEUES_PER_GROUP - 1) / QUEUES_PER_GROUP;
if (num_groups * QUEUES_PER_GROUP > schedule_config.num_queues)
num_groups--;
num_queues = num_groups * QUEUES_PER_GROUP;
for (i = 0; i < num_groups; i++) {
for (j = 0; j < QUEUES_PER_GROUP; j++) {
odp_queue_t queue;
param.size = pkts_per_group;
queue = odp_queue_create(NULL, &param);
if (queue == ODP_QUEUE_INVALID) {
ODPH_ERR("Error: odp_queue_create() failed\n");
return -1;
}
gbl_args->queue[i][j] = queue;
}
}
/* Create packet pool */
if (odp_pool_capability(&pool_capa)) {
ODPH_ERR("Error: odp_pool_capability() failed\n");
exit(EXIT_FAILURE);
}
num_pkts = pkts_per_group * num_groups;
if (num_pkts > pool_capa.pkt.max_num)
num_pkts = pool_capa.pkt.max_num;
pkt_len = sizeof(test_udp_packet);
if (pool_capa.pkt.max_len && pkt_len > pool_capa.pkt.max_len)
pkt_len = pool_capa.pkt.max_len;
if (pool_capa.pkt.max_seg_len && pkt_len > pool_capa.pkt.max_seg_len)
pkt_len = pool_capa.pkt.max_seg_len;
if (pkt_len < sizeof(test_udp_packet)) {
ODPH_ERR("Error: min %dB single segment packets required\n",
(int)sizeof(test_udp_packet));
exit(EXIT_FAILURE);
}
if (pool_capa.pkt.max_uarea_size &&
pool_capa.pkt.max_uarea_size < sizeof(test_hdr_t)) {
ODPH_ERR("Error: min %dB of packet user area required\n",
(int)sizeof(test_hdr_t));
exit(EXIT_FAILURE);
}
params.pkt.len = pkt_len;
params.pkt.max_len = pkt_len;
params.pkt.seg_len = pkt_len;
params.pkt.num = num_pkts;
params.pkt.max_num = num_pkts;
params.pkt.uarea_size = sizeof(test_hdr_t);
pool = odp_pool_create("pkt_pool", &params);
if (pool == ODP_POOL_INVALID) {
ODPH_ERR("Error: packet pool create failed\n");
exit(EXIT_FAILURE);
}
printf("CPU bench args\n--------------\n");
printf(" workers: %u\n", num_workers);
printf(" queues: %" PRIu32 "\n", num_queues);
printf(" pkts: %" PRIu32 "\n", num_pkts);
printf(" pkt size: %" PRIu32 " B\n", pkt_len);
printf(" lookup entries: %" PRIu64 "\n\n",
gbl_args->appl.lookup_tbl_size);
/* Spread test packets into queues */
for (i = 0; i < num_pkts; i++) {
odp_packet_t pkt = odp_packet_alloc(pool, pkt_len);
odp_queue_t queue;
uint16_t group = i % num_groups;
if (pkt == ODP_PACKET_INVALID) {
ODPH_ERR("Error: odp_packet_alloc() failed\n");
return -1;
}
odp_packet_copy_from_mem(pkt, 0, pkt_len, test_udp_packet);
init_packet(pkt, i, group);
queue = gbl_args->queue[group][i % QUEUES_PER_GROUP];
if (odp_queue_enq(queue, ev)) {
ODPH_ERR("Error: odp_queue_enq() failed\n");
return -1;
}
}
odp_barrier_init(&gbl_args->init_barrier, num_workers + 1);
odp_barrier_init(&gbl_args->term_barrier, num_workers + 1);
/* Initialize lookup table */
init_val = CRC_INIT_VAL;
for (i = 0; i < gbl_args->appl.lookup_tbl_size; i++) {
uint32_t *val0 = &gbl_args->lookup_tbl[i].val0;
uint32_t *val1 = &gbl_args->lookup_tbl[i].val1;
gbl_args->lookup_tbl[i].idx = i;
*val0 = i;
*val0 = odp_hash_crc32c(val0, sizeof(uint32_t), init_val);
*val1 = odp_hash_crc32c(val0, sizeof(uint32_t), init_val);
init_val = *val1;
}
/* Create worker threads */
odph_thread_common_param_init(&thr_common);
thr_common.instance = instance;
thr_common.cpumask = &cpumask;
for (i = 0; i < num_workers; i++) {
gbl_args->thread[i].idx = i;
stats[i] = &gbl_args->thread[i].stats;
odph_thread_param_init(&thr_param[i]);
thr_param[i].start = run_thread;
thr_param[i].arg = &gbl_args->thread[i];
thr_param[i].thr_type = ODP_THREAD_WORKER;
}
memset(thread_tbl, 0, sizeof(thread_tbl));
odph_thread_create(thread_tbl, &thr_common, thr_param, num_workers);
ret = print_stats(num_workers, stats, gbl_args->appl.time,
gbl_args->appl.accuracy);
/* Master thread waits for other threads to exit */
odph_thread_join(thread_tbl, num_workers);
for (i = 0; i < num_groups; i++) {
for (j = 0; j < QUEUES_PER_GROUP; j++) {
if (odp_queue_destroy(gbl_args->queue[i][j])) {
ODPH_ERR("Error: queue destroy\n");
exit(EXIT_FAILURE);
}
}
}
gbl_args = NULL;
if (odp_pool_destroy(pool)) {
ODPH_ERR("Error: pool destroy\n");
exit(EXIT_FAILURE);
}
if (odp_shm_free(shm)) {
ODPH_ERR("Error: shm free\n");
exit(EXIT_FAILURE);
}
if (odp_shm_free(lookup_tbl_shm)) {
ODPH_ERR("Error: shm free\n");
exit(EXIT_FAILURE);
}
if (odp_term_local()) {
ODPH_ERR("Error: term local\n");
exit(EXIT_FAILURE);
}
if (odp_term_global(instance)) {
ODPH_ERR("Error: term global\n");
exit(EXIT_FAILURE);
}
return ret;
}
void odp_atomic_init_u32(odp_atomic_u32_t *atom, uint32_t val)
Initialize atomic uint32 variable.
uint32_t odp_atomic_load_u32(odp_atomic_u32_t *atom)
Load value of atomic uint32 variable.
void odp_atomic_store_u32(odp_atomic_u32_t *atom, uint32_t val)
Store value to atomic uint32 variable.
void odp_barrier_init(odp_barrier_t *barr, int count)
Initialize barrier with thread count.
void odp_mb_full(void)
Full memory barrier.
void odp_barrier_wait(odp_barrier_t *barr)
Synchronize thread execution on barrier.
#define ODP_ALIGNED_CACHE
Defines type/struct/variable to be cache line size aligned.
#define odp_unlikely(x)
Branch unlikely taken.
Definition: spec/hints.h:64
#define ODP_UNUSED
Intentionally unused variables of functions.
Definition: spec/hints.h:54
uint64_t odp_cpu_cycles(void)
Current CPU cycle count.
int odp_cpumask_default_worker(odp_cpumask_t *mask, int num)
Default CPU mask for worker threads.
int odp_cpumask_first(const odp_cpumask_t *mask)
Find first set CPU in mask.
int32_t odp_cpumask_to_str(const odp_cpumask_t *mask, char *str, int32_t size)
Format a string from CPU mask.
#define ODP_CPUMASK_STR_SIZE
The maximum number of characters needed to record any CPU mask as a string (output of odp_cpumask_to_...
void odp_event_free(odp_event_t event)
Free event.
odp_event_type_t odp_event_type(odp_event_t event)
Event type of an event.
#define ODP_EVENT_INVALID
Invalid event.
uint32_t odp_hash_crc32c(const void *data, uint32_t data_len, uint32_t init_val)
Calculate CRC-32C.
void odp_init_param_init(odp_init_t *param)
Initialize the odp_init_t to default values for all fields.
#define ODP_STATIC_ASSERT(cond, msg)
Compile time assertion macro.
int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
Thread local ODP initialization.
int odp_init_global(odp_instance_t *instance, const odp_init_t *params, const odp_platform_init_t *platform_params)
Global ODP initialization.
int odp_term_local(void)
Thread local ODP termination.
int odp_term_global(odp_instance_t instance)
Global ODP termination.
uint64_t odp_instance_t
ODP instance ID.
odp_event_t odp_packet_to_event(odp_packet_t pkt)
Convert packet handle to event.
uint32_t odp_packet_l4_offset(odp_packet_t pkt)
Layer 4 start offset.
void * odp_packet_data(odp_packet_t pkt)
Packet data pointer.
void * odp_packet_user_area(odp_packet_t pkt)
User area address.
uint32_t odp_packet_len(odp_packet_t pkt)
Packet data length.
odp_packet_t odp_packet_alloc(odp_pool_t pool, uint32_t len)
Allocate a packet from a packet pool.
odp_packet_t odp_packet_from_event(odp_event_t ev)
Get packet handle from event.
int odp_packet_parse(odp_packet_t pkt, uint32_t offset, const odp_packet_parse_param_t *param)
Parse packet.
int odp_packet_copy_from_mem(odp_packet_t pkt, uint32_t offset, uint32_t len, const void *src)
Copy data from memory to packet.
void * odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
Layer 4 start pointer.
#define ODP_PACKET_INVALID
Invalid packet.
void * odp_packet_offset(odp_packet_t pkt, uint32_t offset, uint32_t *len, odp_packet_seg_t *seg)
Packet offset pointer.
@ ODP_PROTO_ETH
Ethernet (including VLAN)
@ ODP_PROTO_LAYER_ALL
All layers.
odp_pool_t odp_pool_create(const char *name, const odp_pool_param_t *param)
Create a pool.
int odp_pool_capability(odp_pool_capability_t *capa)
Query pool capabilities.
void odp_pool_param_init(odp_pool_param_t *param)
Initialize pool params.
int odp_pool_destroy(odp_pool_t pool)
Destroy a pool previously created by odp_pool_create()
void odp_pool_print(odp_pool_t pool)
Print pool info.
#define ODP_POOL_INVALID
Invalid pool.
@ ODP_POOL_PACKET
Packet pool.
void odp_queue_param_init(odp_queue_param_t *param)
Initialize queue params.
#define ODP_QUEUE_INVALID
Invalid queue.
int odp_queue_enq(odp_queue_t queue, odp_event_t ev)
Enqueue an event to a queue.
odp_queue_t odp_queue_create(const char *name, const odp_queue_param_t *param)
Queue create.
int odp_queue_destroy(odp_queue_t queue)
Destroy ODP queue.
@ ODP_QUEUE_TYPE_SCHED
Scheduled queue.
#define ODP_SCHED_SYNC_PARALLEL
Parallel scheduled queues.
int odp_schedule_multi(odp_queue_t *from, uint64_t wait, odp_event_t events[], int num)
Schedule multiple events.
void odp_schedule_config_init(odp_schedule_config_t *config)
Initialize schedule configuration options.
#define ODP_SCHED_NO_WAIT
Do not wait.
int odp_schedule_default_prio(void)
Default scheduling priority level.
int odp_schedule_config(const odp_schedule_config_t *config)
Global schedule configuration.
uint64_t odp_schedule_wait_time(uint64_t ns)
Schedule wait time.
odp_event_t odp_schedule(odp_queue_t *from, uint64_t wait)
Schedule an event.
#define ODP_SCHED_GROUP_ALL
Group of all threads.
int odp_shm_free(odp_shm_t shm)
Free a contiguous block of shared memory.
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
uint32_t odp_una_u32_t
Unaligned uint32_t type.
void odp_sys_info_print(void)
Print system info.
@ ODP_THREAD_WORKER
Worker thread.
@ ODP_THREAD_CONTROL
Control thread.
odp_time_t odp_time_local(void)
Current local time.
#define ODP_TIME_MSEC_IN_NS
A millisecond in nanoseconds.
uint64_t odp_time_diff_ns(odp_time_t t2, odp_time_t t1)
Time difference in nanoseconds.
The OpenDataPlane API.
Global initialization parameters.
odp_mem_model_t mem_model
Application memory model.
odp_feature_t not_used
Unused features.
Packet parse parameters.
odp_proto_chksums_t chksums
Flags to control payload data checksums checks up to the selected parse layer.
odp_proto_layer_t last_layer
Continue parsing until this layer.
odp_proto_t proto
Protocol header at parse starting point.
uint32_t max_num
Maximum number of buffers of any size.
uint32_t max_uarea_size
Maximum user area size in bytes.
struct odp_pool_capability_t::@119 pkt
Packet pool capabilities
uint32_t max_seg_len
Maximum packet segment data length in bytes.
uint32_t max_len
Maximum packet data length in bytes.
Pool parameters.
uint32_t uarea_size
Minimum user area size in bytes.
uint32_t num
Number of buffers in the pool.
uint32_t max_len
Maximum packet length that will be allocated from the pool.
uint32_t max_num
Maximum number of packets.
odp_pool_type_t type
Pool type.
struct odp_pool_param_t::@123 pkt
Parameters for packet pools.
uint32_t len
Minimum length of 'num' packets.
uint32_t seg_len
Minimum number of packet data bytes that can be stored in the first segment of a newly allocated pack...
ODP Queue parameters.
odp_schedule_param_t sched
Scheduler parameters.
uint32_t size
Queue size.
odp_queue_type_t type
Queue type.
Schedule configuration.
uint32_t num_queues
Maximum number of scheduled queues to be supported.
uint32_t queue_size
Maximum number of events required to be stored simultaneously in scheduled queue.
odp_schedule_group_t group
Thread group.
odp_schedule_prio_t prio
Priority level.
odp_schedule_sync_t sync
Synchronization method.
struct odp_feature_t::@145 feat
Individual feature bits.
uint32_t tm
Traffic Manager APIs, e.g., odp_tm_xxx()
uint32_t crypto
Crypto APIs, e.g., odp_crypto_xxx()
uint32_t ipsec
IPsec APIs, e.g., odp_ipsec_xxx()
uint32_t timer
Timer APIs, e.g., odp_timer_xxx(), odp_timeout_xxx()
uint32_t cls
Classifier APIs, e.g., odp_cls_xxx(), odp_cos_xxx()
uint32_t compress
Compression APIs, e.g., odp_comp_xxx()
uint32_t all_chksum
All checksum bits.