aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Uvarov <maxim.uvarov@linaro.org>2018-07-27 11:07:35 +0300
committerMaxim Uvarov <maxim.uvarov@linaro.org>2018-07-27 11:08:02 +0300
commitd0bd42aa817eb79dffeab77cbe3ea2ea6f5e3db4 (patch)
tree615d085aea5fee310b088e2b74344d3eb9c9f635
parent67acf499acbfb34d9c7dde2bc556db0eb76fb187 (diff)
parentba82f67d9286b8dc51b4f5d9c22aee29f7f6920b (diff)
downloadodp-dpdk-master.tar.gz
Merge branch 'dev/merge_master' of git://github.com/matiaselo/odp-dpdkHEADmaster
Merge and port odp-linux patches up to 6d91fe717 https://github.com/Linaro/odp-dpdk/pull/54 Reviewed-by: Bill Fischofer <bill.fischofer@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
-rw-r--r--.travis.yml4
-rw-r--r--config/odp-linux-dpdk.conf11
-rw-r--r--config/odp-linux-generic.conf11
-rw-r--r--configure.ac6
-rw-r--r--example/Makefile.am1
-rw-r--r--example/classifier/odp_classifier.c12
-rw-r--r--example/generator/odp_generator.c22
-rw-r--r--example/ipsec/odp_ipsec.c11
-rw-r--r--example/ipsec_api/odp_ipsec.c12
-rw-r--r--example/ipsec_offload/odp_ipsec_offload.c11
-rw-r--r--example/l3fwd/odp_l3fwd.c23
-rw-r--r--example/m4/configure.m41
-rw-r--r--example/packet/odp_pktio.c10
-rw-r--r--example/switch/odp_switch.c10
-rw-r--r--example/sysinfo/.gitignore3
-rw-r--r--example/sysinfo/Makefile.am9
-rw-r--r--example/sysinfo/odp_sysinfo.c449
-rw-r--r--example/timer/odp_timer_test.c13
-rw-r--r--include/odp/api/abi-default/thread.h2
-rw-r--r--platform/linux-dpdk/Makefile.am4
-rw-r--r--platform/linux-dpdk/include/odp_config_internal.h7
-rw-r--r--platform/linux-dpdk/odp_queue_basic.c80
-rw-r--r--platform/linux-dpdk/odp_queue_spsc.c2
-rw-r--r--platform/linux-generic/Makefile.am4
-rw-r--r--platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c212
-rw-r--r--platform/linux-generic/arch/default/odp_sysinfo_parse.c8
-rw-r--r--platform/linux-generic/arch/mips64/odp_sysinfo_parse.c4
-rw-r--r--platform/linux-generic/arch/powerpc/odp_sysinfo_parse.c4
-rw-r--r--platform/linux-generic/arch/x86/odp_sysinfo_parse.c30
-rw-r--r--platform/linux-generic/include/odp_config_internal.h5
-rw-r--r--platform/linux-generic/include/odp_global_data.h7
-rw-r--r--platform/linux-generic/include/odp_packet_io_ring_internal.h184
-rw-r--r--platform/linux-generic/include/odp_queue_basic_internal.h (renamed from platform/linux-generic/include/odp_queue_internal.h)11
-rw-r--r--platform/linux-generic/include/odp_ring_internal.h43
-rw-r--r--platform/linux-generic/include/odp_schedule_if.h6
-rw-r--r--platform/linux-generic/include/odp_sysinfo_internal.h1
-rw-r--r--platform/linux-generic/odp_crypto_openssl.c4
-rw-r--r--platform/linux-generic/odp_queue_basic.c84
-rw-r--r--platform/linux-generic/odp_queue_lf.c2
-rw-r--r--platform/linux-generic/odp_queue_spsc.c2
-rw-r--r--platform/linux-generic/odp_schedule_basic.c128
-rw-r--r--platform/linux-generic/odp_schedule_iquery.c13
-rw-r--r--platform/linux-generic/odp_schedule_sp.c10
-rw-r--r--platform/linux-generic/odp_system_info.c24
-rw-r--r--platform/linux-generic/pktio/ring.c189
-rw-r--r--platform/linux-generic/test/ring/ring_basic.c111
-rw-r--r--platform/linux-generic/test/ring/ring_suites.c1
-rw-r--r--platform/linux-generic/test/ring/ring_suites.h1
-rwxr-xr-xscripts/checkpatch.pl4
-rw-r--r--test/performance/.gitignore3
-rw-r--r--test/performance/Makefile.am8
-rw-r--r--test/performance/odp_cpu_bench.c813
-rw-r--r--test/performance/odp_l2fwd.c10
-rw-r--r--test/performance/odp_pktio_ordered.c16
-rw-r--r--test/performance/odp_pktio_perf.c9
-rw-r--r--test/performance/odp_pool_perf.c401
-rw-r--r--test/performance/odp_sched_latency.c7
-rw-r--r--test/performance/odp_sched_perf.c559
-rw-r--r--test/performance/odp_scheduling.c6
59 files changed, 2888 insertions, 750 deletions
diff --git a/.travis.yml b/.travis.yml
index 2018b542..36393236 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -148,6 +148,10 @@ before_install:
# Allow forwaring on virtual interfaces used for testing
- sudo iptables --policy FORWARD ACCEPT
+ # workaround for tap driver issues on recent Travis images
+ # Allow forwaring on virtual interfaces used for testing
+ - sudo iptables --policy FORWARD ACCEPT
+
install:
- if [ -z "$CROSS_ARCH" ] ;
then
diff --git a/config/odp-linux-dpdk.conf b/config/odp-linux-dpdk.conf
index 33296080..963ab97f 100644
--- a/config/odp-linux-dpdk.conf
+++ b/config/odp-linux-dpdk.conf
@@ -46,4 +46,15 @@ sched_basic: {
# uneven service level for low thread counts. Typically, optimal
# value is the number of threads using the scheduler.
prio_spread = 4
+
+ # Default burst sizes for high and low priority queues. The default
+ # and higher priority levels are considered as high. Scheduler
+ # rounds up number of requested events up to these values. In general,
+ # larger requests are not round down. So, larger bursts than these may
+ # received when requested. A large burst size improves throughput,
+ # but decreases application responsiveness to high priority events
+ # due to head of line blocking cause by a burst of low priority
+ # events.
+ burst_size_hi = 32
+ burst_size_low = 16
}
diff --git a/config/odp-linux-generic.conf b/config/odp-linux-generic.conf
index f5f21b45..85d5414b 100644
--- a/config/odp-linux-generic.conf
+++ b/config/odp-linux-generic.conf
@@ -55,4 +55,15 @@ sched_basic: {
# uneven service level for low thread counts. Typically, optimal
# value is the number of threads using the scheduler.
prio_spread = 4
+
+ # Default burst sizes for high and low priority queues. The default
+ # and higher priority levels are considered as high. Scheduler
+ # rounds up number of requested events up to these values. In general,
+ # larger requests are not round down. So, larger bursts than these may
+ # received when requested. A large burst size improves throughput,
+ # but decreases application responsiveness to high priority events
+ # due to head of line blocking cause by a burst of low priority
+ # events.
+ burst_size_hi = 32
+ burst_size_low = 16
}
diff --git a/configure.ac b/configure.ac
index d65bc0bb..0f17721f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -383,11 +383,13 @@ AC_MSG_RESULT([
includedir: ${includedir}
testdir: ${testdir}
WITH_ARCH: ${WITH_ARCH}
+ with_openssl: ${with_openssl}
cc: ${CC}
cc version: ${CC_VERSION}
cppflags: ${CPPFLAGS}
cflags: ${CFLAGS}
+ ld: ${LD}
ldflags: ${LDFLAGS}
libs: ${LIBS}
defs: ${DEFS}
@@ -407,3 +409,7 @@ AC_MSG_RESULT([
user_guides: ${user_guides}
pcapng: ${have_pcapng}
])
+
+AS_IF([test "${with_openssl}" = "no"],
+ [AC_MSG_WARN([Strong cryptography is not available without OpenSSL])]
+ )
diff --git a/example/Makefile.am b/example/Makefile.am
index 2ea244cf..0e12baf1 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -9,6 +9,7 @@ SUBDIRS = classifier \
l3fwd \
packet \
switch \
+ sysinfo \
time \
timer \
traffic_mgmt
diff --git a/example/classifier/odp_classifier.c b/example/classifier/odp_classifier.c
index 3afe7645..3403647b 100644
--- a/example/classifier/odp_classifier.c
+++ b/example/classifier/odp_classifier.c
@@ -20,7 +20,7 @@
/** @def MAX_WORKERS
* @brief Maximum number of worker threads
*/
-#define MAX_WORKERS 32
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/** @def SHM_PKT_POOL_SIZE
* @brief Size of the shared memory block
@@ -70,7 +70,7 @@ typedef struct {
int policy_count; /**< global policy count */
int appl_mode; /**< application mode */
odp_atomic_u64_t total_packets; /**< total received packets */
- int cpu_count; /**< Number of CPUs to use */
+ unsigned int cpu_count; /**< Number of CPUs to use */
uint32_t time; /**< Number of seconds to run */
char *if_name; /**< pointer to interface names */
} appl_args_t;
@@ -519,9 +519,8 @@ int main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), args);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (args->cpu_count)
+ if (args->cpu_count && args->cpu_count < MAX_WORKERS)
num_workers = args->cpu_count;
/* Get default worker cpumask */
@@ -807,6 +806,8 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ appl_args->cpu_count = 1; /* Use one worker by default */
+
while (1) {
opt = getopt_long(argc, argv, shortopts,
longopts, &long_index);
@@ -919,8 +920,7 @@ static void usage(char *progname)
"<mask bits> PMR mask bits to be applied on the PMR term value\n"
"\n"
"Optional OPTIONS\n"
- " -c, --count <number> CPU count.\n"
- " default: CPU core count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
"\n"
" -m, --mode 0: Packet Drop mode. Received packets will be dropped\n"
" !0: Packet ICMP mode. Received packets will be sent back\n"
diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index 1a6bb911..0785e3ec 100644
--- a/example/generator/odp_generator.c
+++ b/example/generator/odp_generator.c
@@ -22,7 +22,8 @@
#include <odp/helper/odph_api.h>
-#define MAX_WORKERS 32 /* Max number of workers */
+/* Max number of workers */
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
#define POOL_NUM_PKT 2048 /* Number of packets in packet pool */
#define POOL_PKT_LEN 1856 /* Max packet length */
#define DEFAULT_PKT_INTERVAL 1000 /* Interval between each packet */
@@ -1169,9 +1170,7 @@ int main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &args->appl);
- /* Default to max number of workers, unless user specified number of
- * workers or cpumask */
- num_workers = MAX_WORKERS;
+ num_workers = 1;
num_workers = odp_cpumask_default_worker(&cpumask, num_workers);
if (args->appl.num_workers) {
@@ -1580,6 +1579,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
appl_args->dstport_end = 0;
appl_args->csum = 0;
appl_args->sched = 0;
+ appl_args->num_workers = -1;
while (1) {
opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
@@ -1596,9 +1596,11 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
num_workers = odp_cpumask_default_worker(&cpumask, 0);
odp_cpumask_and(&cpumask_and, &cpumask_args, &cpumask);
if (odp_cpumask_count(&cpumask_and) <
- odp_cpumask_count(&cpumask_args)) {
+ odp_cpumask_count(&cpumask_args) ||
+ odp_cpumask_count(&cpumask_args) > MAX_WORKERS) {
EXAMPLE_ERR("Wrong cpu mask, max cpu's:%d\n",
- num_workers);
+ num_workers < MAX_WORKERS ?
+ num_workers : MAX_WORKERS);
exit(EXIT_FAILURE);
}
break;
@@ -1748,6 +1750,12 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
}
}
+ if (appl_args->num_workers < 0)
+ appl_args->num_workers = 0;
+ else if (appl_args->num_workers == 0 ||
+ appl_args->num_workers > MAX_WORKERS)
+ appl_args->num_workers = MAX_WORKERS;
+
if (appl_args->if_count == 0 || appl_args->mode == -1) {
usage(argv[0]);
exit(EXIT_FAILURE);
@@ -1834,7 +1842,7 @@ static void usage(char *progname)
" -i, --interval wait interval ms between sending each packet\n"
" default is 1000ms. 0 for flood mode\n"
" -w, --workers specify number of workers need to be assigned to application\n"
- " default is to assign all\n"
+ " default is 1, 0 for all available\n"
" -n, --count the number of packets to be send\n"
" -c, --cpumask to set on cores\n"
" -x, --udp_tx_burst size of UDP TX burst\n"
diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
index 1b21773e..2624af5d 100644
--- a/example/ipsec/odp_ipsec.c
+++ b/example/ipsec/odp_ipsec.c
@@ -63,13 +63,14 @@ static int create_stream_db_entry(char *input ODP_UNUSED)
}
#endif
-#define MAX_WORKERS 32 /**< maximum number of worker threads */
+/* maximum number of worker threads */
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/**
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count;
+ unsigned int cpu_count;
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
crypto_api_mode_e mode; /**< Crypto API preferred mode */
@@ -1247,9 +1248,8 @@ main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (args->appl.cpu_count)
+ if (args->appl.cpu_count && args->appl.cpu_count < MAX_WORKERS)
num_workers = args->appl.cpu_count;
/* Get default worker cpumask */
@@ -1398,6 +1398,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
printf("\nParsing command line options\n");
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->mode = 0; /* turn off async crypto API by default */
while (!rc) {
@@ -1568,7 +1569,7 @@ static void usage(char *progname)
" -a 192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n"
"\n"
"Optional OPTIONS\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -h, --help Display help and exit.\n"
" environment variables: ODP_IPSEC_USE_POLL_QUEUES\n"
" to enable use of poll queues instead of scheduled (default)\n"
diff --git a/example/ipsec_api/odp_ipsec.c b/example/ipsec_api/odp_ipsec.c
index 6142011b..f827eeeb 100644
--- a/example/ipsec_api/odp_ipsec.c
+++ b/example/ipsec_api/odp_ipsec.c
@@ -63,13 +63,14 @@ static int create_stream_db_entry(char *input ODP_UNUSED)
}
#endif
-#define MAX_WORKERS 32 /**< maximum number of worker threads */
+/* maximum number of worker threads */
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/**
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count;
+ unsigned int cpu_count;
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
odp_ipsec_op_mode_t mode; /**< IPsec operation mode */
@@ -945,9 +946,8 @@ main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (args->appl.cpu_count)
+ if (args->appl.cpu_count && args->appl.cpu_count < MAX_WORKERS)
num_workers = args->appl.cpu_count;
/* Get default worker cpumask */
@@ -1095,6 +1095,8 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ appl_args->cpu_count = 1; /* use one worker by default */
+
printf("\nParsing command line options\n");
while (!rc) {
@@ -1268,7 +1270,7 @@ static void usage(char *progname)
" -a 192.168.111.2:192.168.222.2:md5:201:a731649644c5dee92cbd9c2e7e188ee6\n"
"\n"
"Optional OPTIONS\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -h, --help Display help and exit.\n"
" environment variables: ODP_IPSEC_USE_POLL_QUEUES\n"
" to enable use of poll queues instead of scheduled (default)\n"
diff --git a/example/ipsec_offload/odp_ipsec_offload.c b/example/ipsec_offload/odp_ipsec_offload.c
index 890de682..63c8f126 100644
--- a/example/ipsec_offload/odp_ipsec_offload.c
+++ b/example/ipsec_offload/odp_ipsec_offload.c
@@ -45,13 +45,14 @@
#include <odp_ipsec_offload_fwd_db.h>
#include <odp_ipsec_offload_cache.h>
-#define MAX_WORKERS 32 /**< maximum number of worker threads */
+/* maximum number of worker threads */
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/**
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count;
+ unsigned int cpu_count;
int flows;
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
@@ -558,9 +559,8 @@ main(int argc, char *argv[])
if (odp_ipsec_config(&config))
EXAMPLE_ABORT("Error: IPSec not configured.\n");
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (args->appl.cpu_count && args->appl.cpu_count <= MAX_WORKERS)
+ if (args->appl.cpu_count && args->appl.cpu_count < MAX_WORKERS)
num_workers = args->appl.cpu_count;
/*
@@ -661,6 +661,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
{NULL, 0, NULL, 0}
};
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->flows = 1;
appl_args->queue_type = ODP_SCHED_SYNC_ATOMIC;
@@ -842,7 +843,7 @@ static void usage(char *progname)
"\n"
"Optional OPTIONS\n"
" -f, --flows <number> routes count.\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -q specify the queue type\n"
" 0: ODP_SCHED_SYNC_PARALLEL\n"
" 1: ODP_SCHED_SYNC_ATOMIC\n"
diff --git a/example/l3fwd/odp_l3fwd.c b/example/l3fwd/odp_l3fwd.c
index b12348cc..34e2bfce 100644
--- a/example/l3fwd/odp_l3fwd.c
+++ b/example/l3fwd/odp_l3fwd.c
@@ -23,7 +23,7 @@
#define POOL_SEG_LEN 1856
#define MAX_PKT_BURST 32
-#define MAX_NB_WORKER 32
+#define MAX_NB_WORKER (ODP_THREAD_COUNT_MAX - 1)
#define MAX_NB_PKTIO 32
#define MAX_NB_QUEUE 32
#define MAX_NB_QCONFS 1024
@@ -71,9 +71,9 @@ typedef struct {
char *if_names[MAX_NB_PKTIO];
int if_count;
char *route_str[MAX_NB_ROUTE];
- int worker_count;
+ unsigned int worker_count;
struct l3fwd_qconf_s qconf_config[MAX_NB_QCONFS];
- int qconf_count;
+ unsigned int qconf_count;
uint32_t duration; /* seconds to run */
uint8_t hash_mode; /* 1:hash, 0:lpm */
uint8_t dest_mac_changed[MAX_NB_PKTIO]; /* 1: dest mac from cmdline */
@@ -490,7 +490,7 @@ static void print_usage(char *progname)
" -d, --duration Seconds to run and print stats\n"
" optional, default as 0, run forever\n"
" -t, --thread Number of threads to do forwarding\n"
- " optional, default as availbe worker cpu count\n"
+ " 0=all available, default=1\n"
" -q, --queue Configure rx queue(s) for port\n"
" optional, format: [(port, queue, thread),...]\n"
" for example: -q '(0, 0, 1),(1,0,2)'\n"
@@ -507,7 +507,8 @@ static void parse_cmdline_args(int argc, char *argv[], app_args_t *args)
int long_index;
char *token, *local;
size_t len, route_index = 0;
- int i, mem_failure = 0;
+ int mem_failure = 0;
+ unsigned int i;
static struct option longopts[] = {
{"interface", required_argument, NULL, 'i'}, /* return 'i' */
@@ -521,6 +522,8 @@ static void parse_cmdline_args(int argc, char *argv[], app_args_t *args)
{NULL, 0, NULL, 0}
};
+ args->worker_count = 1; /* use one worker by default */
+
while (1) {
opt = getopt_long(argc, argv, "+s:t:d:i:r:q:e:h",
longopts, &long_index);
@@ -679,8 +682,8 @@ static void print_info(char *progname, app_args_t *args)
*/
static void setup_worker_qconf(app_args_t *args)
{
- int nb_worker, if_count, pktio;
- int i, j, rxq_idx;
+ int j, rxq_idx, pktio;
+ unsigned int i, nb_worker, if_count;
struct thread_arg_s *arg;
struct l3fwd_pktio_s *port;
uint8_t queue_mask[MAX_NB_PKTIO][MAX_NB_QUEUE];
@@ -841,7 +844,8 @@ static void setup_worker_qconf(app_args_t *args)
static void print_qconf_table(app_args_t *args)
{
- int i, j, k, qid, if_idx;
+ unsigned int i;
+ int j, k, qid, if_idx;
char buf[32];
struct thread_arg_s *thr_arg;
@@ -1038,9 +1042,8 @@ int main(int argc, char **argv)
setup_fwd_db();
dump_fwd_db();
- /* Dicide available workers */
nb_worker = MAX_NB_WORKER;
- if (args->worker_count)
+ if (args->worker_count && args->worker_count < MAX_NB_WORKER)
nb_worker = args->worker_count;
nb_worker = odp_cpumask_default_worker(&cpumask, nb_worker);
args->worker_count = nb_worker;
diff --git a/example/m4/configure.m4 b/example/m4/configure.m4
index 1ce0cb11..cbac0914 100644
--- a/example/m4/configure.m4
+++ b/example/m4/configure.m4
@@ -18,6 +18,7 @@ AC_CONFIG_FILES([example/classifier/Makefile
example/l3fwd/Makefile
example/packet/Makefile
example/switch/Makefile
+ example/sysinfo/Makefile
example/time/Makefile
example/timer/Makefile
example/traffic_mgmt/Makefile
diff --git a/example/packet/odp_pktio.c b/example/packet/odp_pktio.c
index fcce92b1..7755efcb 100644
--- a/example/packet/odp_pktio.c
+++ b/example/packet/odp_pktio.c
@@ -18,7 +18,7 @@
/** @def MAX_WORKERS
* @brief Maximum number of worker threads
*/
-#define MAX_WORKERS 32
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/** @def SHM_PKT_POOL_SIZE
* @brief Size of the shared memory block
@@ -63,7 +63,7 @@
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count; /**< Number of CPUs to use */
+ unsigned int cpu_count; /**< Number of CPUs to use */
int if_count; /**< Number of interfaces to be used */
char **if_names; /**< Array of pointers to interface names */
int mode; /**< Packet IO mode */
@@ -376,9 +376,8 @@ int main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (args->appl.cpu_count)
+ if (args->appl.cpu_count && args->appl.cpu_count < MAX_WORKERS)
num_workers = args->appl.cpu_count;
/* Get default worker cpumask */
@@ -572,6 +571,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->mode = APPL_MODE_PKT_SCHED;
appl_args->time = 0; /**< loop forever */
@@ -712,7 +712,7 @@ static void usage(char *progname)
" -i, --interface Eth interfaces (comma-separated, no spaces)\n"
"\n"
"Optional OPTIONS\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -t, --time <seconds> Number of seconds to run.\n"
" -m, --mode 0: Receive and send directly (no queues)\n"
" 1: Receive and send via queues.\n"
diff --git a/example/switch/odp_switch.c b/example/switch/odp_switch.c
index 26fcbbcc..18771ea4 100644
--- a/example/switch/odp_switch.c
+++ b/example/switch/odp_switch.c
@@ -14,7 +14,7 @@
#include <odp/helper/odph_api.h>
/** Maximum number of worker threads */
-#define MAX_WORKERS 32
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/** Size of the shared memory block */
#define SHM_PKT_POOL_SIZE 8192
@@ -52,7 +52,7 @@ typedef union {
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count; /**< Number of CPUs to be used */
+ unsigned int cpu_count; /**< Number of CPUs to be used */
unsigned if_count; /**< Number of interfaces to be used */
int num_workers; /**< Number of worker threads */
char **if_names; /**< Array of pointers to interface names */
@@ -725,7 +725,7 @@ static void usage(char *progname)
" Interface count min 2, max %i\n"
"\n"
"Optional OPTIONS:\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -t, --time <number> Time in seconds to run.\n"
" -a, --accuracy <number> Statistics print interval in seconds\n"
" (default is 10 second).\n"
@@ -762,6 +762,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->time = 0; /* loop forever if time to run is 0 */
appl_args->accuracy = 10; /* get and print pps stats second */
@@ -916,9 +917,8 @@ int main(int argc, char **argv)
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &gbl_args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (gbl_args->appl.cpu_count)
+ if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
num_workers = gbl_args->appl.cpu_count;
/* Get default worker cpumask */
diff --git a/example/sysinfo/.gitignore b/example/sysinfo/.gitignore
new file mode 100644
index 00000000..208e8dfc
--- /dev/null
+++ b/example/sysinfo/.gitignore
@@ -0,0 +1,3 @@
+odp_sysinfo
+*.log
+*.trs
diff --git a/example/sysinfo/Makefile.am b/example/sysinfo/Makefile.am
new file mode 100644
index 00000000..a8b55b5c
--- /dev/null
+++ b/example/sysinfo/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/example/Makefile.inc
+
+bin_PROGRAMS = odp_sysinfo
+
+odp_sysinfo_SOURCES = odp_sysinfo.c
+
+if test_example
+TESTS = odp_sysinfo
+endif
diff --git a/example/sysinfo/odp_sysinfo.c b/example/sysinfo/odp_sysinfo.c
new file mode 100644
index 00000000..120910b6
--- /dev/null
+++ b/example/sysinfo/odp_sysinfo.c
@@ -0,0 +1,449 @@
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <odp_api.h>
+
+#define KB 1024
+#define MB (1024 * 1024)
+#define MAX_HUGE_PAGES 32
+
+static const char *support_level(odp_support_t support)
+{
+ switch (support) {
+ case ODP_SUPPORT_NO: return "no";
+ case ODP_SUPPORT_YES: return "yes";
+ case ODP_SUPPORT_PREFERRED: return "yes, preferred";
+ default: return "UNKNOWN";
+ }
+}
+
+static const char *cipher_alg_name(odp_cipher_alg_t cipher)
+{
+ switch (cipher) {
+ case ODP_CIPHER_ALG_NULL:
+ return "null";
+ case ODP_CIPHER_ALG_DES:
+ return "des";
+ case ODP_CIPHER_ALG_3DES_CBC:
+ return "3des_cbc";
+ case ODP_CIPHER_ALG_AES_CBC:
+ return "aes_cbc";
+ case ODP_CIPHER_ALG_AES_CTR:
+ return "aes_ctr";
+ case ODP_CIPHER_ALG_AES_GCM:
+ return "aes_gcm";
+ case ODP_CIPHER_ALG_AES_CCM:
+ return "aes_ccm";
+ case ODP_CIPHER_ALG_CHACHA20_POLY1305:
+ return "chacha20_poly1305";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *auth_alg_name(odp_auth_alg_t auth)
+{
+ switch (auth) {
+ case ODP_AUTH_ALG_NULL:
+ return "null";
+ case ODP_AUTH_ALG_MD5_HMAC:
+ return "md5_hmac";
+ case ODP_AUTH_ALG_SHA1_HMAC:
+ return "sha1_hmac";
+ case ODP_AUTH_ALG_SHA256_HMAC:
+ return "sha256_hmac";
+ case ODP_AUTH_ALG_SHA384_HMAC:
+ return "sha384_hmac";
+ case ODP_AUTH_ALG_SHA512_HMAC:
+ return "sha512_hmac";
+ case ODP_AUTH_ALG_AES_XCBC_MAC:
+ return "aes_xcbc_mac";
+ case ODP_AUTH_ALG_AES_GCM:
+ return "aes_gcm";
+ case ODP_AUTH_ALG_AES_GMAC:
+ return "aes_gmac";
+ case ODP_AUTH_ALG_AES_CCM:
+ return "aes_ccm";
+ case ODP_AUTH_ALG_AES_CMAC:
+ return "aes_cmac";
+ case ODP_AUTH_ALG_CHACHA20_POLY1305:
+ return "chacha20_poly1305";
+ default:
+ return "Unknown";
+ }
+}
+
+static void print_cipher_algos(odp_crypto_cipher_algos_t ciphers)
+{
+ if (ciphers.bit.null)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_NULL));
+ if (ciphers.bit.des)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_DES));
+ if (ciphers.bit.trides_cbc)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_3DES_CBC));
+ if (ciphers.bit.aes_cbc)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_AES_CBC));
+ if (ciphers.bit.aes_ctr)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_AES_CTR));
+ if (ciphers.bit.aes_gcm)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_AES_GCM));
+ if (ciphers.bit.aes_ccm)
+ printf("%s ", cipher_alg_name(ODP_CIPHER_ALG_AES_CCM));
+ if (ciphers.bit.chacha20_poly1305)
+ printf("%s ",
+ cipher_alg_name(ODP_CIPHER_ALG_CHACHA20_POLY1305));
+}
+
+static void print_auth_algos(odp_crypto_auth_algos_t auths)
+{
+ if (auths.bit.null)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_NULL));
+ if (auths.bit.md5_hmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_MD5_HMAC));
+ if (auths.bit.sha1_hmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_SHA1_HMAC));
+ if (auths.bit.sha256_hmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_SHA256_HMAC));
+ if (auths.bit.sha384_hmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_SHA384_HMAC));
+ if (auths.bit.sha512_hmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_SHA512_HMAC));
+ if (auths.bit.aes_gcm)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_AES_GCM));
+ if (auths.bit.aes_gmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_AES_GMAC));
+ if (auths.bit.aes_ccm)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_AES_CCM));
+ if (auths.bit.aes_cmac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_AES_CMAC));
+ if (auths.bit.aes_xcbc_mac)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_AES_XCBC_MAC));
+ if (auths.bit.chacha20_poly1305)
+ printf("%s ", auth_alg_name(ODP_AUTH_ALG_CHACHA20_POLY1305));
+}
+
+static void print_cipher_capa(odp_cipher_alg_t cipher)
+{
+ int caps = odp_crypto_cipher_capability(cipher, NULL, 0);
+ int rc, i;
+
+ if (caps <= 0)
+ return;
+
+ odp_crypto_cipher_capability_t capa[caps];
+
+ rc = odp_crypto_cipher_capability(cipher, capa, caps);
+ if (rc < 0)
+ return;
+
+ printf(" %s:\n", cipher_alg_name(cipher));
+ for (i = 0; i < rc; i++)
+ printf(" key %d iv %d\n",
+ capa[i].key_len, capa[i].iv_len);
+}
+
+static void print_auth_capa(odp_auth_alg_t auth)
+{
+ int caps = odp_crypto_auth_capability(auth, NULL, 0);
+ int rc, i;
+
+ if (caps <= 0)
+ return;
+
+ odp_crypto_auth_capability_t capa[caps];
+
+ rc = odp_crypto_auth_capability(auth, capa, caps);
+ if (rc < 0)
+ return;
+
+ printf(" %s:\n", auth_alg_name(auth));
+ for (i = 0; i < rc; i++) {
+ printf(" digest %d", capa[i].digest_len);
+ if (capa[i].key_len != 0)
+ printf(" key %d", capa[i].key_len);
+ if (capa[i].iv_len != 0)
+ printf(" iv %d", capa[i].iv_len);
+ if (capa[i].aad_len.max != 0)
+ printf(" aad %d, %d, %d",
+ capa[i].aad_len.min, capa[i].aad_len.max,
+ capa[i].aad_len.inc);
+ printf("\n");
+ }
+}
+
+static void print_cipher_caps(odp_crypto_cipher_algos_t ciphers)
+{
+ if (ciphers.bit.null)
+ print_cipher_capa(ODP_CIPHER_ALG_NULL);
+ if (ciphers.bit.des)
+ print_cipher_capa(ODP_CIPHER_ALG_DES);
+ if (ciphers.bit.trides_cbc)
+ print_cipher_capa(ODP_CIPHER_ALG_3DES_CBC);
+ if (ciphers.bit.aes_cbc)
+ print_cipher_capa(ODP_CIPHER_ALG_AES_CBC);
+ if (ciphers.bit.aes_ctr)
+ print_cipher_capa(ODP_CIPHER_ALG_AES_CTR);
+ if (ciphers.bit.aes_gcm)
+ print_cipher_capa(ODP_CIPHER_ALG_AES_GCM);
+ if (ciphers.bit.aes_ccm)
+ print_cipher_capa(ODP_CIPHER_ALG_AES_CCM);
+ if (ciphers.bit.chacha20_poly1305)
+ print_cipher_capa(ODP_CIPHER_ALG_CHACHA20_POLY1305);
+}
+
+static void print_auth_caps(odp_crypto_auth_algos_t auths)
+{
+ if (auths.bit.null)
+ print_auth_capa(ODP_AUTH_ALG_NULL);
+ if (auths.bit.md5_hmac)
+ print_auth_capa(ODP_AUTH_ALG_MD5_HMAC);
+ if (auths.bit.sha1_hmac)
+ print_auth_capa(ODP_AUTH_ALG_SHA1_HMAC);
+ if (auths.bit.sha256_hmac)
+ print_auth_capa(ODP_AUTH_ALG_SHA256_HMAC);
+ if (auths.bit.sha384_hmac)
+ print_auth_capa(ODP_AUTH_ALG_SHA384_HMAC);
+ if (auths.bit.sha512_hmac)
+ print_auth_capa(ODP_AUTH_ALG_SHA512_HMAC);
+ if (auths.bit.aes_gcm)
+ print_auth_capa(ODP_AUTH_ALG_AES_GCM);
+ if (auths.bit.aes_gmac)
+ print_auth_capa(ODP_AUTH_ALG_AES_GMAC);
+ if (auths.bit.aes_ccm)
+ print_auth_capa(ODP_AUTH_ALG_AES_CCM);
+ if (auths.bit.aes_cmac)
+ print_auth_capa(ODP_AUTH_ALG_AES_CMAC);
+ if (auths.bit.aes_xcbc_mac)
+ print_auth_capa(ODP_AUTH_ALG_AES_XCBC_MAC);
+ if (auths.bit.chacha20_poly1305)
+ print_auth_capa(ODP_AUTH_ALG_CHACHA20_POLY1305);
+}
+
+int main(void)
+{
+ odp_instance_t inst;
+ int i, num_hp, num_hp_print;
+ int num_ava, num_work, num_ctrl;
+ odp_cpumask_t ava_mask, work_mask, ctrl_mask;
+ odp_shm_capability_t shm_capa;
+ odp_pool_capability_t pool_capa;
+ odp_queue_capability_t queue_capa;
+ odp_timer_capability_t timer_capa;
+ odp_crypto_capability_t crypto_capa;
+ uint64_t huge_page[MAX_HUGE_PAGES];
+ char ava_mask_str[ODP_CPUMASK_STR_SIZE];
+ char work_mask_str[ODP_CPUMASK_STR_SIZE];
+ char ctrl_mask_str[ODP_CPUMASK_STR_SIZE];
+
+ printf("\n");
+ printf("ODP system info example\n");
+ printf("***********************************************************\n");
+ printf("\n");
+
+ if (odp_init_global(&inst, NULL, NULL)) {
+ printf("Global init failed.\n");
+ return -1;
+ }
+
+ if (odp_init_local(inst, ODP_THREAD_CONTROL)) {
+ printf("Local init failed.\n");
+ return -1;
+ }
+
+ odp_sys_info_print();
+
+ memset(ava_mask_str, 0, ODP_CPUMASK_STR_SIZE);
+ num_ava = odp_cpumask_all_available(&ava_mask);
+ odp_cpumask_to_str(&ava_mask, ava_mask_str, ODP_CPUMASK_STR_SIZE);
+
+ memset(work_mask_str, 0, ODP_CPUMASK_STR_SIZE);
+ num_work = odp_cpumask_default_worker(&work_mask, 0);
+ odp_cpumask_to_str(&work_mask, work_mask_str, ODP_CPUMASK_STR_SIZE);
+
+ memset(ctrl_mask_str, 0, ODP_CPUMASK_STR_SIZE);
+ num_ctrl = odp_cpumask_default_control(&ctrl_mask, 0);
+ odp_cpumask_to_str(&ctrl_mask, ctrl_mask_str, ODP_CPUMASK_STR_SIZE);
+
+ num_hp = odp_sys_huge_page_size_all(huge_page, MAX_HUGE_PAGES);
+
+ num_hp_print = num_hp;
+ if (num_hp_print > MAX_HUGE_PAGES)
+ num_hp_print = MAX_HUGE_PAGES;
+
+ if (odp_shm_capability(&shm_capa)) {
+ printf("shm capability failed\n");
+ return -1;
+ }
+
+ if (odp_pool_capability(&pool_capa)) {
+ printf("pool capability failed\n");
+ return -1;
+ }
+
+ if (odp_queue_capability(&queue_capa)) {
+ printf("queue capability failed\n");
+ return -1;
+ }
+
+ if (odp_timer_capability(ODP_CLOCK_CPU, &timer_capa)) {
+ printf("timer capability failed\n");
+ return -1;
+ }
+
+ if (odp_crypto_capability(&crypto_capa)) {
+ printf("crypto capability failed\n");
+ return -1;
+ }
+
+ printf("\n");
+ printf("S Y S T E M I N F O R M A T I O N\n");
+ printf("***********************************************************\n");
+ printf("\n");
+ printf(" ODP API version: %s\n", odp_version_api_str());
+ printf(" ODP impl name: %s\n", odp_version_impl_name());
+ printf(" ODP impl details: %s\n", odp_version_impl_str());
+ printf(" CPU model: %s\n", odp_cpu_model_str());
+ printf(" CPU max freq: %" PRIu64 " hz\n", odp_cpu_hz_max());
+ printf(" Current CPU: %i\n", odp_cpu_id());
+ printf(" Current CPU freq: %" PRIu64 " hz\n", odp_cpu_hz());
+ printf(" CPU count: %i\n", odp_cpu_count());
+ printf(" CPU available num: %i\n", num_ava);
+ printf(" CPU available mask: %s\n", ava_mask_str);
+ printf(" CPU worker num: %i\n", num_work);
+ printf(" CPU worker mask: %s\n", work_mask_str);
+ printf(" CPU control num: %i\n", num_ctrl);
+ printf(" CPU control mask: %s\n", ctrl_mask_str);
+ printf(" Max threads (define): %i\n", ODP_THREAD_COUNT_MAX);
+ printf(" Max threads: %i\n", odp_thread_count_max());
+ printf(" Byte order: %s (%i / %i)\n",
+ ODP_BYTE_ORDER == ODP_BIG_ENDIAN ? "big" : "little",
+ ODP_BIG_ENDIAN, ODP_LITTLE_ENDIAN);
+ printf(" Bitfield order: %s (%i / %i)\n",
+ ODP_BITFIELD_ORDER == ODP_BIG_ENDIAN_BITFIELD ?
+ "big" : "little",
+ ODP_BIG_ENDIAN_BITFIELD, ODP_LITTLE_ENDIAN_BITFIELD);
+ printf(" Cache line size: %i B\n", odp_sys_cache_line_size());
+ printf(" Page size: %" PRIu64 " kB\n",
+ odp_sys_page_size() / KB);
+ printf(" Default huge page size: %" PRIu64 " kB\n",
+ odp_sys_huge_page_size() / KB);
+ printf(" Num huge page sizes: %i\n", num_hp);
+
+ for (i = 0; i < num_hp_print; i++)
+ printf(" Huge page size [%i]: %" PRIu64 " kB\n",
+ i, huge_page[i] / KB);
+
+ printf("\n");
+ printf(" SHM\n");
+ printf(" max_blocks: %u\n", shm_capa.max_blocks);
+ printf(" max_size: %" PRIu64 " MB\n",
+ shm_capa.max_size / MB);
+ printf(" max_align: %" PRIu64 " B\n", shm_capa.max_align);
+
+ printf("\n");
+ printf(" POOL\n");
+ printf(" max_pools: %u\n", pool_capa.max_pools);
+ printf(" buf.max_pools: %u\n", pool_capa.buf.max_pools);
+ printf(" buf.max_align: %" PRIu32 " B\n",
+ pool_capa.buf.max_align);
+ printf(" buf.max_size: %" PRIu32 " kB\n",
+ pool_capa.buf.max_size / KB);
+ printf(" buf.max_num: %" PRIu32 "\n",
+ pool_capa.buf.max_num);
+ printf(" pkt.max_pools: %u\n", pool_capa.pkt.max_pools);
+ printf(" pkt.max_len: %" PRIu32 " kB\n",
+ pool_capa.pkt.max_len / KB);
+ printf(" pkt.max_num: %" PRIu32 "\n",
+ pool_capa.pkt.max_num);
+ printf(" pkt.max_segs: %" PRIu32 "\n",
+ pool_capa.pkt.max_segs_per_pkt);
+ printf(" pkt.max_seg_len: %" PRIu32 " B\n",
+ pool_capa.pkt.max_seg_len);
+ printf(" pkt.max_uarea: %" PRIu32 " B\n",
+ pool_capa.pkt.max_uarea_size);
+ printf(" tmo.max_pools: %u\n", pool_capa.tmo.max_pools);
+ printf(" tmo.max_num: %" PRIu32 "\n",
+ pool_capa.tmo.max_num);
+
+ printf("\n");
+ printf(" QUEUE\n");
+ printf(" max queues: %" PRIu32 "\n",
+ queue_capa.max_queues);
+ printf(" plain.max_num: %" PRIu32 "\n",
+ queue_capa.plain.max_num);
+ printf(" plain.max_size: %" PRIu32 "\n",
+ queue_capa.plain.max_size);
+ printf(" plain.lf.max_num: %" PRIu32 "\n",
+ queue_capa.plain.lockfree.max_num);
+ printf(" plain.lf.max_size: %" PRIu32 "\n",
+ queue_capa.plain.lockfree.max_size);
+ printf(" plain.wf.max_num: %" PRIu32 "\n",
+ queue_capa.plain.waitfree.max_num);
+ printf(" plain.wf.max_size: %" PRIu32 "\n",
+ queue_capa.plain.waitfree.max_size);
+
+ printf("\n");
+ printf(" SCHEDULER\n");
+ printf(" max ordered locks: %" PRIu32 "\n",
+ queue_capa.max_ordered_locks);
+ printf(" max groups: %u\n", queue_capa.max_sched_groups);
+ printf(" priorities: %u\n", queue_capa.sched_prios);
+ printf(" sched.max_num: %" PRIu32 "\n",
+ queue_capa.sched.max_num);
+ printf(" sched.max_size: %" PRIu32 "\n",
+ queue_capa.sched.max_size);
+ printf(" sched.lf.max_num: %" PRIu32 "\n",
+ queue_capa.sched.lockfree.max_num);
+ printf(" sched.lf.max_size: %" PRIu32 "\n",
+ queue_capa.sched.lockfree.max_size);
+ printf(" sched.wf.max_num: %" PRIu32 "\n",
+ queue_capa.sched.waitfree.max_num);
+ printf(" sched.wf.max_size: %" PRIu32 "\n",
+ queue_capa.sched.waitfree.max_size);
+
+ printf("\n");
+ printf(" TIMER\n");
+ printf(" highest resolution: %" PRIu64 " nsec\n",
+ timer_capa.highest_res_ns);
+
+ printf("\n");
+ printf(" CRYPTO\n");
+ printf(" max sessions: %" PRIu32 "\n",
+ crypto_capa.max_sessions);
+ printf(" sync mode support: %s\n",
+ support_level(crypto_capa.sync_mode));
+ printf(" async mode support: %s\n",
+ support_level(crypto_capa.async_mode));
+ printf(" cipher algorithms: ");
+ print_cipher_algos(crypto_capa.ciphers);
+ printf("\n");
+ print_cipher_caps(crypto_capa.ciphers);
+ printf(" auth algorithms: ");
+ print_auth_algos(crypto_capa.auths);
+ printf("\n");
+ print_auth_caps(crypto_capa.auths);
+
+ printf("\n");
+ printf("***********************************************************\n");
+ printf("\n");
+
+ if (odp_term_local()) {
+ printf("Local term failed.\n");
+ return -1;
+ }
+
+ if (odp_term_global(inst)) {
+ printf("Global term failed.\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/example/timer/odp_timer_test.c b/example/timer/odp_timer_test.c
index 45eea792..9e431b47 100644
--- a/example/timer/odp_timer_test.c
+++ b/example/timer/odp_timer_test.c
@@ -19,15 +19,15 @@
/* GNU lib C */
#include <getopt.h>
-
-#define MAX_WORKERS 32 /**< Max worker threads */
+/* Max worker threads */
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
#define NUM_TMOS 10000 /**< Number of timers */
#define WAIT_NUM 10 /**< Max tries to rx last tmo per worker */
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/** Test arguments */
typedef struct {
- int cpu_count; /**< CPU count*/
+ unsigned int cpu_count; /**< CPU count*/
int resolution_us; /**< Timeout resolution in usec*/
int min_us; /**< Minimum timeout in usec*/
int max_us; /**< Maximum timeout in usec*/
@@ -237,7 +237,7 @@ static void print_usage(void)
{
printf("\n\nUsage: ./odp_example [options]\n");
printf("Options:\n");
- printf(" -c, --count <number> CPU count\n");
+ printf(" -c, --count <number> CPU count, 0=all available, default=1\n");
printf(" -r, --resolution <us> timeout resolution in usec\n");
printf(" -m, --min <us> minimum timeout in usec\n");
printf(" -x, --max <us> maximum timeout in usec\n");
@@ -280,7 +280,7 @@ static void parse_args(int argc, char *argv[], test_args_t *args)
/* defaults */
odp_timer_capability(ODP_CLOCK_CPU, &timer_capa);
- args->cpu_count = 0; /* all CPU's */
+ args->cpu_count = 1;
args->resolution_us = MAX(10000,
timer_capa.highest_res_ns /
ODP_TIME_USEC_IN_NS);
@@ -391,9 +391,8 @@ int main(int argc, char *argv[])
memset(thread_tbl, 0, sizeof(thread_tbl));
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (gbls->args.cpu_count)
+ if (gbls->args.cpu_count && gbls->args.cpu_count < MAX_WORKERS)
num_workers = gbls->args.cpu_count;
/* Get default worker cpumask */
diff --git a/include/odp/api/abi-default/thread.h b/include/odp/api/abi-default/thread.h
index 0420e245..e31651a2 100644
--- a/include/odp/api/abi-default/thread.h
+++ b/include/odp/api/abi-default/thread.h
@@ -21,7 +21,7 @@ extern "C" {
* @{
*/
-#define ODP_THREAD_COUNT_MAX 128
+#define ODP_THREAD_COUNT_MAX 256
/**
* @}
diff --git a/platform/linux-dpdk/Makefile.am b/platform/linux-dpdk/Makefile.am
index 62134db9..0b75c630 100644
--- a/platform/linux-dpdk/Makefile.am
+++ b/platform/linux-dpdk/Makefile.am
@@ -110,7 +110,7 @@ noinst_HEADERS = \
${top_srcdir}/platform/linux-generic/include/odp_pkt_queue_internal.h \
include/odp_pool_internal.h \
include/odp_posix_extensions.h \
- ${top_srcdir}/platform/linux-generic/include/odp_queue_internal.h \
+ ${top_srcdir}/platform/linux-generic/include/odp_queue_basic_internal.h \
${top_srcdir}/platform/linux-generic/include/odp_queue_if.h \
${top_srcdir}/platform/linux-generic/include/odp_queue_lf.h \
${top_srcdir}/platform/linux-generic/include/odp_ring_internal.h \
@@ -232,7 +232,7 @@ endif
if ARCH_IS_AARCH64
__LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \
arch/aarch64/odp_global_time.c \
- arch/default/odp_sysinfo_parse.c
+ arch/aarch64/odp_sysinfo_parse.c
odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \
arch/default/odp/api/abi/cpu_time.h
if !ODP_ABI_COMPAT
diff --git a/platform/linux-dpdk/include/odp_config_internal.h b/platform/linux-dpdk/include/odp_config_internal.h
index db24e6e2..b200f381 100644
--- a/platform/linux-dpdk/include/odp_config_internal.h
+++ b/platform/linux-dpdk/include/odp_config_internal.h
@@ -12,6 +12,11 @@ extern "C" {
#endif
/*
+ * Maximum number of CPUs supported. Maximum CPU ID is CONFIG_NUM_CPU - 1.
+ */
+#define CONFIG_NUM_CPU 256
+
+/*
* Maximum number of pools
*/
#define ODP_CONFIG_POOLS 256
@@ -117,7 +122,7 @@ extern "C" {
* This controls the burst size on various enqueue, dequeue, etc calls. Large
* burst size improves throughput, but may degrade QoS (increase latency).
*/
-#define CONFIG_BURST_SIZE 16
+#define CONFIG_BURST_SIZE 32
/*
* Maximum number of events in a pool
diff --git a/platform/linux-dpdk/odp_queue_basic.c b/platform/linux-dpdk/odp_queue_basic.c
index 1d20d5af..2a33e194 100644
--- a/platform/linux-dpdk/odp_queue_basic.c
+++ b/platform/linux-dpdk/odp_queue_basic.c
@@ -7,7 +7,7 @@
#include "config.h"
#include <odp/api/queue.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include <odp_queue_if.h>
#include <odp/api/std_types.h>
#include <odp/api/align.h>
@@ -341,7 +341,7 @@ static odp_queue_t queue_create(const char *name,
return handle;
}
-void sched_cb_queue_destroy_finalize(uint32_t queue_index)
+void sched_queue_destroy_finalize(uint32_t queue_index)
{
queue_entry_t *queue = qentry_from_index(queue_index);
@@ -354,7 +354,7 @@ void sched_cb_queue_destroy_finalize(uint32_t queue_index)
UNLOCK(queue);
}
-void sched_cb_queue_set_status(uint32_t queue_index, int status)
+void sched_queue_set_status(uint32_t queue_index, int status)
{
queue_entry_t *queue = qentry_from_index(queue_index);
@@ -538,40 +538,21 @@ static int queue_enq(odp_queue_t handle, odp_event_t ev)
return queue->s.enqueue(queue, (odp_buffer_hdr_t *)(uintptr_t)ev);
}
-static inline int deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[],
- int num, int update_status)
+static inline int plain_queue_deq(queue_entry_t *queue,
+ odp_buffer_hdr_t *buf_hdr[], int num)
{
- int status_sync = sched_fn->status_sync;
int num_deq;
LOCK(queue);
if (odp_unlikely(queue->s.status < QUEUE_STATUS_READY)) {
- /* Bad queue, or queue has been destroyed.
- * Scheduler finalizes queue destroy after this. */
+ /* Bad queue, or queue has been destroyed. */
UNLOCK(queue);
return -1;
}
num_deq = ring_st_deq_multi(queue->s.ring_st, (void **)buf_hdr, num);
- if (num_deq == 0) {
- /* Already empty queue */
- if (update_status && queue->s.status == QUEUE_STATUS_SCHED) {
- queue->s.status = QUEUE_STATUS_NOTSCHED;
-
- if (status_sync)
- sched_fn->unsched_queue(queue->s.index);
- }
-
- UNLOCK(queue);
-
- return 0;
- }
-
- if (status_sync && queue->s.type == ODP_QUEUE_TYPE_SCHED)
- sched_fn->save_context(queue->s.index);
-
UNLOCK(queue);
return num_deq;
@@ -582,7 +563,7 @@ static int queue_int_deq_multi(void *q_int, odp_buffer_hdr_t *buf_hdr[],
{
queue_entry_t *queue = q_int;
- return deq_multi(queue, buf_hdr, num, 0);
+ return plain_queue_deq(queue, buf_hdr, num);
}
static odp_buffer_hdr_t *queue_int_deq(void *q_int)
@@ -591,7 +572,7 @@ static odp_buffer_hdr_t *queue_int_deq(void *q_int)
odp_buffer_hdr_t *buf_hdr = NULL;
int ret;
- ret = deq_multi(queue, &buf_hdr, 1, 0);
+ ret = plain_queue_deq(queue, &buf_hdr, 1);
if (ret == 1)
return buf_hdr;
@@ -760,15 +741,50 @@ static int queue_info(odp_queue_t handle, odp_queue_info_t *info)
return 0;
}
-int sched_cb_queue_deq_multi(uint32_t queue_index, odp_event_t ev[], int num,
- int update_status)
+int sched_queue_deq(uint32_t queue_index, odp_event_t ev[], int max_num,
+ int update_status)
{
- queue_entry_t *qe = qentry_from_index(queue_index);
+ int num_deq;
+ ring_st_t ring_st;
+ queue_entry_t *queue = qentry_from_index(queue_index);
+ int status_sync = sched_fn->status_sync;
+
+ ring_st = queue->s.ring_st;
- return deq_multi(qe, (odp_buffer_hdr_t **)ev, num, update_status);
+ LOCK(queue);
+
+ if (odp_unlikely(queue->s.status < QUEUE_STATUS_READY)) {
+ /* Bad queue, or queue has been destroyed.
+ * Scheduler finalizes queue destroy after this. */
+ UNLOCK(queue);
+ return -1;
+ }
+
+ num_deq = ring_st_deq_multi(ring_st, (void **)ev, max_num);
+
+ if (num_deq == 0) {
+ /* Already empty queue */
+ if (update_status && queue->s.status == QUEUE_STATUS_SCHED) {
+ queue->s.status = QUEUE_STATUS_NOTSCHED;
+
+ if (status_sync)
+ sched_fn->unsched_queue(queue->s.index);
+ }
+
+ UNLOCK(queue);
+
+ return 0;
+ }
+
+ if (status_sync && queue->s.type == ODP_QUEUE_TYPE_SCHED)
+ sched_fn->save_context(queue->s.index);
+
+ UNLOCK(queue);
+
+ return num_deq;
}
-int sched_cb_queue_empty(uint32_t queue_index)
+int sched_queue_empty(uint32_t queue_index)
{
queue_entry_t *queue = qentry_from_index(queue_index);
int ret = 0;
diff --git a/platform/linux-dpdk/odp_queue_spsc.c b/platform/linux-dpdk/odp_queue_spsc.c
index 9ee6f5b0..89915eb9 100644
--- a/platform/linux-dpdk/odp_queue_spsc.c
+++ b/platform/linux-dpdk/odp_queue_spsc.c
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <odp/api/hints.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include "config.h"
#include <odp_debug_internal.h>
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index c6b5ac99..13101cfd 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -123,7 +123,7 @@ noinst_HEADERS = \
include/odp_pool_internal.h \
include/odp_posix_extensions.h \
include/odp_queue_if.h \
- include/odp_queue_internal.h \
+ include/odp_queue_basic_internal.h \
include/odp_queue_lf.h \
include/odp_queue_scalable_internal.h \
include/odp_ring_internal.h \
@@ -266,7 +266,7 @@ endif
if ARCH_IS_AARCH64
__LIB__libodp_linux_la_SOURCES += arch/default/odp_cpu_cycles.c \
arch/aarch64/odp_global_time.c \
- arch/default/odp_sysinfo_parse.c
+ arch/aarch64/odp_sysinfo_parse.c
odpapiabiarchinclude_HEADERS += arch/default/odp/api/abi/cpu_inlines.h \
arch/default/odp/api/abi/cpu_time.h
if !ODP_ABI_COMPAT
diff --git a/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c b/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c
new file mode 100644
index 00000000..85aec6a6
--- /dev/null
+++ b/platform/linux-generic/arch/aarch64/odp_sysinfo_parse.c
@@ -0,0 +1,212 @@
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <odp_sysinfo_internal.h>
+#include <odp_debug_internal.h>
+
+#define DUMMY_MAX_MHZ 1000
+#define TMP_STR_LEN 64
+
+static void aarch64_impl_str(char *str, int maxlen, int implementer)
+{
+ switch (implementer) {
+ case 0x41:
+ snprintf(str, maxlen, "ARM Limited");
+ return;
+ case 0x42:
+ snprintf(str, maxlen, "Broadcom Corporation");
+ return;
+ case 0x43:
+ snprintf(str, maxlen, "Cavium Inc.");
+ return;
+ case 0x44:
+ snprintf(str, maxlen, "Digital Equipment Corporation");
+ return;
+ case 0x49:
+ snprintf(str, maxlen, "Infineon Technologies AG");
+ return;
+ case 0x4d:
+ snprintf(str, maxlen, "Freescale Semiconductor Inc.");
+ return;
+ case 0x4e:
+ snprintf(str, maxlen, "NVIDIA Corporation");
+ return;
+ case 0x50:
+ snprintf(str, maxlen, "Applied Micro Circuits Corporation");
+ return;
+ case 0x51:
+ snprintf(str, maxlen, "Qualcomm Inc.");
+ return;
+ case 0x56:
+ snprintf(str, maxlen, "Marvell International Ltd.");
+ return;
+ case 0x69:
+ snprintf(str, maxlen, "Intel Corporation");
+ return;
+ default:
+ break;
+ }
+
+ snprintf(str, maxlen, "UNKNOWN (0x%x)", implementer);
+}
+
+static void aarch64_part_str(char *str, int maxlen, int implementer,
+ int part, int variant, int revision)
+{
+ if (implementer == 0x41) {
+ switch (part) {
+ case 0xd03:
+ snprintf(str, maxlen, "Cortex-A53");
+ return;
+ case 0xd05:
+ snprintf(str, maxlen, "Cortex-A55");
+ return;
+ case 0xd07:
+ snprintf(str, maxlen, "Cortex-A57");
+ return;
+ case 0xd08:
+ snprintf(str, maxlen, "Cortex-A72");
+ return;
+ case 0xd09:
+ snprintf(str, maxlen, "Cortex-A73");
+ return;
+ case 0xd0a:
+ snprintf(str, maxlen, "Cortex-A75");
+ return;
+ default:
+ break;
+ }
+ } else if (implementer == 0x43) {
+ switch (part) {
+ case 0xa1:
+ snprintf(str, maxlen, "CN88XX, Pass %i.%i",
+ variant + 1, revision);
+ return;
+ case 0xa2:
+ snprintf(str, maxlen, "CN81XX, Pass %i.%i",
+ variant + 1, revision);
+ return;
+ case 0xa3:
+ snprintf(str, maxlen, "CN83XX, Pass %i.%i",
+ variant + 1, revision);
+ return;
+ case 0xaf:
+ snprintf(str, maxlen, "CN99XX, Pass %i.%i",
+ variant + 1, revision);
+ return;
+ default:
+ break;
+ }
+ }
+
+ snprintf(str, maxlen, "part 0x%x, var 0x%x, rev 0x%x",
+ part, variant, revision);
+}
+
+int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
+{
+ char str[1024];
+ char impl_str[TMP_STR_LEN];
+ char part_str[TMP_STR_LEN];
+ const char *cur;
+ long int impl, arch, var, part, rev;
+ int id;
+
+ strcpy(sysinfo->cpu_arch_str, "aarch64");
+
+ memset(impl_str, 0, sizeof(impl_str));
+ memset(part_str, 0, sizeof(part_str));
+
+ impl = 0;
+ arch = 0;
+ var = 0;
+ part = 0;
+ rev = 0;
+ id = 0;
+
+ while (fgets(str, sizeof(str), file) != NULL && id < CONFIG_NUM_CPU) {
+ /* Parse line by line a block of cpuinfo */
+ cur = strstr(str, "CPU implementer");
+
+ if (cur) {
+ cur = strchr(cur, ':');
+ impl = strtol(cur + 1, NULL, 16);
+ aarch64_impl_str(impl_str, TMP_STR_LEN, impl);
+ continue;
+ }
+
+ cur = strstr(str, "CPU architecture");
+
+ if (cur) {
+ cur = strchr(cur, ':');
+ arch = strtol(cur + 1, NULL, 10);
+ continue;
+ }
+
+ cur = strstr(str, "CPU variant");
+
+ if (cur) {
+ cur = strchr(cur, ':');
+ var = strtol(cur + 1, NULL, 16);
+ continue;
+ }
+
+ cur = strstr(str, "CPU part");
+
+ if (cur) {
+ cur = strchr(cur, ':');
+ part = strtol(cur + 1, NULL, 16);
+ continue;
+ }
+
+ cur = strstr(str, "CPU revision");
+
+ if (cur) {
+ cur = strchr(cur, ':');
+ rev = strtol(cur + 1, NULL, 10);
+
+ aarch64_part_str(part_str, TMP_STR_LEN,
+ impl, part, var, rev);
+
+ /* This is the last line about this cpu, update
+ * model string. */
+ snprintf(sysinfo->model_str[id],
+ sizeof(sysinfo->model_str[id]),
+ "%s, %s, arch %li",
+ impl_str, part_str, arch);
+
+ /* Some CPUs do not support cpufreq, use a dummy
+ * max freq. */
+ if (sysinfo->cpu_hz_max[id] == 0) {
+ uint64_t hz = DUMMY_MAX_MHZ * 1000000;
+
+ ODP_PRINT("WARN: cpu[%i] uses dummy max frequency %u MHz\n",
+ id, DUMMY_MAX_MHZ);
+ sysinfo->cpu_hz_max[id] = hz;
+ }
+
+ id++;
+ }
+ }
+
+ return 0;
+}
+
+void sys_info_print_arch(void)
+{
+}
+
+uint64_t odp_cpu_arch_hz_current(int id)
+{
+ (void)id;
+
+ return 0;
+}
diff --git a/platform/linux-generic/arch/default/odp_sysinfo_parse.c b/platform/linux-generic/arch/default/odp_sysinfo_parse.c
index 49e94029..b9378887 100644
--- a/platform/linux-generic/arch/default/odp_sysinfo_parse.c
+++ b/platform/linux-generic/arch/default/odp_sysinfo_parse.c
@@ -10,13 +10,17 @@
#include <odp_debug_internal.h>
#include <string.h>
+#define DUMMY_MAX_MHZ 1400
+
int cpuinfo_parser(FILE *file ODP_UNUSED, system_info_t *sysinfo)
{
int i;
ODP_DBG("Warning: use dummy values for freq and model string\n");
- for (i = 0; i < MAX_CPU_NUMBER; i++) {
- sysinfo->cpu_hz_max[i] = 1400000000;
+ for (i = 0; i < CONFIG_NUM_CPU; i++) {
+ ODP_PRINT("WARN: cpu[%i] uses dummy max frequency %u MHz\n",
+ i, DUMMY_MAX_MHZ);
+ sysinfo->cpu_hz_max[i] = DUMMY_MAX_MHZ * 1000000;
strcpy(sysinfo->model_str[i], "UNKNOWN");
}
diff --git a/platform/linux-generic/arch/mips64/odp_sysinfo_parse.c b/platform/linux-generic/arch/mips64/odp_sysinfo_parse.c
index 339c6749..7b313b6d 100644
--- a/platform/linux-generic/arch/mips64/odp_sysinfo_parse.c
+++ b/platform/linux-generic/arch/mips64/odp_sysinfo_parse.c
@@ -20,7 +20,7 @@ int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
int id = 0;
strcpy(sysinfo->cpu_arch_str, "mips64");
- while (fgets(str, sizeof(str), file) != NULL && id < MAX_CPU_NUMBER) {
+ while (fgets(str, sizeof(str), file) != NULL && id < CONFIG_NUM_CPU) {
if (!mhz) {
pos = strstr(str, "BogoMIPS");
@@ -41,7 +41,7 @@ int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
pos = strchr(str, ':');
strncpy(sysinfo->model_str[id], pos + 2,
- sizeof(sysinfo->model_str[id]) - 1);
+ MODEL_STR_SIZE - 1);
len = strlen(sysinfo->model_str[id]);
sysinfo->model_str[id][len - 1] = 0;
model = 1;
diff --git a/platform/linux-generic/arch/powerpc/odp_sysinfo_parse.c b/platform/linux-generic/arch/powerpc/odp_sysinfo_parse.c
index 810f3758..1fb1b4a3 100644
--- a/platform/linux-generic/arch/powerpc/odp_sysinfo_parse.c
+++ b/platform/linux-generic/arch/powerpc/odp_sysinfo_parse.c
@@ -20,7 +20,7 @@ int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
int id = 0;
strcpy(sysinfo->cpu_arch_str, "powerpc");
- while (fgets(str, sizeof(str), file) != NULL && id < MAX_CPU_NUMBER) {
+ while (fgets(str, sizeof(str), file) != NULL && id < CONFIG_NUM_CPU) {
if (!mhz) {
pos = strstr(str, "clock");
@@ -40,7 +40,7 @@ int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
pos = strchr(str, ':');
strncpy(sysinfo->model_str[id], pos + 2,
- sizeof(sysinfo->model_str[id]) - 1);
+ MODEL_STR_SIZE - 1);
len = strlen(sysinfo->model_str[id]);
sysinfo->model_str[id][len - 1] = 0;
model = 1;
diff --git a/platform/linux-generic/arch/x86/odp_sysinfo_parse.c b/platform/linux-generic/arch/x86/odp_sysinfo_parse.c
index d9f3a82d..504aa3ef 100644
--- a/platform/linux-generic/arch/x86/odp_sysinfo_parse.c
+++ b/platform/linux-generic/arch/x86/odp_sysinfo_parse.c
@@ -13,26 +13,34 @@
int cpuinfo_parser(FILE *file, system_info_t *sysinfo)
{
char str[1024];
- char *pos;
+ char *pos, *pos_end;
double ghz = 0.0;
uint64_t hz;
int id = 0;
strcpy(sysinfo->cpu_arch_str, "x86");
- while (fgets(str, sizeof(str), file) != NULL && id < MAX_CPU_NUMBER) {
+ while (fgets(str, sizeof(str), file) != NULL && id < CONFIG_NUM_CPU) {
pos = strstr(str, "model name");
if (pos) {
- pos = strchr(str, ':');
+ /* Copy model name between : and @ characters */
+ pos = strchr(str, ':');
+ pos_end = strchr(str, '@');
+ if (pos == NULL || pos_end == NULL)
+ continue;
+
+ *(pos_end - 1) = '\0';
strncpy(sysinfo->model_str[id], pos + 2,
- sizeof(sysinfo->model_str[id]) - 1);
+ MODEL_STR_SIZE - 1);
+
+ if (sysinfo->cpu_hz_max[id]) {
+ id++;
+ continue;
+ }
- pos = strchr(sysinfo->model_str[id], '@');
- if (pos) {
- *(pos - 1) = '\0';
- if (sscanf(pos, "@ %lfGHz", &ghz) == 1) {
- hz = (uint64_t)(ghz * 1000000000.0);
- sysinfo->cpu_hz_max[id] = hz;
- }
+ /* max frequency needs to be set */
+ if (sscanf(pos_end, "@ %lfGHz", &ghz) == 1) {
+ hz = (uint64_t)(ghz * 1000000000.0);
+ sysinfo->cpu_hz_max[id] = hz;
}
id++;
}
diff --git a/platform/linux-generic/include/odp_config_internal.h b/platform/linux-generic/include/odp_config_internal.h
index d579381e..14fa4f6c 100644
--- a/platform/linux-generic/include/odp_config_internal.h
+++ b/platform/linux-generic/include/odp_config_internal.h
@@ -12,6 +12,11 @@ extern "C" {
#endif
/*
+ * Maximum number of CPUs supported. Maximum CPU ID is CONFIG_NUM_CPU - 1.
+ */
+#define CONFIG_NUM_CPU 256
+
+/*
* Maximum number of pools
*/
#define ODP_CONFIG_POOLS 64
diff --git a/platform/linux-generic/include/odp_global_data.h b/platform/linux-generic/include/odp_global_data.h
index a9eccc2b..1ddc49ea 100644
--- a/platform/linux-generic/include/odp_global_data.h
+++ b/platform/linux-generic/include/odp_global_data.h
@@ -18,17 +18,18 @@ extern "C" {
#include <pthread.h>
#include <stdint.h>
#include <libconfig.h>
+#include <odp_config_internal.h>
-#define MAX_CPU_NUMBER 128
+#define MODEL_STR_SIZE 128
#define UID_MAXLEN 30
typedef struct {
- uint64_t cpu_hz_max[MAX_CPU_NUMBER];
+ uint64_t cpu_hz_max[CONFIG_NUM_CPU];
uint64_t page_size;
int cache_line_size;
int cpu_count;
char cpu_arch_str[128];
- char model_str[MAX_CPU_NUMBER][128];
+ char model_str[CONFIG_NUM_CPU][MODEL_STR_SIZE];
} system_info_t;
typedef struct {
diff --git a/platform/linux-generic/include/odp_packet_io_ring_internal.h b/platform/linux-generic/include/odp_packet_io_ring_internal.h
index e459e3a5..889a6559 100644
--- a/platform/linux-generic/include/odp_packet_io_ring_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_ring_internal.h
@@ -133,8 +133,6 @@ typedef struct _ring {
/** @private Producer */
struct ODP_ALIGNED_CACHE _prod {
- uint32_t watermark; /* Maximum items */
- uint32_t sp_enqueue; /* True, if single producer. */
uint32_t size; /* Size of ring. */
uint32_t mask; /* Mask (size-1) of ring. */
volatile uint32_t head; /* Producer head. */
@@ -143,7 +141,6 @@ typedef struct _ring {
/** @private Consumer */
struct ODP_ALIGNED_CACHE _cons {
- uint32_t sc_dequeue; /* True, if single consumer. */
uint32_t size; /* Size of the ring. */
uint32_t mask; /* Mask (size-1) of ring. */
volatile uint32_t head; /* Consumer head. */
@@ -163,8 +160,6 @@ typedef struct _ring {
#define _RING_SHM_PROC (1 << 2)
/* Do not link ring to linked list. */
#define _RING_NO_LIST (1 << 3)
-/* Quota exceed for burst ops */
-#define _RING_QUOT_EXCEED (1 << 31)
/* Ring size mask */
#define _RING_SZ_MASK (unsigned)(0x0fffffff)
@@ -172,9 +167,8 @@ typedef struct _ring {
* Create a new ring named *name* in memory.
*
* This function uses odp_shm_reserve() to allocate memory. Its size is
- * set to *count*, which must be a power of two. Water marking is
- * disabled by default. Note that the real usable ring size is count-1
- * instead of count.
+ * set to *count*, which must be a power of two. Note that the real usable
+ * ring size is count-1 instead of count.
*
* @param name
* The name of the ring.
@@ -208,23 +202,6 @@ _ring_t *_ring_create(const char *name, unsigned count,
int _ring_destroy(const char *name);
/**
- * Change the high water mark.
- *
- * If *count* is 0, water marking is disabled. Otherwise, it is set to the
- * *count* value. The *count* value must be greater than 0 and less
- * than the ring size.
- *
- * This function can be called at any time (not necessarily at
- * initialization).
- *
- * @param r Pointer to the ring structure.
- * @param count New water mark value.
- * @return 0: Success; water mark changed.
- * -EINVAL: Invalid water mark value.
- */
-int _ring_set_water_mark(_ring_t *r, unsigned count);
-
-/**
* Dump the status of the ring to the console.
*
* @param r A pointer to the ring structure.
@@ -250,8 +227,6 @@ void _ring_dump(const _ring_t *r);
* Depend on the behavior value
* if behavior = ODPH_RING_QUEUE_FIXED
* - 0: Success; objects enqueue.
- * - -EDQUOT: Quota exceeded. The objects have been enqueued, but the
- * high water mark is exceeded.
* - -ENOBUFS: Not enough room in the ring to enqueue, no object is enqueued.
* if behavior = ODPH_RING_QUEUE_VARIABLE
* - n: Actual number of objects enqueued.
@@ -261,32 +236,6 @@ int ___ring_mp_do_enqueue(_ring_t *r, void * const *obj_table,
enum _ring_queue_behavior behavior);
/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects).
- * @param n
- * The number of objects to add in the ring from the obj_table.
- * @param behavior
- * ODPH_RING_QUEUE_FIXED: Enqueue a fixed number of items from a ring
- * ODPH_RING_QUEUE_VARIABLE: Enqueue as many items a possible from ring
- * @return
- * Depend on the behavior value
- * if behavior = ODPH_RING_QUEUE_FIXED
- * - 0: Success; objects enqueue.
- * - -EDQUOT: Quota exceeded. The objects have been enqueued, but the
- * high water mark is exceeded.
- * - -ENOBUFS: Not enough room in the ring to enqueue, no object is enqueued.
- * if behavior = ODPH_RING_QUEUE_VARIABLE
- * - n: Actual number of objects enqueued.
- */
-int ___ring_sp_do_enqueue(_ring_t *r, void * const *obj_table,
- unsigned n,
- enum _ring_queue_behavior behavior);
-
-/**
* Dequeue several objects from a ring (multi-consumers safe). When
* the request objects are more than the available objects, only dequeue the
* actual number of objects
@@ -318,33 +267,6 @@ int ___ring_mc_do_dequeue(_ring_t *r, void **obj_table,
enum _ring_queue_behavior behavior);
/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).
- * When the request objects are more than the available objects, only dequeue
- * the actual number of objects
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects) that will be filled.
- * @param n
- * The number of objects to dequeue from the ring to the obj_table.
- * @param behavior
- * ODPH_RING_QUEUE_FIXED: Dequeue a fixed number of items from a ring
- * ODPH_RING_QUEUE_VARIABLE: Dequeue as many items a possible from ring
- * @return
- * Depend on the behavior value
- * if behavior = ODPH_RING_QUEUE_FIXED
- * - 0: Success; objects dequeued.
- * - -ENOENT: Not enough entries in the ring to dequeue; no object is
- * dequeued.
- * if behavior = ODPH_RING_QUEUE_VARIABLE
- * - n: Actual number of objects dequeued.
- */
-int ___ring_sc_do_dequeue(_ring_t *r, void **obj_table,
- unsigned n,
- enum _ring_queue_behavior behavior);
-
-/**
* Enqueue several objects on the ring (multi-producers safe).
*
* This function uses a "compare and set" instruction to move the
@@ -366,24 +288,6 @@ int _ring_mp_enqueue_bulk(_ring_t *r, void * const *obj_table,
unsigned n);
/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects).
- * @param n
- * The number of objects to add in the ring from the obj_table.
- * @return
- * - 0: Success; objects enqueued.
- * - -EDQUOT: Quota exceeded. The objects have been enqueued, but the
- * high water mark is exceeded.
- * - -ENOBUFS: Not enough room in the ring to enqueue; no object is enqueued.
- */
-int _ring_sp_enqueue_bulk(_ring_t *r, void * const *obj_table,
- unsigned n);
-
-/**
* Dequeue several objects from a ring (multi-consumers safe).
*
* This function uses a "compare and set" instruction to move the
@@ -403,23 +307,6 @@ int _ring_sp_enqueue_bulk(_ring_t *r, void * const *obj_table,
int _ring_mc_dequeue_bulk(_ring_t *r, void **obj_table, unsigned n);
/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects) that will be filled.
- * @param n
- * The number of objects to dequeue from the ring to the obj_table,
- * must be strictly positive.
- * @return
- * - 0: Success; objects dequeued.
- * - -ENOENT: Not enough entries in the ring to dequeue; no object is
- * dequeued.
- */
-int _ring_sc_dequeue_bulk(_ring_t *r, void **obj_table, unsigned n);
-
-/**
* Test if a ring is full.
*
* @param r
@@ -487,39 +374,6 @@ int _ring_mp_enqueue_burst(_ring_t *r, void * const *obj_table,
unsigned n);
/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects).
- * @param n
- * The number of objects to add in the ring from the obj_table.
- * @return
- * - n: Actual number of objects enqueued.
- */
-int _ring_sp_enqueue_burst(_ring_t *r, void * const *obj_table,
- unsigned n);
-/**
- * Enqueue several objects on a ring.
- *
- * This function calls the multi-producer or the single-producer
- * version depending on the default behavior that was specified at
- * ring creation time (see flags).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects).
- * @param n
- * The number of objects to add in the ring from the obj_table.
- * @return
- * - n: Actual number of objects enqueued.
- */
-int _ring_enqueue_burst(_ring_t *r, void * const *obj_table,
- unsigned n);
-
-/**
* Dequeue several objects from a ring (multi-consumers safe). When the request
* objects are more than the available objects, only dequeue the actual number
* of objects
@@ -539,40 +393,6 @@ int _ring_enqueue_burst(_ring_t *r, void * const *obj_table,
int _ring_mc_dequeue_burst(_ring_t *r, void **obj_table, unsigned n);
/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).When the
- * request objects are more than the available objects, only dequeue the
- * actual number of objects
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects) that will be filled.
- * @param n
- * The number of objects to dequeue from the ring to the obj_table.
- * @return
- * - n: Actual number of objects dequeued, 0 if ring is empty
- */
-int _ring_sc_dequeue_burst(_ring_t *r, void **obj_table, unsigned n);
-
-/**
- * Dequeue multiple objects from a ring up to a maximum number.
- *
- * This function calls the multi-consumers or the single-consumer
- * version, depending on the default behaviour that was specified at
- * ring creation time (see flags).
- *
- * @param r
- * A pointer to the ring structure.
- * @param obj_table
- * A pointer to a table of void * pointers (objects) that will be filled.
- * @param n
- * The number of objects to dequeue from the ring to the obj_table.
- * @return
- * - Number of objects dequeued, or a negative error code on error
- */
-int _ring_dequeue_burst(_ring_t *r, void **obj_table, unsigned n);
-
-/**
* dump the status of all rings on the console
*/
void _ring_list_dump(void);
diff --git a/platform/linux-generic/include/odp_queue_internal.h b/platform/linux-generic/include/odp_queue_basic_internal.h
index bb74f729..654b9e31 100644
--- a/platform/linux-generic/include/odp_queue_internal.h
+++ b/platform/linux-generic/include/odp_queue_basic_internal.h
@@ -4,8 +4,8 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
-#ifndef ODP_QUEUE_INTERNAL_H_
-#define ODP_QUEUE_INTERNAL_H_
+#ifndef ODP_QUEUE_BASIC_INTERNAL_H_
+#define ODP_QUEUE_BASIC_INTERNAL_H_
#ifdef __cplusplus
extern "C" {
@@ -98,6 +98,13 @@ static inline odp_queue_t queue_from_index(uint32_t queue_id)
void queue_spsc_init(queue_entry_t *queue, uint32_t queue_size);
+/* Functions for schedulers */
+void sched_queue_destroy_finalize(uint32_t queue_index);
+void sched_queue_set_status(uint32_t queue_index, int status);
+int sched_queue_deq(uint32_t queue_index, odp_event_t ev[], int num,
+ int update_status);
+int sched_queue_empty(uint32_t queue_index);
+
#ifdef __cplusplus
}
#endif
diff --git a/platform/linux-generic/include/odp_ring_internal.h b/platform/linux-generic/include/odp_ring_internal.h
index 130d74cc..97673bef 100644
--- a/platform/linux-generic/include/odp_ring_internal.h
+++ b/platform/linux-generic/include/odp_ring_internal.h
@@ -36,7 +36,6 @@ typedef struct ODP_ALIGNED_CACHE {
/* Reader head and tail */
odp_atomic_u32_t r_head;
- odp_atomic_u32_t r_tail;
uint32_t data[0];
} ring_t;
@@ -57,14 +56,12 @@ static inline void ring_init(ring_t *ring)
odp_atomic_init_u32(&ring->w_head, 0);
odp_atomic_init_u32(&ring->w_tail, 0);
odp_atomic_init_u32(&ring->r_head, 0);
- odp_atomic_init_u32(&ring->r_tail, 0);
}
/* Dequeue data from the ring head */
static inline uint32_t ring_deq(ring_t *ring, uint32_t mask)
{
uint32_t head, tail, new_head;
- uint32_t data;
/* Load/CAS acquire of r_head ensures that w_tail load happens after
* r_head load, and thus head value is always behind or equal to tail
@@ -81,20 +78,12 @@ static inline uint32_t ring_deq(ring_t *ring, uint32_t mask)
new_head = head + 1;
} while (odp_unlikely(cas_mo_u32(&ring->r_head, &head, new_head,
- __ATOMIC_ACQUIRE,
+ __ATOMIC_ACQ_REL,
__ATOMIC_ACQUIRE) == 0));
- /* Read queue index */
- data = ring->data[new_head & mask];
-
- /* Wait until other readers have updated the tail */
- while (odp_unlikely(odp_atomic_load_acq_u32(&ring->r_tail) != head))
- odp_cpu_pause();
-
- /* Now update the reader tail */
- odp_atomic_store_rel_u32(&ring->r_tail, new_head);
-
- return data;
+ /* Read data. CAS acquire-release ensures that data read
+ * does not move above from here. */
+ return ring->data[new_head & mask];
}
/* Dequeue multiple data from the ring head. Num is smaller than ring size. */
@@ -123,20 +112,14 @@ static inline uint32_t ring_deq_multi(ring_t *ring, uint32_t mask,
new_head = head + num;
} while (odp_unlikely(cas_mo_u32(&ring->r_head, &head, new_head,
- __ATOMIC_ACQUIRE,
+ __ATOMIC_ACQ_REL,
__ATOMIC_ACQUIRE) == 0));
- /* Read queue index */
+ /* Read data. CAS acquire-release ensures that data read
+ * does not move above from here. */
for (i = 0; i < num; i++)
data[i] = ring->data[(head + 1 + i) & mask];
- /* Wait until other readers have updated the tail */
- while (odp_unlikely(odp_atomic_load_acq_u32(&ring->r_tail) != head))
- odp_cpu_pause();
-
- /* Now update the reader tail */
- odp_atomic_store_rel_u32(&ring->r_tail, new_head);
-
return num;
}
@@ -149,10 +132,6 @@ static inline void ring_enq(ring_t *ring, uint32_t mask, uint32_t data)
old_head = odp_atomic_fetch_inc_u32(&ring->w_head);
new_head = old_head + 1;
- /* Ring is full. Wait for the last reader to finish. */
- while (odp_unlikely(odp_atomic_load_acq_u32(&ring->r_tail) == new_head))
- odp_cpu_pause();
-
/* Write data */
ring->data[new_head & mask] = data;
@@ -160,7 +139,7 @@ static inline void ring_enq(ring_t *ring, uint32_t mask, uint32_t data)
while (odp_unlikely(odp_atomic_load_acq_u32(&ring->w_tail) != old_head))
odp_cpu_pause();
- /* Now update the writer tail */
+ /* Release the new writer tail, readers acquire it. */
odp_atomic_store_rel_u32(&ring->w_tail, new_head);
}
@@ -174,10 +153,6 @@ static inline void ring_enq_multi(ring_t *ring, uint32_t mask, uint32_t data[],
old_head = odp_atomic_fetch_add_u32(&ring->w_head, num);
new_head = old_head + 1;
- /* Ring is full. Wait for the last reader to finish. */
- while (odp_unlikely(odp_atomic_load_acq_u32(&ring->r_tail) == new_head))
- odp_cpu_pause();
-
/* Write data */
for (i = 0; i < num; i++)
ring->data[(new_head + i) & mask] = data[i];
@@ -186,7 +161,7 @@ static inline void ring_enq_multi(ring_t *ring, uint32_t mask, uint32_t data[],
while (odp_unlikely(odp_atomic_load_acq_u32(&ring->w_tail) != old_head))
odp_cpu_pause();
- /* Now update the writer tail */
+ /* Release the new writer tail, readers acquire it. */
odp_atomic_store_rel_u32(&ring->w_tail, old_head + num);
}
diff --git a/platform/linux-generic/include/odp_schedule_if.h b/platform/linux-generic/include/odp_schedule_if.h
index 0d095262..8f082aaa 100644
--- a/platform/linux-generic/include/odp_schedule_if.h
+++ b/platform/linux-generic/include/odp_schedule_if.h
@@ -82,12 +82,6 @@ int sched_cb_pktin_poll(int pktio_index, int pktin_index,
int sched_cb_pktin_poll_old(int pktio_index, int num_queue, int index[]);
int sched_cb_pktin_poll_one(int pktio_index, int rx_queue, odp_event_t evts[]);
void sched_cb_pktio_stop_finalize(int pktio_index);
-odp_queue_t sched_cb_queue_handle(uint32_t queue_index);
-void sched_cb_queue_destroy_finalize(uint32_t queue_index);
-void sched_cb_queue_set_status(uint32_t queue_index, int status);
-int sched_cb_queue_deq_multi(uint32_t queue_index, odp_event_t ev[], int num,
- int update_status);
-int sched_cb_queue_empty(uint32_t queue_index);
/* API functions */
typedef struct {
diff --git a/platform/linux-generic/include/odp_sysinfo_internal.h b/platform/linux-generic/include/odp_sysinfo_internal.h
index d34087e2..2f01d18e 100644
--- a/platform/linux-generic/include/odp_sysinfo_internal.h
+++ b/platform/linux-generic/include/odp_sysinfo_internal.h
@@ -14,7 +14,6 @@ extern "C" {
#include <odp_global_data.h>
int cpuinfo_parser(FILE *file, system_info_t *sysinfo);
-uint64_t odp_cpufreq_id(const char *filename, int id);
uint64_t odp_cpu_hz_current(int id);
uint64_t odp_cpu_arch_hz_current(int id);
void sys_info_print_arch(void);
diff --git a/platform/linux-generic/odp_crypto_openssl.c b/platform/linux-generic/odp_crypto_openssl.c
index 8473bf5a..ecab6bd0 100644
--- a/platform/linux-generic/odp_crypto_openssl.c
+++ b/platform/linux-generic/odp_crypto_openssl.c
@@ -124,10 +124,10 @@ static const odp_crypto_auth_capability_t auth_capa_aes_gmac[] = {
static const odp_crypto_auth_capability_t auth_capa_aes_cmac[] = {
{.digest_len = 12, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
-{.digest_len = 16, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
{.digest_len = 12, .key_len = 24, .aad_len = {.min = 0, .max = 0, .inc = 0} },
-{.digest_len = 16, .key_len = 24, .aad_len = {.min = 0, .max = 0, .inc = 0} },
{.digest_len = 12, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 16, .aad_len = {.min = 0, .max = 0, .inc = 0} },
+{.digest_len = 16, .key_len = 24, .aad_len = {.min = 0, .max = 0, .inc = 0} },
{.digest_len = 16, .key_len = 32, .aad_len = {.min = 0, .max = 0, .inc = 0} } };
#if _ODP_HAVE_CHACHA20_POLY1305
diff --git a/platform/linux-generic/odp_queue_basic.c b/platform/linux-generic/odp_queue_basic.c
index 39e2d59c..89eed3c0 100644
--- a/platform/linux-generic/odp_queue_basic.c
+++ b/platform/linux-generic/odp_queue_basic.c
@@ -7,7 +7,7 @@
#include "config.h"
#include <odp/api/queue.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include <odp_queue_if.h>
#include <odp/api/std_types.h>
#include <odp/api/align.h>
@@ -357,7 +357,7 @@ static odp_queue_t queue_create(const char *name,
return handle;
}
-void sched_cb_queue_destroy_finalize(uint32_t queue_index)
+void sched_queue_destroy_finalize(uint32_t queue_index)
{
queue_entry_t *queue = qentry_from_index(queue_index);
@@ -370,7 +370,7 @@ void sched_cb_queue_destroy_finalize(uint32_t queue_index)
UNLOCK(queue);
}
-void sched_cb_queue_set_status(uint32_t queue_index, int status)
+void sched_queue_set_status(uint32_t queue_index, int status)
{
queue_entry_t *queue = qentry_from_index(queue_index);
@@ -576,10 +576,9 @@ static int queue_enq(odp_queue_t handle, odp_event_t ev)
(odp_buffer_hdr_t *)(uintptr_t)ev);
}
-static inline int deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[],
- int num, int update_status)
+static inline int plain_queue_deq(queue_entry_t *queue,
+ odp_buffer_hdr_t *buf_hdr[], int num)
{
- int status_sync = sched_fn->status_sync;
int num_deq;
ring_st_t *ring_st;
uint32_t buf_idx[num];
@@ -589,32 +588,17 @@ static inline int deq_multi(queue_entry_t *queue, odp_buffer_hdr_t *buf_hdr[],
LOCK(queue);
if (odp_unlikely(queue->s.status < QUEUE_STATUS_READY)) {
- /* Bad queue, or queue has been destroyed.
- * Scheduler finalizes queue destroy after this. */
+ /* Bad queue, or queue has been destroyed. */
UNLOCK(queue);
return -1;
}
num_deq = ring_st_deq_multi(ring_st, buf_idx, num);
- if (num_deq == 0) {
- /* Already empty queue */
- if (update_status && queue->s.status == QUEUE_STATUS_SCHED) {
- queue->s.status = QUEUE_STATUS_NOTSCHED;
-
- if (status_sync)
- sched_fn->unsched_queue(queue->s.index);
- }
-
- UNLOCK(queue);
+ UNLOCK(queue);
+ if (num_deq == 0)
return 0;
- }
-
- if (status_sync && queue->s.type == ODP_QUEUE_TYPE_SCHED)
- sched_fn->save_context(queue->s.index);
-
- UNLOCK(queue);
buffer_index_to_buf(buf_hdr, buf_idx, num_deq);
@@ -626,7 +610,7 @@ static int queue_int_deq_multi(void *q_int, odp_buffer_hdr_t *buf_hdr[],
{
queue_entry_t *queue = q_int;
- return deq_multi(queue, buf_hdr, num, 0);
+ return plain_queue_deq(queue, buf_hdr, num);
}
static odp_buffer_hdr_t *queue_int_deq(void *q_int)
@@ -635,7 +619,7 @@ static odp_buffer_hdr_t *queue_int_deq(void *q_int)
odp_buffer_hdr_t *buf_hdr = NULL;
int ret;
- ret = deq_multi(queue, &buf_hdr, 1, 0);
+ ret = plain_queue_deq(queue, &buf_hdr, 1);
if (ret == 1)
return buf_hdr;
@@ -777,15 +761,53 @@ static int queue_info(odp_queue_t handle, odp_queue_info_t *info)
return 0;
}
-int sched_cb_queue_deq_multi(uint32_t queue_index, odp_event_t ev[], int num,
- int update_status)
+int sched_queue_deq(uint32_t queue_index, odp_event_t ev[], int max_num,
+ int update_status)
{
- queue_entry_t *qe = qentry_from_index(queue_index);
+ int num_deq;
+ ring_st_t *ring_st;
+ queue_entry_t *queue = qentry_from_index(queue_index);
+ int status_sync = sched_fn->status_sync;
+ uint32_t buf_idx[max_num];
+
+ ring_st = &queue->s.ring_st;
+
+ LOCK(queue);
- return deq_multi(qe, (odp_buffer_hdr_t **)ev, num, update_status);
+ if (odp_unlikely(queue->s.status < QUEUE_STATUS_READY)) {
+ /* Bad queue, or queue has been destroyed.
+ * Scheduler finalizes queue destroy after this. */
+ UNLOCK(queue);
+ return -1;
+ }
+
+ num_deq = ring_st_deq_multi(ring_st, buf_idx, max_num);
+
+ if (num_deq == 0) {
+ /* Already empty queue */
+ if (update_status && queue->s.status == QUEUE_STATUS_SCHED) {
+ queue->s.status = QUEUE_STATUS_NOTSCHED;
+
+ if (status_sync)
+ sched_fn->unsched_queue(queue->s.index);
+ }
+
+ UNLOCK(queue);
+
+ return 0;
+ }
+
+ if (status_sync && queue->s.type == ODP_QUEUE_TYPE_SCHED)
+ sched_fn->save_context(queue->s.index);
+
+ UNLOCK(queue);
+
+ buffer_index_to_buf((odp_buffer_hdr_t **)ev, buf_idx, num_deq);
+
+ return num_deq;
}
-int sched_cb_queue_empty(uint32_t queue_index)
+int sched_queue_empty(uint32_t queue_index)
{
queue_entry_t *queue = qentry_from_index(queue_index);
int ret = 0;
diff --git a/platform/linux-generic/odp_queue_lf.c b/platform/linux-generic/odp_queue_lf.c
index 3ec32524..d12a994b 100644
--- a/platform/linux-generic/odp_queue_lf.c
+++ b/platform/linux-generic/odp_queue_lf.c
@@ -8,7 +8,7 @@
#include <odp/api/atomic.h>
#include <odp/api/plat/atomic_inlines.h>
#include <odp/api/shared_memory.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include <string.h>
#include <stdio.h>
diff --git a/platform/linux-generic/odp_queue_spsc.c b/platform/linux-generic/odp_queue_spsc.c
index f8b04ca2..3e42b038 100644
--- a/platform/linux-generic/odp_queue_spsc.c
+++ b/platform/linux-generic/odp_queue_spsc.c
@@ -6,7 +6,7 @@
#include <string.h>
#include <stdio.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include <odp_pool_internal.h>
#include "config.h"
diff --git a/platform/linux-generic/odp_schedule_basic.c b/platform/linux-generic/odp_schedule_basic.c
index c81e417c..df63da72 100644
--- a/platform/linux-generic/odp_schedule_basic.c
+++ b/platform/linux-generic/odp_schedule_basic.c
@@ -26,7 +26,7 @@
#include <odp/api/packet_io.h>
#include <odp_ring_internal.h>
#include <odp_timer_internal.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#include <odp_libconfig_internal.h>
/* Number of priority levels */
@@ -92,8 +92,10 @@ ODP_STATIC_ASSERT((8 * sizeof(pri_mask_t)) >= MAX_SPREAD,
/* Start of named groups in group mask arrays */
#define SCHED_GROUP_NAMED (ODP_SCHED_GROUP_CONTROL + 1)
-/* Maximum number of dequeues */
-#define MAX_DEQ CONFIG_BURST_SIZE
+/* Default burst size. Scheduler rounds up number of requested events up to
+ * this value. */
+#define BURST_SIZE_MAX CONFIG_BURST_SIZE
+#define BURST_SIZE_MIN 1
/* Ordered stash size */
#define MAX_ORDERED_STASH 512
@@ -123,7 +125,7 @@ typedef struct {
uint16_t spread_round;
uint32_t stash_qi;
odp_queue_t stash_queue;
- odp_event_t stash_ev[MAX_DEQ];
+ odp_event_t stash_ev[BURST_SIZE_MAX];
uint32_t grp_epoch;
uint16_t num_grp;
@@ -178,6 +180,8 @@ typedef struct {
struct {
uint8_t num_spread;
+ uint8_t burst_hi;
+ uint8_t burst_low;
} config;
uint32_t pri_count[NUM_PRIO][MAX_SPREAD];
@@ -251,6 +255,34 @@ static int read_config_file(sched_global_t *sched)
}
sched->config.num_spread = val;
+ ODP_PRINT(" %s: %i\n", str, val);
+
+ str = "sched_basic.burst_size_hi";
+ if (!_odp_libconfig_lookup_int(str, &val)) {
+ ODP_ERR("Config option '%s' not found.\n", str);
+ return -1;
+ }
+
+ if (val > BURST_SIZE_MAX || val < BURST_SIZE_MIN) {
+ ODP_ERR("Bad value %s = %u\n", str, val);
+ return -1;
+ }
+
+ sched->config.burst_hi = val;
+ ODP_PRINT(" %s: %i\n", str, val);
+
+ str = "sched_basic.burst_size_low";
+ if (!_odp_libconfig_lookup_int(str, &val)) {
+ ODP_ERR("Config option '%s' not found.\n", str);
+ return -1;
+ }
+
+ if (val > BURST_SIZE_MAX || val < BURST_SIZE_MIN) {
+ ODP_ERR("Bad value %s = %u\n", str, val);
+ return -1;
+ }
+
+ sched->config.burst_low = val;
ODP_PRINT(" %s: %i\n\n", str, val);
return 0;
@@ -362,7 +394,7 @@ static int schedule_init_global(void)
static inline void queue_destroy_finalize(uint32_t qi)
{
- sched_cb_queue_destroy_finalize(qi);
+ sched_queue_destroy_finalize(qi);
}
static int schedule_term_global(void)
@@ -383,9 +415,7 @@ static int schedule_term_global(void)
odp_event_t events[1];
int num;
- num = sched_cb_queue_deq_multi(qi,
- events,
- 1, 1);
+ num = sched_queue_deq(qi, events, 1, 1);
if (num < 0)
queue_destroy_finalize(qi);
@@ -580,7 +610,7 @@ static void schedule_pktio_start(int pktio_index, int num_pktin,
ODP_ASSERT(pktin_idx[i] <= MAX_PKTIN_INDEX);
/* Start polling */
- sched_cb_queue_set_status(qi, QUEUE_STATUS_SCHED);
+ sched_queue_set_status(qi, QUEUE_STATUS_SCHED);
schedule_sched_queue(qi);
}
}
@@ -761,17 +791,29 @@ static inline int queue_is_pktin(uint32_t queue_index)
return sched->queue[queue_index].poll_pktin;
}
-static inline int poll_pktin(uint32_t qi, int stash)
+static inline int poll_pktin(uint32_t qi, int direct_recv,
+ odp_event_t ev_tbl[], int max_num)
{
- odp_buffer_hdr_t *b_hdr[MAX_DEQ];
- int pktio_index, pktin_index, num, num_pktin, i;
+ int pktio_index, pktin_index, num, num_pktin;
+ odp_buffer_hdr_t **hdr_tbl;
int ret;
void *q_int;
+ odp_buffer_hdr_t *b_hdr[BURST_SIZE_MAX];
+
+ hdr_tbl = (odp_buffer_hdr_t **)ev_tbl;
+
+ if (!direct_recv) {
+ hdr_tbl = b_hdr;
+
+ /* Limit burst to max queue enqueue size */
+ if (max_num > BURST_SIZE_MAX)
+ max_num = BURST_SIZE_MAX;
+ }
pktio_index = sched->queue[qi].pktio_index;
pktin_index = sched->queue[qi].pktin_index;
- num = sched_cb_pktin_poll(pktio_index, pktin_index, b_hdr, MAX_DEQ);
+ num = sched_cb_pktin_poll(pktio_index, pktin_index, hdr_tbl, max_num);
if (num == 0)
return 0;
@@ -784,7 +826,7 @@ static inline int poll_pktin(uint32_t qi, int stash)
num_pktin = sched->pktio[pktio_index].num_pktin;
odp_spinlock_unlock(&sched->pktio_lock);
- sched_cb_queue_set_status(qi, QUEUE_STATUS_NOTSCHED);
+ sched_queue_set_status(qi, QUEUE_STATUS_NOTSCHED);
if (num_pktin == 0)
sched_cb_pktio_stop_finalize(pktio_index);
@@ -792,12 +834,8 @@ static inline int poll_pktin(uint32_t qi, int stash)
return num;
}
- if (stash) {
- for (i = 0; i < num; i++)
- sched_local.stash_ev[i] = event_from_buf_hdr(b_hdr[i]);
-
+ if (direct_recv)
return num;
- }
q_int = qentry_from_index(qi);
@@ -824,7 +862,7 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
int ret;
int id;
uint32_t qi;
- unsigned int max_deq = MAX_DEQ;
+ unsigned int max_burst;
int num_spread = sched->config.num_spread;
uint32_t ring_mask = sched->ring_mask;
@@ -834,6 +872,10 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
if (sched->pri_mask[prio] == 0)
continue;
+ max_burst = sched->config.burst_hi;
+ if (prio > ODP_SCHED_PRIO_DEFAULT)
+ max_burst = sched->config.burst_low;
+
/* Select the first ring based on weights */
id = first;
@@ -843,6 +885,9 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
odp_queue_t handle;
ring_t *ring;
int pktin;
+ unsigned int max_deq = max_burst;
+ int stashed = 1;
+ odp_event_t *ev_tbl = sched_local.stash_ev;
if (id >= num_spread)
id = 0;
@@ -866,29 +911,27 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
continue;
}
- /* Low priorities have smaller batch size to limit
- * head of line blocking latency. */
- if (odp_unlikely(MAX_DEQ > 1 &&
- prio > ODP_SCHED_PRIO_DEFAULT))
- max_deq = MAX_DEQ / 2;
-
ordered = queue_is_ordered(qi);
- /* Do not cache ordered events locally to improve
+ /* When application's array is larger than max burst
+ * size, output all events directly there. Also, ordered
+ * queues are not stashed locally to improve
* parallelism. Ordered context can only be released
* when the local cache is empty. */
- if (ordered && max_num < MAX_DEQ)
+ if (max_num > max_burst || ordered) {
+ stashed = 0;
+ ev_tbl = out_ev;
max_deq = max_num;
+ }
pktin = queue_is_pktin(qi);
- num = sched_cb_queue_deq_multi(qi, sched_local.stash_ev,
- max_deq, !pktin);
+ num = sched_queue_deq(qi, ev_tbl, max_deq, !pktin);
if (num < 0) {
/* Destroyed queue. Continue scheduling the same
* priority queue. */
- sched_cb_queue_destroy_finalize(qi);
+ sched_queue_destroy_finalize(qi);
continue;
}
@@ -899,13 +942,16 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
* priorities. Stop scheduling queue when pktio
* has been stopped. */
if (pktin) {
- int stash = !ordered;
- int num_pkt = poll_pktin(qi, stash);
+ int direct_recv = !ordered;
+ int num_pkt;
+
+ num_pkt = poll_pktin(qi, direct_recv,
+ ev_tbl, max_deq);
if (odp_unlikely(num_pkt < 0))
continue;
- if (num_pkt == 0 || !stash) {
+ if (num_pkt == 0 || !direct_recv) {
ring_enq(ring, ring_mask, qi);
break;
}
@@ -943,10 +989,16 @@ static inline int do_schedule_grp(odp_queue_t *out_queue, odp_event_t out_ev[],
}
handle = queue_from_index(qi);
- sched_local.stash_num = num;
- sched_local.stash_index = 0;
- sched_local.stash_queue = handle;
- ret = copy_from_stash(out_ev, max_num);
+
+ if (stashed) {
+ sched_local.stash_num = num;
+ sched_local.stash_index = 0;
+ sched_local.stash_queue = handle;
+ ret = copy_from_stash(out_ev, max_num);
+ } else {
+ sched_local.stash_num = 0;
+ ret = num;
+ }
/* Output the source queue handle */
if (out_queue)
diff --git a/platform/linux-generic/odp_schedule_iquery.c b/platform/linux-generic/odp_schedule_iquery.c
index c1e51bb5..2501a3f6 100644
--- a/platform/linux-generic/odp_schedule_iquery.c
+++ b/platform/linux-generic/odp_schedule_iquery.c
@@ -25,9 +25,7 @@
#include <odp/api/packet_io.h>
#include <odp_config_internal.h>
#include <odp_timer_internal.h>
-
-/* Should remove this dependency */
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
/* Number of priority levels */
#define NUM_SCHED_PRIO 8
@@ -291,10 +289,10 @@ static int schedule_term_global(void)
odp_event_t events[1];
if (sched->availables[i])
- count = sched_cb_queue_deq_multi(i, events, 1, 1);
+ count = sched_queue_deq(i, events, 1, 1);
if (count < 0)
- sched_cb_queue_destroy_finalize(i);
+ sched_queue_destroy_finalize(i);
else if (count > 0)
ODP_ERR("Queue (%d) not empty\n", i);
}
@@ -1534,12 +1532,11 @@ static inline int consume_queue(int prio, unsigned int queue_index)
if (is_ordered_queue(queue_index))
max = 1;
- count = sched_cb_queue_deq_multi(
- queue_index, cache->stash, max, 1);
+ count = sched_queue_deq(queue_index, cache->stash, max, 1);
if (count < 0) {
DO_SCHED_UNLOCK();
- sched_cb_queue_destroy_finalize(queue_index);
+ sched_queue_destroy_finalize(queue_index);
DO_SCHED_LOCK();
return 0;
}
diff --git a/platform/linux-generic/odp_schedule_sp.c b/platform/linux-generic/odp_schedule_sp.c
index ac0b35fd..ae292051 100644
--- a/platform/linux-generic/odp_schedule_sp.c
+++ b/platform/linux-generic/odp_schedule_sp.c
@@ -20,7 +20,7 @@
#include <odp_config_internal.h>
#include <odp_ring_internal.h>
#include <odp_timer_internal.h>
-#include <odp_queue_internal.h>
+#include <odp_queue_basic_internal.h>
#define NUM_THREAD ODP_THREAD_COUNT_MAX
#define NUM_QUEUE ODP_CONFIG_QUEUES
@@ -228,7 +228,7 @@ static int term_global(void)
for (qi = 0; qi < NUM_QUEUE; qi++) {
if (sched_global->queue_cmd[qi].s.init) {
/* todo: dequeue until empty ? */
- sched_cb_queue_destroy_finalize(qi);
+ sched_queue_destroy_finalize(qi);
}
}
@@ -507,7 +507,7 @@ static int schedule_multi(odp_queue_t *from, uint64_t wait,
if (sched_local.cmd) {
/* Continue scheduling if queue is not empty */
- if (sched_cb_queue_empty(sched_local.cmd->s.index) == 0)
+ if (sched_queue_empty(sched_local.cmd->s.index) == 0)
add_tail(sched_local.cmd);
sched_local.cmd = NULL;
@@ -562,7 +562,7 @@ static int schedule_multi(odp_queue_t *from, uint64_t wait,
}
qi = cmd->s.index;
- num = sched_cb_queue_deq_multi(qi, events, 1, 1);
+ num = sched_queue_deq(qi, events, 1, 1);
if (num > 0) {
sched_local.cmd = cmd;
@@ -575,7 +575,7 @@ static int schedule_multi(odp_queue_t *from, uint64_t wait,
if (num < 0) {
/* Destroyed queue */
- sched_cb_queue_destroy_finalize(qi);
+ sched_queue_destroy_finalize(qi);
continue;
}
diff --git a/platform/linux-generic/odp_system_info.c b/platform/linux-generic/odp_system_info.c
index 8b2bfc5c..bca02ba1 100644
--- a/platform/linux-generic/odp_system_info.c
+++ b/platform/linux-generic/odp_system_info.c
@@ -265,7 +265,7 @@ static char *get_hugepage_dir(uint64_t hugepage_sz)
/*
* Analysis of /sys/devices/system/cpu/cpu%d/cpufreq/ files
*/
-uint64_t odp_cpufreq_id(const char *filename, int id)
+static uint64_t read_cpufreq(const char *filename, int id)
{
char path[256], buffer[256], *endptr = NULL;
FILE *file;
@@ -343,23 +343,25 @@ int odp_system_info_init(void)
odp_global_data.system_info.page_size = ODP_PAGE_SIZE;
+ /* By default, read max frequency from a cpufreq file */
+ for (i = 0; i < CONFIG_NUM_CPU; i++) {
+ uint64_t cpu_hz_max = read_cpufreq("cpuinfo_max_freq", i);
+
+ if (cpu_hz_max)
+ odp_global_data.system_info.cpu_hz_max[i] = cpu_hz_max;
+ }
+
file = fopen("/proc/cpuinfo", "rt");
if (file == NULL) {
ODP_ERR("Failed to open /proc/cpuinfo\n");
return -1;
}
+ /* Read CPU model, and set max cpu frequency if not set from cpufreq. */
cpuinfo_parser(file, &odp_global_data.system_info);
fclose(file);
- for (i = 0; i < MAX_CPU_NUMBER; i++) {
- uint64_t cpu_hz_max = odp_cpufreq_id("cpuinfo_max_freq", i);
-
- if (cpu_hz_max)
- odp_global_data.system_info.cpu_hz_max[i] = cpu_hz_max;
- }
-
if (systemcpu(&odp_global_data.system_info)) {
ODP_ERR("systemcpu failed\n");
return -1;
@@ -387,7 +389,7 @@ int odp_system_info_term(void)
*/
uint64_t odp_cpu_hz_current(int id)
{
- uint64_t cur_hz = odp_cpufreq_id("cpuinfo_cur_freq", id);
+ uint64_t cur_hz = read_cpufreq("cpuinfo_cur_freq", id);
if (!cur_hz)
cur_hz = odp_cpu_arch_hz_current(id);
@@ -414,7 +416,7 @@ uint64_t odp_cpu_hz_max(void)
uint64_t odp_cpu_hz_max_id(int id)
{
- if (id >= 0 && id < MAX_CPU_NUMBER)
+ if (id >= 0 && id < CONFIG_NUM_CPU)
return odp_global_data.system_info.cpu_hz_max[id];
else
return 0;
@@ -473,7 +475,7 @@ const char *odp_cpu_model_str(void)
const char *odp_cpu_model_str_id(int id)
{
- if (id >= 0 && id < MAX_CPU_NUMBER)
+ if (id >= 0 && id < CONFIG_NUM_CPU)
return odp_global_data.system_info.model_str[id];
else
return NULL;
diff --git a/platform/linux-generic/pktio/ring.c b/platform/linux-generic/pktio/ring.c
index 518d940e..bb0d6780 100644
--- a/platform/linux-generic/pktio/ring.c
+++ b/platform/linux-generic/pktio/ring.c
@@ -195,9 +195,6 @@ _ring_create(const char *name, unsigned count, unsigned flags)
/* init the ring structure */
snprintf(r->name, sizeof(r->name), "%s", name);
r->flags = flags;
- r->prod.watermark = count;
- r->prod.sp_enqueue = !!(flags & _RING_F_SP_ENQ);
- r->cons.sc_dequeue = !!(flags & _RING_F_SC_DEQ);
r->prod.size = count;
r->cons.size = count;
r->prod.mask = count - 1;
@@ -235,23 +232,6 @@ int _ring_destroy(const char *name)
return 0;
}
-/*
- * change the high water mark. If *count* is 0, water marking is
- * disabled
- */
-int _ring_set_water_mark(_ring_t *r, unsigned count)
-{
- if (count >= r->prod.size)
- return -EINVAL;
-
- /* if count is 0, disable the watermarking */
- if (count == 0)
- count = r->prod.size;
-
- r->prod.watermark = count;
- return 0;
-}
-
/**
* Enqueue several objects on the ring (multi-producers safe).
*/
@@ -264,14 +244,13 @@ int ___ring_mp_do_enqueue(_ring_t *r, void * const *obj_table,
int success;
unsigned i;
uint32_t mask = r->prod.mask;
- int ret;
/* move prod.head atomically */
do {
/* Reset n to the initial burst count */
n = max;
- prod_head = __atomic_load_n(&r->prod.head, __ATOMIC_RELAXED);
+ prod_head = __atomic_load_n(&r->prod.head, __ATOMIC_ACQUIRE);
cons_tail = __atomic_load_n(&r->cons.tail, __ATOMIC_ACQUIRE);
/* The subtraction is done between two unsigned 32bits value
* (the result is always modulo 32 bits even if we have
@@ -302,14 +281,6 @@ int ___ring_mp_do_enqueue(_ring_t *r, void * const *obj_table,
/* write entries in ring */
ENQUEUE_PTRS();
- /* if we exceed the watermark */
- if (odp_unlikely(((mask + 1) - free_entries + n) > r->prod.watermark)) {
- ret = (behavior == _RING_QUEUE_FIXED) ? -EDQUOT :
- (int)(n | _RING_QUOT_EXCEED);
- } else {
- ret = (behavior == _RING_QUEUE_FIXED) ? 0 : n;
- }
-
/*
* If there are other enqueues in progress that preceded us,
* we need to wait for them to complete
@@ -320,57 +291,7 @@ int ___ring_mp_do_enqueue(_ring_t *r, void * const *obj_table,
/* Release our entries and the memory they refer to */
__atomic_store_n(&r->prod.tail, prod_next, __ATOMIC_RELEASE);
- return ret;
-}
-
-/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- */
-int ___ring_sp_do_enqueue(_ring_t *r, void * const *obj_table,
- unsigned n, enum _ring_queue_behavior behavior)
-{
- uint32_t prod_head, cons_tail;
- uint32_t prod_next, free_entries;
- unsigned i;
- uint32_t mask = r->prod.mask;
- int ret;
-
- prod_head = r->prod.head;
- cons_tail = __atomic_load_n(&r->cons.tail, __ATOMIC_ACQUIRE);
- /* The subtraction is done between two unsigned 32bits value
- * (the result is always modulo 32 bits even if we have
- * prod_head > cons_tail). So 'free_entries' is always between 0
- * and size(ring)-1. */
- free_entries = mask + cons_tail - prod_head;
-
- /* check that we have enough room in ring */
- if (odp_unlikely(n > free_entries)) {
- if (behavior == _RING_QUEUE_FIXED)
- return -ENOBUFS;
- /* No free entry available */
- if (odp_unlikely(free_entries == 0))
- return 0;
-
- n = free_entries;
- }
-
- prod_next = prod_head + n;
- r->prod.head = prod_next;
-
- /* write entries in ring */
- ENQUEUE_PTRS();
-
- /* if we exceed the watermark */
- if (odp_unlikely(((mask + 1) - free_entries + n) > r->prod.watermark)) {
- ret = (behavior == _RING_QUEUE_FIXED) ? -EDQUOT :
- (int)(n | _RING_QUOT_EXCEED);
- } else {
- ret = (behavior == _RING_QUEUE_FIXED) ? 0 : n;
- }
-
- /* Release our entries and the memory they refer to */
- __atomic_store_n(&r->prod.tail, prod_next, __ATOMIC_RELEASE);
- return ret;
+ return (behavior == _RING_QUEUE_FIXED) ? 0 : n;
}
/**
@@ -392,7 +313,7 @@ int ___ring_mc_do_dequeue(_ring_t *r, void **obj_table,
/* Restore n as it may change every loop */
n = max;
- cons_head = __atomic_load_n(&r->cons.head, __ATOMIC_RELAXED);
+ cons_head = __atomic_load_n(&r->cons.head, __ATOMIC_ACQUIRE);
prod_tail = __atomic_load_n(&r->prod.tail, __ATOMIC_ACQUIRE);
/* The subtraction is done between two unsigned 32bits value
* (the result is always modulo 32 bits even if we have
@@ -437,45 +358,6 @@ int ___ring_mc_do_dequeue(_ring_t *r, void **obj_table,
}
/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).
- */
-int ___ring_sc_do_dequeue(_ring_t *r, void **obj_table,
- unsigned n, enum _ring_queue_behavior behavior)
-{
- uint32_t cons_head, prod_tail;
- uint32_t cons_next, entries;
- unsigned i;
- uint32_t mask = r->prod.mask;
-
- cons_head = r->cons.head;
- prod_tail = __atomic_load_n(&r->prod.tail, __ATOMIC_ACQUIRE);
- /* The subtraction is done between two unsigned 32bits value
- * (the result is always modulo 32 bits even if we have
- * cons_head > prod_tail). So 'entries' is always between 0
- * and size(ring)-1. */
- entries = prod_tail - cons_head;
-
- if (n > entries) {
- if (behavior == _RING_QUEUE_FIXED)
- return -ENOENT;
- if (odp_unlikely(entries == 0))
- return 0;
-
- n = entries;
- }
-
- cons_next = cons_head + n;
- r->cons.head = cons_next;
-
- /* Acquire the pointers and the memory they refer to */
- /* copy in table */
- DEQUEUE_PTRS();
-
- __atomic_store_n(&r->cons.tail, cons_next, __ATOMIC_RELEASE);
- return behavior == _RING_QUEUE_FIXED ? 0 : n;
-}
-
-/**
* Enqueue several objects on the ring (multi-producers safe).
*/
int _ring_mp_enqueue_bulk(_ring_t *r, void * const *obj_table,
@@ -486,16 +368,6 @@ int _ring_mp_enqueue_bulk(_ring_t *r, void * const *obj_table,
}
/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- */
-int _ring_sp_enqueue_bulk(_ring_t *r, void * const *obj_table,
- unsigned n)
-{
- return ___ring_sp_do_enqueue(r, obj_table, n,
- _RING_QUEUE_FIXED);
-}
-
-/**
* Dequeue several objects from a ring (multi-consumers safe).
*/
int _ring_mc_dequeue_bulk(_ring_t *r, void **obj_table, unsigned n)
@@ -505,15 +377,6 @@ int _ring_mc_dequeue_bulk(_ring_t *r, void **obj_table, unsigned n)
}
/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).
- */
-int _ring_sc_dequeue_bulk(_ring_t *r, void **obj_table, unsigned n)
-{
- return ___ring_sc_do_dequeue(r, obj_table, n,
- _RING_QUEUE_FIXED);
-}
-
-/**
* Test if a ring is full.
*/
int _ring_full(const _ring_t *r)
@@ -569,10 +432,6 @@ void _ring_dump(const _ring_t *r)
ODP_DBG(" ph=%" PRIu32 "\n", r->prod.head);
ODP_DBG(" used=%u\n", _ring_count(r));
ODP_DBG(" avail=%u\n", _ring_free_count(r));
- if (r->prod.watermark == r->prod.size)
- ODP_DBG(" watermark=0\n");
- else
- ODP_DBG(" watermark=%" PRIu32 "\n", r->prod.watermark);
}
/* dump the status of all rings on the console */
@@ -615,28 +474,6 @@ int _ring_mp_enqueue_burst(_ring_t *r, void * const *obj_table,
}
/**
- * Enqueue several objects on a ring (NOT multi-producers safe).
- */
-int _ring_sp_enqueue_burst(_ring_t *r, void * const *obj_table,
- unsigned n)
-{
- return ___ring_sp_do_enqueue(r, obj_table, n,
- _RING_QUEUE_VARIABLE);
-}
-
-/**
- * Enqueue several objects on a ring.
- */
-int _ring_enqueue_burst(_ring_t *r, void * const *obj_table,
- unsigned n)
-{
- if (r->prod.sp_enqueue)
- return _ring_sp_enqueue_burst(r, obj_table, n);
- else
- return _ring_mp_enqueue_burst(r, obj_table, n);
-}
-
-/**
* Dequeue several objects from a ring (multi-consumers safe).
*/
int _ring_mc_dequeue_burst(_ring_t *r, void **obj_table, unsigned n)
@@ -644,23 +481,3 @@ int _ring_mc_dequeue_burst(_ring_t *r, void **obj_table, unsigned n)
return ___ring_mc_do_dequeue(r, obj_table, n,
_RING_QUEUE_VARIABLE);
}
-
-/**
- * Dequeue several objects from a ring (NOT multi-consumers safe).
- */
-int _ring_sc_dequeue_burst(_ring_t *r, void **obj_table, unsigned n)
-{
- return ___ring_sc_do_dequeue(r, obj_table, n,
- _RING_QUEUE_VARIABLE);
-}
-
-/**
- * Dequeue multiple objects from a ring up to a maximum number.
- */
-int _ring_dequeue_burst(_ring_t *r, void **obj_table, unsigned n)
-{
- if (r->cons.sc_dequeue)
- return _ring_sc_dequeue_burst(r, obj_table, n);
- else
- return _ring_mc_dequeue_burst(r, obj_table, n);
-}
diff --git a/platform/linux-generic/test/ring/ring_basic.c b/platform/linux-generic/test/ring/ring_basic.c
index 87fb18c3..6b17d8e5 100644
--- a/platform/linux-generic/test/ring/ring_basic.c
+++ b/platform/linux-generic/test/ring/ring_basic.c
@@ -26,20 +26,14 @@
/* labor functions declaration */
static void __do_basic_burst(_ring_t *r);
static void __do_basic_bulk(_ring_t *r);
-static void __do_basic_watermark(_ring_t *r);
/* dummy object pointers for enqueue and dequeue testing */
static void **test_enq_data;
static void **test_deq_data;
-/* create two rings: one for single thread usage scenario
- * and another for multiple thread usage scenario.
- * st - single thread usage scenario
- * mt - multiple thread usage scenario
- */
-static const char *st_ring_name = "ST basic ring";
+/* create multiple thread test ring */
static const char *mt_ring_name = "MT basic ring";
-static _ring_t *st_ring, *mt_ring;
+static _ring_t *mt_ring;
int ring_test_basic_start(void)
{
@@ -69,7 +63,6 @@ int ring_test_basic_start(void)
int ring_test_basic_end(void)
{
- _ring_destroy(st_ring_name);
_ring_destroy(mt_ring_name);
free(test_enq_data);
@@ -81,17 +74,10 @@ int ring_test_basic_end(void)
void ring_test_basic_create(void)
{
/* prove illegal size shall fail */
- st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0);
- CU_ASSERT(NULL == st_ring);
+ mt_ring = _ring_create(mt_ring_name, ILLEGAL_SIZE, 0);
+ CU_ASSERT(NULL == mt_ring);
CU_ASSERT(EINVAL == __odp_errno);
- /* create ring for single thread usage scenario */
- st_ring = _ring_create(st_ring_name, RING_SIZE,
- _RING_F_SP_ENQ | _RING_F_SC_DEQ);
-
- CU_ASSERT(NULL != st_ring);
- CU_ASSERT(_ring_lookup(st_ring_name) == st_ring);
-
/* create ring for multiple thread usage scenario */
mt_ring = _ring_create(mt_ring_name, RING_SIZE,
_RING_SHM_PROC);
@@ -102,25 +88,14 @@ void ring_test_basic_create(void)
void ring_test_basic_burst(void)
{
- /* two rounds to cover both single
- * thread and multiple thread APIs
- */
- __do_basic_burst(st_ring);
__do_basic_burst(mt_ring);
}
void ring_test_basic_bulk(void)
{
- __do_basic_bulk(st_ring);
__do_basic_bulk(mt_ring);
}
-void ring_test_basic_watermark(void)
-{
- __do_basic_watermark(st_ring);
- __do_basic_watermark(mt_ring);
-}
-
/* labor functions definition */
static void __do_basic_burst(_ring_t *r)
{
@@ -136,17 +111,17 @@ static void __do_basic_burst(_ring_t *r)
CU_ASSERT(1 == _ring_empty(r));
/* enqueue 1 object */
- result = _ring_enqueue_burst(r, enq, 1);
+ result = _ring_mp_enqueue_burst(r, enq, 1);
enq += 1;
CU_ASSERT(1 == (result & _RING_SZ_MASK));
/* enqueue 2 objects */
- result = _ring_enqueue_burst(r, enq, 2);
+ result = _ring_mp_enqueue_burst(r, enq, 2);
enq += 2;
CU_ASSERT(2 == (result & _RING_SZ_MASK));
/* enqueue HALF_BULK objects */
- result = _ring_enqueue_burst(r, enq, HALF_BULK);
+ result = _ring_mp_enqueue_burst(r, enq, HALF_BULK);
enq += HALF_BULK;
CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK));
@@ -162,23 +137,23 @@ static void __do_basic_burst(_ring_t *r)
CU_ASSERT(count == _ring_free_count(r));
/* exceed the size, enquene as many as possible */
- result = _ring_enqueue_burst(r, enq, HALF_BULK);
+ result = _ring_mp_enqueue_burst(r, enq, HALF_BULK);
enq += count;
CU_ASSERT(count == (result & _RING_SZ_MASK));
CU_ASSERT(1 == _ring_full(r));
/* dequeue 1 object */
- result = _ring_dequeue_burst(r, deq, 1);
+ result = _ring_mc_dequeue_burst(r, deq, 1);
deq += 1;
CU_ASSERT(1 == (result & _RING_SZ_MASK));
/* dequeue 2 objects */
- result = _ring_dequeue_burst(r, deq, 2);
+ result = _ring_mc_dequeue_burst(r, deq, 2);
deq += 2;
CU_ASSERT(2 == (result & _RING_SZ_MASK));
/* dequeue HALF_BULK objects */
- result = _ring_dequeue_burst(r, deq, HALF_BULK);
+ result = _ring_mc_dequeue_burst(r, deq, HALF_BULK);
deq += HALF_BULK;
CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK));
@@ -190,7 +165,7 @@ static void __do_basic_burst(_ring_t *r)
CU_ASSERT(count == _ring_count(r));
/* underrun the size, dequeue as many as possible */
- result = _ring_dequeue_burst(r, deq, HALF_BULK);
+ result = _ring_mc_dequeue_burst(r, deq, HALF_BULK);
deq += count;
CU_ASSERT(count == (result & _RING_SZ_MASK));
CU_ASSERT(1 == _ring_empty(r));
@@ -208,19 +183,13 @@ static void __do_basic_burst(_ring_t *r)
static inline int __ring_enqueue_bulk(
_ring_t *r, void * const *objects, unsigned bulk)
{
- if (r->prod.sp_enqueue)
- return _ring_sp_enqueue_bulk(r, objects, bulk);
- else
- return _ring_mp_enqueue_bulk(r, objects, bulk);
+ return _ring_mp_enqueue_bulk(r, objects, bulk);
}
static inline int __ring_dequeue_bulk(
_ring_t *r, void **objects, unsigned bulk)
{
- if (r->cons.sc_dequeue)
- return _ring_sc_dequeue_bulk(r, objects, bulk);
- else
- return _ring_mc_dequeue_bulk(r, objects, bulk);
+ return _ring_mc_dequeue_bulk(r, objects, bulk);
}
static void __do_basic_bulk(_ring_t *r)
@@ -310,55 +279,3 @@ static void __do_basic_bulk(_ring_t *r)
/* reset dequeue data */
memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
}
-
-void __do_basic_watermark(_ring_t *r)
-{
- int result = 0;
- void * const *source = test_enq_data;
- void * const *dest = test_deq_data;
- void **enq = NULL, **deq = NULL;
-
- enq = test_enq_data; deq = test_deq_data;
-
- /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */
- const unsigned watermark = PIECE_BULK;
- const unsigned bulk = (watermark / 4) * 3;
-
- /* watermark cannot exceed ring size */
- result = _ring_set_water_mark(r, ILLEGAL_SIZE);
- CU_ASSERT(-EINVAL == result);
-
- /* set watermark */
- result = _ring_set_water_mark(r, watermark);
- CU_ASSERT(0 == result);
-
- /* 1st enqueue shall succeed */
- result = __ring_enqueue_bulk(r, enq, bulk);
- enq += bulk;
- CU_ASSERT(0 == result);
-
- /* 2nd enqueue shall succeed but return -EDQUOT */
- result = __ring_enqueue_bulk(r, enq, bulk);
- enq += bulk;
- CU_ASSERT(-EDQUOT == result);
-
- /* dequeue 1st bulk */
- result = __ring_dequeue_bulk(r, deq, bulk);
- deq += bulk;
- CU_ASSERT(0 == result);
-
- /* dequeue 2nd bulk */
- result = __ring_dequeue_bulk(r, deq, bulk);
- deq += bulk;
- CU_ASSERT(0 == result);
-
- /* check data */
- CU_ASSERT(0 == memcmp(source, dest, deq - dest));
-
- /* reset watermark */
- result = _ring_set_water_mark(r, 0);
- CU_ASSERT(0 == result);
-
- /* reset dequeue data */
- memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *));
-}
diff --git a/platform/linux-generic/test/ring/ring_suites.c b/platform/linux-generic/test/ring/ring_suites.c
index baecba6e..5f195777 100644
--- a/platform/linux-generic/test/ring/ring_suites.c
+++ b/platform/linux-generic/test/ring/ring_suites.c
@@ -36,7 +36,6 @@ static odp_testinfo_t ring_suite_basic[] = {
ODP_TEST_INFO(ring_test_basic_create),
ODP_TEST_INFO(ring_test_basic_burst),
ODP_TEST_INFO(ring_test_basic_bulk),
- ODP_TEST_INFO(ring_test_basic_watermark),
ODP_TEST_INFO_NULL,
};
diff --git a/platform/linux-generic/test/ring/ring_suites.h b/platform/linux-generic/test/ring/ring_suites.h
index 1735f2d7..d56ab784 100644
--- a/platform/linux-generic/test/ring/ring_suites.h
+++ b/platform/linux-generic/test/ring/ring_suites.h
@@ -18,7 +18,6 @@ int ring_test_basic_end(void);
void ring_test_basic_create(void);
void ring_test_basic_burst(void);
void ring_test_basic_bulk(void);
-void ring_test_basic_watermark(void);
/* test suite start and stop */
int ring_test_stress_start(void);
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index d5ffd1dd..a0d18972 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2487,7 +2487,7 @@ sub process {
# Check the patch for a signoff:
if ($line =~ /^\s*signed-off-by:/i) {
$signoff++;
- $in_commit_log = 0;
+ #$in_commit_log = 0;
}
# Check if MAINTAINERS is being updated. If so, there's probably no need to
@@ -2497,7 +2497,7 @@ sub process {
}
# Check signature styles
- if (!$in_header_lines &&
+ if (!$in_header_lines && $in_commit_log &&
$line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
my $space_before = $1;
my $sign_off = $2;
diff --git a/test/performance/.gitignore b/test/performance/.gitignore
index febe86ed..ca0e884f 100644
--- a/test/performance/.gitignore
+++ b/test/performance/.gitignore
@@ -2,12 +2,15 @@
*.trs
odp_atomic
odp_bench_packet
+odp_cpu_bench
odp_crypto
odp_ipsec
odp_l2fwd
odp_pktio_ordered
odp_pktio_perf
+odp_pool_perf
odp_queue_perf
odp_sched_latency
+odp_sched_perf
odp_sched_pktio
odp_scheduling
diff --git a/test/performance/Makefile.am b/test/performance/Makefile.am
index 2d83c16c..e1098f13 100644
--- a/test/performance/Makefile.am
+++ b/test/performance/Makefile.am
@@ -3,10 +3,13 @@ include $(top_srcdir)/test/Makefile.inc
TESTS_ENVIRONMENT += TEST_DIR=${builddir}
EXECUTABLES = odp_bench_packet \
+ odp_cpu_bench \
odp_crypto \
odp_ipsec \
odp_pktio_perf \
- odp_queue_perf
+ odp_pool_perf \
+ odp_queue_perf \
+ odp_sched_perf
COMPILE_ONLY = odp_l2fwd \
odp_pktio_ordered \
@@ -32,6 +35,7 @@ endif
bin_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY)
odp_bench_packet_SOURCES = odp_bench_packet.c
+odp_cpu_bench_SOURCES = odp_cpu_bench.c
odp_crypto_SOURCES = odp_crypto.c
odp_ipsec_SOURCES = odp_ipsec.c
odp_pktio_ordered_SOURCES = odp_pktio_ordered.c dummy_crc.h
@@ -39,7 +43,9 @@ odp_sched_latency_SOURCES = odp_sched_latency.c
odp_sched_pktio_SOURCES = odp_sched_pktio.c
odp_scheduling_SOURCES = odp_scheduling.c
odp_pktio_perf_SOURCES = odp_pktio_perf.c
+odp_pool_perf_SOURCES = odp_pool_perf.c
odp_queue_perf_SOURCES = odp_queue_perf.c
+odp_sched_perf_SOURCES = odp_sched_perf.c
# l2fwd test depends on generator example
EXTRA_odp_l2fwd_DEPENDENCIES = example-generator
diff --git a/test/performance/odp_cpu_bench.c b/test/performance/odp_cpu_bench.c
new file mode 100644
index 00000000..949825e9
--- /dev/null
+++ b/test/performance/odp_cpu_bench.c
@@ -0,0 +1,813 @@
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "config.h"
+
+#include <odp_api.h>
+#include <odp/helper/odph_api.h>
+
+#include <test_debug.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)
+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;
+} args_t;
+
+/* Global pointer to args */
+static args_t *gbl_args;
+
+static volatile int exit_threads; /* Break workers loop if set to 1 */
+
+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)
+{
+ exit_threads = 1;
+}
+
+static inline void init_packet(odp_packet_t pkt, uint32_t seq, uint16_t group)
+{
+ uint32_t *payload;
+ test_hdr_t *hdr;
+ odp_packet_parse_param_t param;
+
+ param.proto = ODP_PROTO_ETH;
+ param.last_layer = ODP_PROTO_LAYER_ALL;
+ param.chksums.all_chksum = 0;
+ if (odp_packet_parse(pkt, 0, &param))
+ LOG_ABORT("odp_packet_parse() failed\n");
+
+ /* Modify UDP payload and update checksum */
+ payload = odp_packet_offset(pkt, odp_packet_l4_offset(pkt) +
+ ODPH_UDPHDR_LEN, NULL, NULL);
+ *payload = seq;
+ if (odph_udp_chksum_set(pkt))
+ LOG_ABORT("odph_udp_chksum_set() failed\n");
+
+ /* Test header is stored in user area */
+ hdr = odp_packet_user_area(pkt);
+ hdr->seq = seq;
+ hdr->group = group;
+ hdr->crc = odp_hash_crc32c(odp_packet_data(pkt), odp_packet_len(pkt),
+ CRC_INIT_VAL);
+}
+
+static inline odp_queue_t work_on_event(odp_event_t event)
+{
+ odp_packet_t pkt;
+ odp_packet_parse_param_t param;
+ odph_udphdr_t *udp_hdr;
+ test_hdr_t *hdr;
+ lookup_entry_t *lookup_entry;
+ uint32_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)
+ return ODP_QUEUE_INVALID;
+
+ pkt = odp_packet_from_event(event);
+ hdr = odp_packet_user_area(pkt);
+ 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)
+ LOG_ERR("Error: Invalid packet crc\n");
+
+ param.proto = ODP_PROTO_ETH;
+ param.last_layer = ODP_PROTO_LAYER_ALL;
+ param.chksums.all_chksum = 1;
+ if (odp_packet_parse(pkt, 0, &param)) {
+ LOG_ERR("Error: odp_packet_parse() failed\n");
+ return ODP_QUEUE_INVALID;
+ }
+
+ /* 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);
+ payload = odp_packet_offset(pkt, odp_packet_l4_offset(pkt) +
+ 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];
+}
+
+/**
+ * Worker thread
+ */
+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);
+
+ c1 = odp_cpu_cycles();
+ t1 = odp_time_local();
+
+ while (!exit_threads) {
+ odp_event_t event_tbl[MAX_EVENT_BURST];
+ odp_queue_t dst_queue;
+ int num_events;
+ int i;
+
+ num_events = odp_schedule_multi(NULL, ODP_SCHED_NO_WAIT,
+ 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++;
+ odp_event_free(event);
+ continue;
+ }
+
+ if (odp_unlikely(odp_queue_enq(dst_queue, event))) {
+ LOG_ERR("Error: odp_queue_enq() failed\n");
+ stats->s.dropped_pkts++;
+ odp_event_free(event);
+ break;
+ }
+
+ stats->s.pkts++;
+ }
+ }
+
+ c2 = odp_cpu_cycles();
+ t2 = odp_time_local();
+
+ 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) {
+ odp_event_t ev;
+
+ ev = odp_schedule(NULL,
+ odp_schedule_wait_time(ODP_TIME_SEC_IN_NS));
+
+ if (ev == ODP_EVENT_INVALID)
+ break;
+
+ odp_event_free(ev);
+ }
+
+ return 0;
+}
+
+/*
+ * Prinf 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);
+}
+
+/**
+ * @internal Parse arguments
+ *
+ * @param argc Argument count
+ * @param argv Argument vector
+ * @param args Test arguments
+ */
+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";
+
+ /* Let helper collect its own arguments (e.g. --odph_proc) */
+ argc = odph_parse_options(argc, argv);
+
+ 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 (!exit_threads && (loop_forever || (elapsed < duration)));
+
+ 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));
+}
+
+/**
+ * Test main function
+ */
+int main(int argc, char *argv[])
+{
+ stats_t *stats[MAX_WORKERS];
+ odph_odpthread_t thread_tbl[MAX_WORKERS];
+ odp_cpumask_t cpumask;
+ odp_pool_capability_t pool_capa;
+ odp_pool_t pool;
+ odp_queue_capability_t queue_capa;
+ odp_shm_t shm;
+ odp_shm_t lookup_tbl_shm;
+ odp_pool_param_t params;
+ 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 cpu;
+ int ret = 0;
+
+ odp_init_param_init(&init);
+
+ /* 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;
+
+ /* 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)) {
+ LOG_ERR("Error: ODP global init failed\n");
+ return -1;
+ }
+
+ if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+ LOG_ERR("Error: ODP local init failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ shm = odp_shm_reserve("shm_args", sizeof(args_t), ODP_CACHE_LINE_SIZE,
+ 0);
+ gbl_args = odp_shm_addr(shm);
+ if (gbl_args == NULL) {
+ LOG_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);
+ gbl_args->lookup_tbl = odp_shm_addr(lookup_tbl_shm);
+ if (gbl_args->lookup_tbl == NULL) {
+ LOG_ERR("Error: lookup table mem alloc failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("\n");
+ odp_sys_info_print();
+
+ /* 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);
+
+ /* Create application queues */
+ if (odp_queue_capability(&queue_capa)) {
+ LOG_ERR("Error: odp_queue_capability() failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Make sure a single queue can store all the packets in a group */
+ pkts_per_group = QUEUES_PER_GROUP * PKTS_PER_QUEUE;
+ if (queue_capa.sched.max_size &&
+ queue_capa.sched.max_size < pkts_per_group)
+ pkts_per_group = queue_capa.sched.max_size;
+
+ /* Divide queues evenly into groups */
+ if (queue_capa.sched.max_num < QUEUES_PER_GROUP) {
+ LOG_ERR("Error: min %d queues required\n", QUEUES_PER_GROUP);
+ return -1;
+ }
+ num_queues = num_workers > queue_capa.sched.max_num ?
+ queue_capa.sched.max_num : num_workers;
+ num_groups = (num_queues + QUEUES_PER_GROUP - 1) / QUEUES_PER_GROUP;
+ if (num_groups * QUEUES_PER_GROUP > queue_capa.sched.max_num)
+ 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;
+ odp_queue_param_t param;
+
+ odp_queue_param_init(&param);
+ param.type = ODP_QUEUE_TYPE_SCHED;
+ param.sched.prio = ODP_SCHED_PRIO_NORMAL;
+ param.sched.sync = ODP_SCHED_SYNC_PARALLEL;
+ param.sched.group = ODP_SCHED_GROUP_ALL;
+ param.size = pkts_per_group;
+
+ queue = odp_queue_create(NULL, &param);
+ if (queue == ODP_QUEUE_INVALID) {
+ LOG_ERR("Error: odp_queue_create() failed\n");
+ return -1;
+ }
+ gbl_args->queue[i][j] = queue;
+ }
+ }
+
+ /* Create packet pool */
+ if (odp_pool_capability(&pool_capa)) {
+ LOG_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)) {
+ LOG_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)) {
+ LOG_ERR("Error: min %dB of packet user area required\n",
+ (int)sizeof(test_hdr_t));
+ exit(EXIT_FAILURE);
+ }
+
+ odp_pool_param_init(&params);
+ 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);
+ params.type = ODP_POOL_PACKET;
+ pool = odp_pool_create("pkt_pool", &params);
+ if (pool == ODP_POOL_INVALID) {
+ LOG_ERR("Error: packet pool create failed\n");
+ exit(EXIT_FAILURE);
+ }
+ odp_pool_print(pool);
+
+ 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_event_t ev;
+ odp_queue_t queue;
+ uint16_t group = i % num_groups;
+
+ if (pkt == ODP_PACKET_INVALID) {
+ LOG_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];
+
+ ev = odp_packet_to_event(pkt);
+ if (odp_queue_enq(queue, ev)) {
+ LOG_ERR("Error: odp_queue_enq() failed\n");
+ return -1;
+ }
+ }
+
+ memset(thread_tbl, 0, sizeof(thread_tbl));
+ 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 */
+ cpu = odp_cpumask_first(&cpumask);
+ for (i = 0; i < num_workers; i++) {
+ odp_cpumask_t thd_mask;
+ odph_odpthread_params_t thr_params;
+
+ gbl_args->thread[i].idx = i;
+
+ memset(&thr_params, 0, sizeof(thr_params));
+ thr_params.start = run_thread;
+ thr_params.arg = &gbl_args->thread[i];
+ thr_params.thr_type = ODP_THREAD_WORKER;
+ thr_params.instance = instance;
+
+ stats[i] = &gbl_args->thread[i].stats;
+
+ odp_cpumask_zero(&thd_mask);
+ odp_cpumask_set(&thd_mask, cpu);
+ odph_odpthreads_create(&thread_tbl[i], &thd_mask,
+ &thr_params);
+ cpu = odp_cpumask_next(&cpumask, cpu);
+ }
+
+ ret = print_stats(num_workers, stats, gbl_args->appl.time,
+ gbl_args->appl.accuracy);
+
+ /* Master thread waits for other threads to exit */
+ for (i = 0; i < num_workers; ++i)
+ odph_odpthreads_join(&thread_tbl[i]);
+
+ for (i = 0; i < num_groups; i++) {
+ for (j = 0; j < QUEUES_PER_GROUP; j++) {
+ if (odp_queue_destroy(gbl_args->queue[i][j])) {
+ LOG_ERR("Error: queue destroy\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ if (odp_pool_destroy(pool)) {
+ LOG_ERR("Error: pool destroy\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (odp_shm_free(shm)) {
+ LOG_ERR("Error: shm free\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (odp_shm_free(lookup_tbl_shm)) {
+ LOG_ERR("Error: shm free\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (odp_term_local()) {
+ LOG_ERR("Error: term local\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (odp_term_global(instance)) {
+ LOG_ERR("Error: term global\n");
+ exit(EXIT_FAILURE);
+ }
+
+ return ret;
+}
diff --git a/test/performance/odp_l2fwd.c b/test/performance/odp_l2fwd.c
index ff14ab2f..16336392 100644
--- a/test/performance/odp_l2fwd.c
+++ b/test/performance/odp_l2fwd.c
@@ -25,7 +25,7 @@
#include <odp/helper/odph_api.h>
/* Maximum number of worker threads */
-#define MAX_WORKERS 32
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/* Size of the shared memory block */
#define POOL_PKT_NUM (16 * 1024)
@@ -75,7 +75,7 @@ static inline int sched_mode(pktin_mode_t in_mode)
*/
typedef struct {
int extra_check; /* Some extra checks have been enabled */
- int cpu_count;
+ unsigned int cpu_count;
int if_count; /* Number of interfaces to be used */
int addr_count; /* Number of dst addresses to be used */
int num_workers; /* Number of worker threads */
@@ -1125,7 +1125,7 @@ static void usage(char *progname)
" -o, --out_mode <arg> Packet output mode\n"
" 0: Direct mode: PKTOUT_MODE_DIRECT (default)\n"
" 1: Queue mode: PKTOUT_MODE_QUEUE\n"
- " -c, --count <num> CPU count.\n"
+ " -c, --count <num> CPU count, 0=all available, default=1\n"
" -t, --time <sec> Time in seconds to run.\n"
" -a, --accuracy <sec> Time in seconds get print statistics\n"
" (default is 1 second).\n"
@@ -1188,6 +1188,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
appl_args->time = 0; /* loop forever if time to run is 0 */
appl_args->accuracy = 1; /* get and print pps stats second */
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->dst_change = 1; /* change eth dst address by default */
appl_args->src_change = 1; /* change eth src address by default */
appl_args->num_groups = 0; /* use default group */
@@ -1492,9 +1493,8 @@ int main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &gbl_args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (gbl_args->appl.cpu_count)
+ if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
num_workers = gbl_args->appl.cpu_count;
/* Get default worker cpumask */
diff --git a/test/performance/odp_pktio_ordered.c b/test/performance/odp_pktio_ordered.c
index ec6c4faa..e884d38a 100644
--- a/test/performance/odp_pktio_ordered.c
+++ b/test/performance/odp_pktio_ordered.c
@@ -79,7 +79,7 @@
#define MAX_NUM_PKT (8 * 1024)
/** Maximum number of worker threads */
-#define MAX_WORKERS 64
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
/** Buffer size of the packet pool buffer in bytes*/
#define PKT_POOL_BUF_SIZE 1856
@@ -134,7 +134,7 @@ typedef enum pktin_mode_t {
* Parsed command line application arguments
*/
typedef struct {
- int cpu_count; /**< CPU count */
+ unsigned int cpu_count; /**< CPU count */
int if_count; /**< Number of interfaces to be used */
int addr_count; /**< Number of dst addresses to be used */
int num_rx_q; /**< Number of input queues per interface */
@@ -826,7 +826,7 @@ static void usage(char *progname)
" -r, --num_rx_q Number of RX queues per interface\n"
" -f, --num_flows Number of packet flows\n"
" -e, --extra_input <number> Number of extra input processing rounds\n"
- " -c, --count <number> CPU count.\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -t, --time <number> Time in seconds to run.\n"
" -a, --accuracy <number> Statistics print interval in seconds\n"
" (default is 1 second).\n"
@@ -872,6 +872,7 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
appl_args->time = 0; /* loop forever if time to run is 0 */
appl_args->accuracy = DEF_STATS_INT;
+ appl_args->cpu_count = 1; /* use one worker by default */
appl_args->num_rx_q = DEF_NUM_RX_QUEUES;
appl_args->num_flows = DEF_NUM_FLOWS;
appl_args->extra_rounds = DEF_EXTRA_ROUNDS;
@@ -997,12 +998,6 @@ static void parse_args(int argc, char *argv[], appl_args_t *appl_args)
}
}
- if (appl_args->cpu_count > MAX_WORKERS) {
- printf("Too many workers requested %d, max: %d\n",
- appl_args->cpu_count, MAX_WORKERS);
- exit(EXIT_FAILURE);
- }
-
if (appl_args->num_flows > MAX_FLOWS) {
printf("Too many flows requested %d, max: %d\n",
appl_args->num_flows, MAX_FLOWS);
@@ -1136,9 +1131,8 @@ int main(int argc, char *argv[])
/* Print both system and application information */
print_info(NO_PATH(argv[0]), &gbl_args->appl);
- /* Default to system CPU count unless user specified */
num_workers = MAX_WORKERS;
- if (gbl_args->appl.cpu_count)
+ if (gbl_args->appl.cpu_count && gbl_args->appl.cpu_count < MAX_WORKERS)
num_workers = gbl_args->appl.cpu_count;
/* Get default worker cpumask */
diff --git a/test/performance/odp_pktio_perf.c b/test/performance/odp_pktio_perf.c
index 2791856a..7ddf8250 100644
--- a/test/performance/odp_pktio_perf.c
+++ b/test/performance/odp_pktio_perf.c
@@ -39,7 +39,7 @@
#define PKT_BUF_NUM (32 * 1024)
#define MAX_NUM_IFACES 2
#define TEST_HDR_MAGIC 0x92749451
-#define MAX_WORKERS 128
+#define MAX_WORKERS (ODP_THREAD_COUNT_MAX - 1)
#define BATCH_LEN_MAX 32
/* Packet rate at which to start when using binary search */
@@ -70,7 +70,7 @@
/** Parsed command line application arguments */
typedef struct {
- int cpu_count; /* CPU count */
+ unsigned int cpu_count; /* CPU count */
int num_tx_workers;/* Number of CPUs to use for transmit */
int duration; /* Number of seconds to run each iteration
of the test for */
@@ -918,8 +918,7 @@ static int test_term(void)
static void usage(void)
{
printf("\nUsage: odp_pktio_perf [options]\n\n");
- printf(" -c, --count <number> CPU count\n");
- printf(" default: all available\n");
+ printf(" -c, --count <number> CPU count, 0=all available, default=2\n");
printf(" -t, --txcount <number> Number of CPUs to use for TX\n");
printf(" default: cpu_count+1/2\n");
printf(" -b, --txbatch <length> Number of packets per TX batch\n");
@@ -963,7 +962,7 @@ static void parse_args(int argc, char *argv[], test_args_t *args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
- args->cpu_count = 0; /* all CPUs */
+ args->cpu_count = 2;
args->num_tx_workers = 0; /* defaults to cpu_count+1/2 */
args->tx_batch_len = BATCH_LEN_MAX;
args->rx_batch_len = BATCH_LEN_MAX;
diff --git a/test/performance/odp_pool_perf.c b/test/performance/odp_pool_perf.c
new file mode 100644
index 00000000..4a77f327
--- /dev/null
+++ b/test/performance/odp_pool_perf.c
@@ -0,0 +1,401 @@
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <odp_api.h>
+#include <odp/helper/odph_api.h>
+
+typedef struct test_options_t {
+ uint32_t num_cpu;
+ uint32_t num_event;
+ uint32_t num_round;
+ uint32_t max_burst;
+
+} test_options_t;
+
+typedef struct test_stat_t {
+ uint64_t rounds;
+ uint64_t frees;
+ uint64_t events;
+ uint64_t nsec;
+ uint64_t cycles;
+
+} test_stat_t;
+
+typedef struct test_global_t {
+ test_options_t test_options;
+
+ odp_barrier_t barrier;
+ odp_pool_t pool;
+ odp_cpumask_t cpumask;
+ odph_odpthread_t thread_tbl[ODP_THREAD_COUNT_MAX];
+ test_stat_t stat[ODP_THREAD_COUNT_MAX];
+
+} test_global_t;
+
+test_global_t test_global;
+
+static void print_usage(void)
+{
+ printf("\n"
+ "Pool performance test\n"
+ "\n"
+ "Usage: odp_pool_perf [options]\n"
+ "\n"
+ " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default 1.\n"
+ " -e, --num_event Number of events\n"
+ " -r, --num_round Number of rounds\n"
+ " -b, --burst Maximum number of events per operation\n"
+ " -h, --help This help\n"
+ "\n");
+}
+
+static int parse_options(int argc, char *argv[], test_options_t *test_options)
+{
+ int opt;
+ int long_index;
+ int ret = 0;
+
+ static const struct option longopts[] = {
+ {"num_cpu", required_argument, NULL, 'c'},
+ {"num_event", required_argument, NULL, 'e'},
+ {"num_round", required_argument, NULL, 'r'},
+ {"burst", required_argument, NULL, 'b'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ static const char *shortopts = "+c:e:r:b:h";
+
+ test_options->num_cpu = 1;
+ test_options->num_event = 1000;
+ test_options->num_round = 100000;
+ test_options->max_burst = 100;
+
+ while (1) {
+ opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'c':
+ test_options->num_cpu = atoi(optarg);
+ break;
+ case 'e':
+ test_options->num_event = atoi(optarg);
+ break;
+ case 'r':
+ test_options->num_round = atoi(optarg);
+ break;
+ case 'b':
+ test_options->max_burst = atoi(optarg);
+ break;
+ case 'h':
+ /* fall through */
+ default:
+ print_usage();
+ ret = -1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int set_num_cpu(test_global_t *global)
+{
+ int ret;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+
+ /* One thread used for the main thread */
+ if (num_cpu > ODP_THREAD_COUNT_MAX - 1) {
+ printf("Error: Too many workers. Maximum is %i.\n",
+ ODP_THREAD_COUNT_MAX - 1);
+ return -1;
+ }
+
+ ret = odp_cpumask_default_worker(&global->cpumask, num_cpu);
+
+ if (num_cpu && ret != num_cpu) {
+ printf("Error: Too many workers. Max supported %i\n.", ret);
+ return -1;
+ }
+
+ /* Zero: all available workers */
+ if (num_cpu == 0) {
+ num_cpu = ret;
+ test_options->num_cpu = num_cpu;
+ }
+
+ odp_barrier_init(&global->barrier, num_cpu);
+
+ return 0;
+}
+
+static int create_pool(test_global_t *global)
+{
+ odp_pool_capability_t pool_capa;
+ odp_pool_param_t pool_param;
+ odp_pool_t pool;
+ test_options_t *test_options = &global->test_options;
+ uint32_t num_event = test_options->num_event;
+ uint32_t num_round = test_options->num_round;
+ uint32_t max_burst = test_options->max_burst;
+ uint32_t num_cpu = test_options->num_cpu;
+
+ printf("\nPool performance test\n");
+ printf(" num cpu %u\n", num_cpu);
+ printf(" num rounds %u\n", num_round);
+ printf(" num events %u\n", num_event);
+ printf(" max burst %u\n\n", max_burst);
+
+ if (odp_pool_capability(&pool_capa)) {
+ printf("Error: Pool capa failed.\n");
+ return -1;
+ }
+
+ if (num_event > pool_capa.buf.max_num) {
+ printf("Max events supported %u\n", pool_capa.buf.max_num);
+ return -1;
+ }
+
+ odp_pool_param_init(&pool_param);
+ pool_param.type = ODP_POOL_BUFFER;
+ pool_param.buf.num = num_event;
+
+ pool = odp_pool_create("pool perf", &pool_param);
+
+ if (pool == ODP_POOL_INVALID) {
+ printf("Error: Pool create failed.\n");
+ return -1;
+ }
+
+ global->pool = pool;
+
+ return 0;
+}
+
+static int test_pool(void *arg)
+{
+ int num, ret, thr;
+ uint32_t i, rounds;
+ uint64_t c1, c2, cycles, nsec;
+ uint64_t events, frees;
+ odp_time_t t1, t2;
+ test_global_t *global = arg;
+ test_options_t *test_options = &global->test_options;
+ uint32_t num_round = test_options->num_round;
+ uint32_t max_burst = test_options->max_burst;
+ odp_pool_t pool = global->pool;
+ odp_buffer_t buf[max_burst];
+
+ thr = odp_thread_id();
+
+ for (i = 0; i < max_burst; i++)
+ buf[i] = ODP_BUFFER_INVALID;
+
+ events = 0;
+ frees = 0;
+ ret = 0;
+
+ /* Start all workers at the same time */
+ odp_barrier_wait(&global->barrier);
+
+ t1 = odp_time_local();
+ c1 = odp_cpu_cycles();
+
+ for (rounds = 0; rounds < num_round; rounds++) {
+ num = odp_buffer_alloc_multi(pool, buf, max_burst);
+
+ if (odp_likely(num > 0)) {
+ events += num;
+ odp_buffer_free_multi(buf, num);
+ frees++;
+ continue;
+ }
+
+ if (num < 0) {
+ printf("Error: Alloc failed. Round %u\n", rounds);
+ ret = -1;
+ break;
+ }
+ }
+
+ c2 = odp_cpu_cycles();
+ t2 = odp_time_local();
+
+ nsec = odp_time_diff_ns(t2, t1);
+ cycles = odp_cpu_cycles_diff(c2, c1);
+
+ /* Update stats*/
+ global->stat[thr].rounds = rounds;
+ global->stat[thr].frees = frees;
+ global->stat[thr].events = events;
+ global->stat[thr].nsec = nsec;
+ global->stat[thr].cycles = cycles;
+
+ return ret;
+}
+
+static int start_workers(test_global_t *global, odp_instance_t instance)
+{
+ odph_odpthread_params_t thr_params;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+
+ memset(&thr_params, 0, sizeof(thr_params));
+ thr_params.thr_type = ODP_THREAD_WORKER;
+ thr_params.instance = instance;
+ thr_params.start = test_pool;
+ thr_params.arg = global;
+
+ if (odph_odpthreads_create(global->thread_tbl, &global->cpumask,
+ &thr_params) != num_cpu)
+ return -1;
+
+ return 0;
+}
+
+static void print_stat(test_global_t *global)
+{
+ int i, num;
+ double rounds_ave, frees_ave, events_ave, nsec_ave, cycles_ave;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+ uint64_t rounds_sum = 0;
+ uint64_t frees_sum = 0;
+ uint64_t events_sum = 0;
+ uint64_t nsec_sum = 0;
+ uint64_t cycles_sum = 0;
+
+ /* Averages */
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+ rounds_sum += global->stat[i].rounds;
+ frees_sum += global->stat[i].frees;
+ events_sum += global->stat[i].events;
+ nsec_sum += global->stat[i].nsec;
+ cycles_sum += global->stat[i].cycles;
+ }
+
+ if (rounds_sum == 0) {
+ printf("No results.\n");
+ return;
+ }
+
+ rounds_ave = rounds_sum / num_cpu;
+ frees_ave = frees_sum / num_cpu;
+ events_ave = events_sum / num_cpu;
+ nsec_ave = nsec_sum / num_cpu;
+ cycles_ave = cycles_sum / num_cpu;
+ num = 0;
+
+ printf("RESULTS - per thread (Million events per sec):\n");
+ printf("----------------------------------------------\n");
+ printf(" 1 2 3 4 5 6 7 8 9 10");
+
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+ if (global->stat[i].rounds) {
+ if ((num % 10) == 0)
+ printf("\n ");
+
+ printf("%6.1f ", (1000.0 * global->stat[i].events) /
+ global->stat[i].nsec);
+ num++;
+ }
+ }
+ printf("\n\n");
+
+ printf("RESULTS - average over %i threads:\n", num_cpu);
+ printf("----------------------------------\n");
+ printf(" alloc calls: %.3f\n", rounds_ave);
+ printf(" free calls: %.3f\n", frees_ave);
+ printf(" duration: %.3f msec\n", nsec_ave / 1000000);
+ printf(" num cycles: %.3f M\n", cycles_ave / 1000000);
+ printf(" cycles per round: %.3f\n",
+ cycles_ave / rounds_ave);
+ printf(" cycles per event: %.3f\n",
+ cycles_ave / events_ave);
+ printf(" ave events allocated: %.3f\n",
+ events_ave / rounds_ave);
+ printf(" operations per sec: %.3f M\n",
+ (1000.0 * rounds_ave) / nsec_ave);
+ printf(" events per sec: %.3f M\n\n",
+ (1000.0 * events_ave) / nsec_ave);
+}
+
+int main(int argc, char **argv)
+{
+ odp_instance_t instance;
+ odp_init_t init;
+ test_global_t *global;
+
+ global = &test_global;
+ memset(global, 0, sizeof(test_global_t));
+ global->pool = ODP_POOL_INVALID;
+
+ if (parse_options(argc, argv, &global->test_options))
+ return -1;
+
+ /* List features not to be used */
+ odp_init_param_init(&init);
+ init.not_used.feat.cls = 1;
+ init.not_used.feat.crypto = 1;
+ init.not_used.feat.ipsec = 1;
+ init.not_used.feat.schedule = 1;
+ init.not_used.feat.timer = 1;
+ init.not_used.feat.tm = 1;
+
+ /* Init ODP before calling anything else */
+ if (odp_init_global(&instance, &init, NULL)) {
+ printf("Error: Global init failed.\n");
+ return -1;
+ }
+
+ /* Init this thread */
+ if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+ printf("Error: Local init failed.\n");
+ return -1;
+ }
+
+ if (set_num_cpu(global))
+ return -1;
+
+ if (create_pool(global))
+ return -1;
+
+ /* Start workers */
+ start_workers(global, instance);
+
+ /* Wait workers to exit */
+ odph_odpthreads_join(global->thread_tbl);
+
+ print_stat(global);
+
+ if (odp_pool_destroy(global->pool)) {
+ printf("Error: Pool destroy failed.\n");
+ return -1;
+ }
+
+ if (odp_term_local()) {
+ printf("Error: term local failed.\n");
+ return -1;
+ }
+
+ if (odp_term_global(instance)) {
+ printf("Error: term global failed.\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/test/performance/odp_sched_latency.c b/test/performance/odp_sched_latency.c
index 7e98db18..64a21983 100644
--- a/test/performance/odp_sched_latency.c
+++ b/test/performance/odp_sched_latency.c
@@ -74,7 +74,7 @@ typedef struct {
/** Test arguments */
typedef struct {
- int cpu_count; /**< CPU count */
+ unsigned int cpu_count; /**< CPU count */
odp_schedule_sync_t sync_type; /**< Scheduler sync type */
struct {
int queues; /**< Number of scheduling queues */
@@ -265,7 +265,7 @@ static void print_results(test_globals_t *globals)
test_stat_t total;
test_args_t *args;
uint64_t avg;
- int i, j;
+ unsigned int i, j;
args = &globals->args;
stype = globals->args.sync_type;
@@ -500,7 +500,7 @@ static void usage(void)
"\n"
"Usage: ./odp_sched_latency [options]\n"
"Optional OPTIONS:\n"
- " -c, --count <number> CPU count\n"
+ " -c, --count <number> CPU count, 0=all available, default=1\n"
" -l, --lo-prio-queues <number> Number of low priority scheduled queues\n"
" -t, --hi-prio-queues <number> Number of high priority scheduled queues\n"
" -m, --lo-prio-events-per-queue <number> Number of events per low priority queue\n"
@@ -552,6 +552,7 @@ static void parse_args(int argc, char *argv[], test_args_t *args)
/* Let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ args->cpu_count = 1;
args->sync_type = ODP_SCHED_SYNC_PARALLEL;
args->sample_per_prio = SAMPLE_EVENT_PER_PRIO;
args->prio[LO_PRIO].queues = LO_PRIO_QUEUES;
diff --git a/test/performance/odp_sched_perf.c b/test/performance/odp_sched_perf.c
new file mode 100644
index 00000000..e76725cc
--- /dev/null
+++ b/test/performance/odp_sched_perf.c
@@ -0,0 +1,559 @@
+/* Copyright (c) 2018, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <odp_api.h>
+#include <odp/helper/odph_api.h>
+
+typedef struct test_options_t {
+ uint32_t num_cpu;
+ uint32_t num_event;
+ uint32_t num_round;
+ uint32_t max_burst;
+ int queue_type;
+
+} test_options_t;
+
+typedef struct test_stat_t {
+ uint64_t rounds;
+ uint64_t enqueues;
+ uint64_t events;
+ uint64_t nsec;
+ uint64_t cycles;
+
+} test_stat_t;
+
+typedef struct test_global_t {
+ test_options_t test_options;
+
+ odp_barrier_t barrier;
+ odp_pool_t pool;
+ odp_cpumask_t cpumask;
+ odp_queue_t queue[ODP_THREAD_COUNT_MAX];
+ odph_odpthread_t thread_tbl[ODP_THREAD_COUNT_MAX];
+ test_stat_t stat[ODP_THREAD_COUNT_MAX];
+
+} test_global_t;
+
+test_global_t test_global;
+
+static void print_usage(void)
+{
+ printf("\n"
+ "Scheduler performance test\n"
+ "\n"
+ "Usage: odp_sched_perf [options]\n"
+ "\n"
+ " -c, --num_cpu Number of CPUs (worker threads). 0: all available CPUs. Default 1.\n"
+ " -e, --num_event Number of events per queue\n"
+ " -r, --num_round Number of rounds\n"
+ " -b, --burst Maximum number of events per operation\n"
+ " -t, --type Queue type. 0: parallel, 1: atomic, 2: ordered. Default 0.\n"
+ " -h, --help This help\n"
+ "\n");
+}
+
+static int parse_options(int argc, char *argv[], test_options_t *test_options)
+{
+ int opt;
+ int long_index;
+ int ret = 0;
+
+ static const struct option longopts[] = {
+ {"num_cpu", required_argument, NULL, 'c'},
+ {"num_event", required_argument, NULL, 'e'},
+ {"num_round", required_argument, NULL, 'r'},
+ {"burst", required_argument, NULL, 'b'},
+ {"type", required_argument, NULL, 't'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ static const char *shortopts = "+c:e:r:b:t:h";
+
+ test_options->num_cpu = 1;
+ test_options->num_event = 100;
+ test_options->num_round = 100000;
+ test_options->max_burst = 100;
+ test_options->queue_type = 0;
+
+ while (1) {
+ opt = getopt_long(argc, argv, shortopts, longopts, &long_index);
+
+ if (opt == -1)
+ break;
+
+ switch (opt) {
+ case 'c':
+ test_options->num_cpu = atoi(optarg);
+ break;
+ case 'e':
+ test_options->num_event = atoi(optarg);
+ break;
+ case 'r':
+ test_options->num_round = atoi(optarg);
+ break;
+ case 'b':
+ test_options->max_burst = atoi(optarg);
+ break;
+ case 't':
+ test_options->queue_type = atoi(optarg);
+ break;
+ case 'h':
+ /* fall through */
+ default:
+ print_usage();
+ ret = -1;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int set_num_cpu(test_global_t *global)
+{
+ int ret;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+
+ /* One thread used for the main thread */
+ if (num_cpu > ODP_THREAD_COUNT_MAX - 1) {
+ printf("Error: Too many workers. Maximum is %i.\n",
+ ODP_THREAD_COUNT_MAX - 1);
+ return -1;
+ }
+
+ ret = odp_cpumask_default_worker(&global->cpumask, num_cpu);
+
+ if (num_cpu && ret != num_cpu) {
+ printf("Error: Too many workers. Max supported %i\n.", ret);
+ return -1;
+ }
+
+ /* Zero: all available workers */
+ if (num_cpu == 0) {
+ num_cpu = ret;
+ test_options->num_cpu = num_cpu;
+ }
+
+ odp_barrier_init(&global->barrier, num_cpu);
+
+ return 0;
+}
+
+static int create_pool(test_global_t *global)
+{
+ odp_pool_capability_t pool_capa;
+ odp_pool_param_t pool_param;
+ odp_pool_t pool;
+ test_options_t *test_options = &global->test_options;
+ uint32_t num_event = test_options->num_event;
+ uint32_t num_round = test_options->num_round;
+ uint32_t max_burst = test_options->max_burst;
+ int num_cpu = test_options->num_cpu;
+ uint32_t tot_event = num_event * num_cpu;
+
+ printf("\nScheduler performance test\n");
+ printf(" num cpu %i\n", num_cpu);
+ printf(" num rounds %u\n", num_round);
+ printf(" num events %u\n", tot_event);
+ printf(" events per queue %u\n", num_event);
+ printf(" max burst %u\n", max_burst);
+
+ if (odp_pool_capability(&pool_capa)) {
+ printf("Error: Pool capa failed.\n");
+ return -1;
+ }
+
+ if (tot_event > pool_capa.buf.max_num) {
+ printf("Max events supported %u\n", pool_capa.buf.max_num);
+ return -1;
+ }
+
+ odp_pool_param_init(&pool_param);
+ pool_param.type = ODP_POOL_BUFFER;
+ pool_param.buf.num = tot_event;
+
+ pool = odp_pool_create("sched perf", &pool_param);
+
+ if (pool == ODP_POOL_INVALID) {
+ printf("Error: Pool create failed.\n");
+ return -1;
+ }
+
+ global->pool = pool;
+
+ return 0;
+}
+
+static int create_queues(test_global_t *global)
+{
+ odp_queue_capability_t queue_capa;
+ odp_queue_param_t queue_param;
+ odp_queue_t queue;
+ odp_buffer_t buf;
+ odp_schedule_sync_t sync;
+ const char *type_str;
+ uint32_t i, j;
+ test_options_t *test_options = &global->test_options;
+ uint32_t num_event = test_options->num_event;
+ uint32_t num_queue = test_options->num_cpu;
+ int type = test_options->queue_type;
+ odp_pool_t pool = global->pool;
+
+ if (type == 0) {
+ type_str = "parallel";
+ sync = ODP_SCHED_SYNC_PARALLEL;
+ } else if (type == 1) {
+ type_str = "atomic";
+ sync = ODP_SCHED_SYNC_ATOMIC;
+ } else {
+ type_str = "ordered";
+ sync = ODP_SCHED_SYNC_ORDERED;
+ }
+
+ printf(" num queues %u\n", num_queue);
+ printf(" queue type %s\n\n", type_str);
+
+ if (odp_queue_capability(&queue_capa)) {
+ printf("Error: Queue capa failed.\n");
+ return -1;
+ }
+
+ if (num_queue > queue_capa.sched.max_num) {
+ printf("Max queues supported %u\n", queue_capa.sched.max_num);
+ return -1;
+ }
+
+ if (queue_capa.sched.max_size &&
+ num_event > queue_capa.sched.max_size) {
+ printf("Max events per queue %u\n", queue_capa.sched.max_size);
+ return -1;
+ }
+
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++)
+ global->queue[i] = ODP_QUEUE_INVALID;
+
+ odp_queue_param_init(&queue_param);
+ queue_param.type = ODP_QUEUE_TYPE_SCHED;
+ queue_param.sched.prio = ODP_SCHED_PRIO_DEFAULT;
+ queue_param.sched.sync = sync;
+ queue_param.sched.group = ODP_SCHED_GROUP_ALL;
+ queue_param.size = num_event;
+
+ for (i = 0; i < num_queue; i++) {
+ queue = odp_queue_create(NULL, &queue_param);
+
+ if (queue == ODP_QUEUE_INVALID) {
+ printf("Error: Queue create failed %u\n", i);
+ return -1;
+ }
+
+ global->queue[i] = queue;
+ }
+
+ for (i = 0; i < num_queue; i++) {
+ queue = global->queue[i];
+
+ for (j = 0; j < num_event; j++) {
+ buf = odp_buffer_alloc(pool);
+
+ if (buf == ODP_BUFFER_INVALID) {
+ printf("Error: Alloc failed %u/%u\n", i, j);
+ return -1;
+ }
+
+ if (odp_queue_enq(queue, odp_buffer_to_event(buf))) {
+ printf("Error: Enqueue failed %u/%u\n", i, j);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int destroy_queues(test_global_t *global)
+{
+ uint32_t i;
+ odp_event_t ev;
+ uint64_t wait;
+
+ wait = odp_schedule_wait_time(200 * ODP_TIME_MSEC_IN_NS);
+
+ while ((ev = odp_schedule(NULL, wait)) != ODP_EVENT_INVALID)
+ odp_event_free(ev);
+
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+ if (global->queue[i] != ODP_QUEUE_INVALID) {
+ if (odp_queue_destroy(global->queue[i])) {
+ printf("Error: Queue destroy failed %u\n", i);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int test_sched(void *arg)
+{
+ int num, num_enq, ret, thr;
+ uint32_t i, rounds;
+ uint64_t c1, c2, cycles, nsec;
+ uint64_t events, enqueues;
+ odp_time_t t1, t2;
+ odp_queue_t queue;
+ test_global_t *global = arg;
+ test_options_t *test_options = &global->test_options;
+ uint32_t num_round = test_options->num_round;
+ uint32_t max_burst = test_options->max_burst;
+ odp_event_t ev[max_burst];
+
+ thr = odp_thread_id();
+
+ for (i = 0; i < max_burst; i++)
+ ev[i] = ODP_EVENT_INVALID;
+
+ enqueues = 0;
+ events = 0;
+ ret = 0;
+
+ /* Start all workers at the same time */
+ odp_barrier_wait(&global->barrier);
+
+ t1 = odp_time_local();
+ c1 = odp_cpu_cycles();
+
+ for (rounds = 0; rounds < num_round; rounds++) {
+ num = odp_schedule_multi(&queue, ODP_SCHED_NO_WAIT,
+ ev, max_burst);
+
+ if (odp_likely(num > 0)) {
+ events += num;
+ i = 0;
+
+ while (num) {
+ num_enq = odp_queue_enq_multi(queue, &ev[i],
+ num);
+
+ if (num_enq < 0) {
+ printf("Error: Enqueue failed. Round %u\n",
+ rounds);
+ ret = -1;
+ break;
+ }
+
+ num -= num_enq;
+ i += num_enq;
+ enqueues++;
+ }
+
+ if (odp_unlikely(ret))
+ break;
+
+ continue;
+ }
+
+ /* <0 not specified as an error but checking anyway */
+ if (num < 0) {
+ printf("Error: Sched failed. Round %u\n", rounds);
+ ret = -1;
+ break;
+ }
+ }
+
+ c2 = odp_cpu_cycles();
+ t2 = odp_time_local();
+
+ nsec = odp_time_diff_ns(t2, t1);
+ cycles = odp_cpu_cycles_diff(c2, c1);
+
+ /* Update stats*/
+ global->stat[thr].rounds = rounds;
+ global->stat[thr].enqueues = enqueues;
+ global->stat[thr].events = events;
+ global->stat[thr].nsec = nsec;
+ global->stat[thr].cycles = cycles;
+
+ /* Pause scheduling before thread exit */
+ odp_schedule_pause();
+
+ while (1) {
+ ev[0] = odp_schedule(&queue, ODP_SCHED_NO_WAIT);
+
+ if (ev[0] == ODP_EVENT_INVALID)
+ break;
+
+ odp_queue_enq(queue, ev[0]);
+ }
+
+ return ret;
+}
+
+static int start_workers(test_global_t *global, odp_instance_t instance)
+{
+ odph_odpthread_params_t thr_params;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+
+ memset(&thr_params, 0, sizeof(thr_params));
+ thr_params.thr_type = ODP_THREAD_WORKER;
+ thr_params.instance = instance;
+ thr_params.start = test_sched;
+ thr_params.arg = global;
+
+ if (odph_odpthreads_create(global->thread_tbl, &global->cpumask,
+ &thr_params) != num_cpu)
+ return -1;
+
+ return 0;
+}
+
+static void print_stat(test_global_t *global)
+{
+ int i, num;
+ double rounds_ave, enqueues_ave, events_ave, nsec_ave, cycles_ave;
+ test_options_t *test_options = &global->test_options;
+ int num_cpu = test_options->num_cpu;
+ uint64_t rounds_sum = 0;
+ uint64_t enqueues_sum = 0;
+ uint64_t events_sum = 0;
+ uint64_t nsec_sum = 0;
+ uint64_t cycles_sum = 0;
+
+ /* Averages */
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+ rounds_sum += global->stat[i].rounds;
+ enqueues_sum += global->stat[i].enqueues;
+ events_sum += global->stat[i].events;
+ nsec_sum += global->stat[i].nsec;
+ cycles_sum += global->stat[i].cycles;
+ }
+
+ if (rounds_sum == 0) {
+ printf("No results.\n");
+ return;
+ }
+
+ rounds_ave = rounds_sum / num_cpu;
+ enqueues_ave = enqueues_sum / num_cpu;
+ events_ave = events_sum / num_cpu;
+ nsec_ave = nsec_sum / num_cpu;
+ cycles_ave = cycles_sum / num_cpu;
+ num = 0;
+
+ printf("RESULTS - per thread (Million events per sec):\n");
+ printf("----------------------------------------------\n");
+ printf(" 1 2 3 4 5 6 7 8 9 10");
+
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++) {
+ if (global->stat[i].rounds) {
+ if ((num % 10) == 0)
+ printf("\n ");
+
+ printf("%6.1f ", (1000.0 * global->stat[i].events) /
+ global->stat[i].nsec);
+ num++;
+ }
+ }
+ printf("\n\n");
+
+ printf("RESULTS - average over %i threads:\n", num_cpu);
+ printf("----------------------------------\n");
+ printf(" schedule calls: %.3f\n", rounds_ave);
+ printf(" enqueue calls: %.3f\n", enqueues_ave);
+ printf(" duration: %.3f msec\n", nsec_ave / 1000000);
+ printf(" num cycles: %.3f M\n", cycles_ave / 1000000);
+ printf(" cycles per round: %.3f\n",
+ cycles_ave / rounds_ave);
+ printf(" cycles per event: %.3f\n",
+ cycles_ave / events_ave);
+ printf(" ave events received: %.3f\n",
+ events_ave / rounds_ave);
+ printf(" rounds per sec: %.3f M\n",
+ (1000.0 * rounds_ave) / nsec_ave);
+ printf(" events per sec: %.3f M\n\n",
+ (1000.0 * events_ave) / nsec_ave);
+}
+
+int main(int argc, char **argv)
+{
+ odp_instance_t instance;
+ odp_init_t init;
+ test_global_t *global;
+
+ global = &test_global;
+ memset(global, 0, sizeof(test_global_t));
+ global->pool = ODP_POOL_INVALID;
+
+ if (parse_options(argc, argv, &global->test_options))
+ return -1;
+
+ /* List features not to be used */
+ odp_init_param_init(&init);
+ 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 ODP before calling anything else */
+ if (odp_init_global(&instance, &init, NULL)) {
+ printf("Error: Global init failed.\n");
+ return -1;
+ }
+
+ /* Init this thread */
+ if (odp_init_local(instance, ODP_THREAD_CONTROL)) {
+ printf("Error: Local init failed.\n");
+ return -1;
+ }
+
+ if (set_num_cpu(global))
+ return -1;
+
+ if (create_pool(global))
+ return -1;
+
+ if (create_queues(global))
+ return -1;
+
+ /* Start workers */
+ start_workers(global, instance);
+
+ /* Wait workers to exit */
+ odph_odpthreads_join(global->thread_tbl);
+
+ if (destroy_queues(global))
+ return -1;
+
+ print_stat(global);
+
+ if (odp_pool_destroy(global->pool)) {
+ printf("Error: Pool destroy failed.\n");
+ return -1;
+ }
+
+ if (odp_term_local()) {
+ printf("Error: term local failed.\n");
+ return -1;
+ }
+
+ if (odp_term_global(instance)) {
+ printf("Error: term global failed.\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/test/performance/odp_scheduling.c b/test/performance/odp_scheduling.c
index d2fbf894..3b75f635 100644
--- a/test/performance/odp_scheduling.c
+++ b/test/performance/odp_scheduling.c
@@ -51,7 +51,7 @@ typedef struct {
/** Test arguments */
typedef struct {
- int cpu_count; /**< CPU count */
+ unsigned int cpu_count; /**< CPU count */
int fairness; /**< Check fairness */
} test_args_t;
@@ -735,7 +735,7 @@ static void print_usage(void)
{
printf("\n\nUsage: ./odp_example [options]\n");
printf("Options:\n");
- printf(" -c, --count <number> CPU count, 0=all available, default=0\n");
+ printf(" -c, --count <number> CPU count, 0=all available, default=1\n");
printf(" -h, --help this help\n");
printf(" -f, --fair collect fairness statistics\n");
printf("\n\n");
@@ -765,6 +765,8 @@ static void parse_args(int argc, char *argv[], test_args_t *args)
/* let helper collect its own arguments (e.g. --odph_proc) */
argc = odph_parse_options(argc, argv);
+ args->cpu_count = 1; /* use one worker by default */
+
while (1) {
opt = getopt_long(argc, argv, shortopts, longopts, &long_index);