From 5aa387dd83e3aa507ed9297d7975d542f0e5891b Mon Sep 17 00:00:00 2001 From: Maxim Uvarov Date: Wed, 8 Apr 2015 21:22:14 +0300 Subject: validation: move l2fwd from example to performance tests Signed-off-by: Maxim Uvarov Signed-off-by: Ciprian Barbu Reviewed-by: Anders Roxell Reviewed-and-tested-by: Mike Holmes --- example/l2fwd/.gitignore | 1 - example/l2fwd/Makefile.am | 10 - example/l2fwd/odp_l2fwd.c | 685 ---------------------------------------------- 3 files changed, 696 deletions(-) delete mode 100644 example/l2fwd/.gitignore delete mode 100644 example/l2fwd/Makefile.am delete mode 100644 example/l2fwd/odp_l2fwd.c (limited to 'example/l2fwd') diff --git a/example/l2fwd/.gitignore b/example/l2fwd/.gitignore deleted file mode 100644 index 8563319f0..000000000 --- a/example/l2fwd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -odp_l2fwd diff --git a/example/l2fwd/Makefile.am b/example/l2fwd/Makefile.am deleted file mode 100644 index feced2ad2..000000000 --- a/example/l2fwd/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -include $(top_srcdir)/example/Makefile.inc - -bin_PROGRAMS = odp_l2fwd -odp_l2fwd_LDFLAGS = $(AM_LDFLAGS) -static -odp_l2fwd_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example - -noinst_HEADERS = \ - $(top_srcdir)/example/example_debug.h - -dist_odp_l2fwd_SOURCES = odp_l2fwd.c diff --git a/example/l2fwd/odp_l2fwd.c b/example/l2fwd/odp_l2fwd.c deleted file mode 100644 index 4a490084d..000000000 --- a/example/l2fwd/odp_l2fwd.c +++ /dev/null @@ -1,685 +0,0 @@ -/* Copyright (c) 2014, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * @file - * - * @example odp_l2fwd.c ODP basic forwarding application - */ - -/** enable strtok */ -#define _POSIX_C_SOURCE 200112L - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -/** @def MAX_WORKERS - * @brief Maximum number of worker threads - */ -#define MAX_WORKERS 32 - -/** @def SHM_PKT_POOL_SIZE - * @brief Size of the shared memory block - */ -#define SHM_PKT_POOL_SIZE (512*2048) - -/** @def SHM_PKT_POOL_BUF_SIZE - * @brief Buffer size of the packet pool buffer - */ -#define SHM_PKT_POOL_BUF_SIZE 1856 - -/** @def MAX_PKT_BURST - * @brief Maximum number of packet bursts - */ -#define MAX_PKT_BURST 16 - -/** @def APPL_MODE_PKT_BURST - * @brief The application will handle pakcets in bursts - */ -#define APPL_MODE_PKT_BURST 0 - -/** @def APPL_MODE_PKT_QUEUE - * @brief The application will handle packets in queues - */ -#define APPL_MODE_PKT_QUEUE 1 - -/** @def PRINT_APPL_MODE(x) - * @brief Macro to print the current status of how the application handles - * packets. - */ -#define PRINT_APPL_MODE(x) printf("%s(%i)\n", #x, (x)) - -/** 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)) -/** - * Parsed command line application arguments - */ -typedef struct { - int cpu_count; - int if_count; /**< Number of interfaces to be used */ - char **if_names; /**< Array of pointers to interface names */ - int mode; /**< Packet IO mode */ - int time; /**< Time in seconds to run. */ - int accuracy; /**< Number of seconds to get and print statistics */ - char *if_str; /**< Storage for interface names */ -} appl_args_t; - -static int exit_threads; /**< Break workers loop if set to 1 */ - -/** - * Statistics - */ -typedef struct { - uint64_t packets; /**< Number of forwarded packets. */ - uint64_t drops; /**< Number of dropped packets. */ -} stats_t; - -/** - * Thread specific arguments - */ -typedef struct { - int src_idx; /**< Source interface identifier */ - stats_t **stats; /**< Per thread packet stats */ -} thread_args_t; - -/** - * Grouping of all global data - */ -typedef struct { - /** Application (parsed) arguments */ - appl_args_t appl; - /** Thread specific arguments */ - thread_args_t thread[MAX_WORKERS]; - /** Table of pktio handles */ - odp_pktio_t pktios[ODP_CONFIG_PKTIO_ENTRIES]; -} args_t; - -/** Global pointer to args */ -static args_t *gbl_args; - -/* helper funcs */ -static inline odp_queue_t lookup_dest_q(odp_packet_t pkt); -static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len); -static void parse_args(int argc, char *argv[], appl_args_t *appl_args); -static void print_info(char *progname, appl_args_t *appl_args); -static void usage(char *progname); - -/** - * Packet IO worker thread using ODP queues - * - * @param arg thread arguments of type 'thread_args_t *' - */ -static void *pktio_queue_thread(void *arg) -{ - int thr; - odp_queue_t outq_def; - odp_packet_t pkt; - odp_event_t ev; - thread_args_t *thr_args = arg; - - stats_t *stats = calloc(1, sizeof(stats_t)); - *thr_args->stats = stats; - - thr = odp_thread_id(); - - printf("[%02i] QUEUE mode\n", thr); - - /* Loop packets */ - while (!exit_threads) { - /* Use schedule to get buf from any input queue */ - ev = odp_schedule(NULL, ODP_SCHED_WAIT); - pkt = odp_packet_from_event(ev); - - /* Drop packets with errors */ - if (odp_unlikely(drop_err_pkts(&pkt, 1) == 0)) { - stats->drops += 1; - continue; - } - - outq_def = lookup_dest_q(pkt); - - /* Enqueue the packet for output */ - odp_queue_enq(outq_def, ev); - - stats->packets += 1; - } - - free(stats); - return NULL; -} - -/** - * Lookup the destination pktio for a given packet - */ -static inline odp_queue_t lookup_dest_q(odp_packet_t pkt) -{ - int i, src_idx, dst_idx; - odp_pktio_t pktio_src, pktio_dst; - - pktio_src = odp_packet_input(pkt); - - for (src_idx = -1, i = 0; gbl_args->pktios[i] != ODP_PKTIO_INVALID; ++i) - if (gbl_args->pktios[i] == pktio_src) - src_idx = i; - - if (src_idx == -1) - EXAMPLE_ABORT("Failed to determine pktio input\n"); - - dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1; - pktio_dst = gbl_args->pktios[dst_idx]; - - return odp_pktio_outq_getdef(pktio_dst); -} - -/** - * Packet IO worker thread using bursts from/to IO resources - * - * @param arg thread arguments of type 'thread_args_t *' - */ -static void *pktio_ifburst_thread(void *arg) -{ - int thr; - thread_args_t *thr_args; - int pkts, pkts_ok; - odp_packet_t pkt_tbl[MAX_PKT_BURST]; - int src_idx, dst_idx; - odp_pktio_t pktio_src, pktio_dst; - - thr = odp_thread_id(); - thr_args = arg; - - stats_t *stats = calloc(1, sizeof(stats_t)); - *thr_args->stats = stats; - - src_idx = thr_args->src_idx; - dst_idx = (src_idx % 2 == 0) ? src_idx+1 : src_idx-1; - pktio_src = gbl_args->pktios[src_idx]; - pktio_dst = gbl_args->pktios[dst_idx]; - - printf("[%02i] srcif:%s dstif:%s spktio:%02" PRIu64 - " dpktio:%02" PRIu64 " BURST mode\n", - thr, - gbl_args->appl.if_names[src_idx], - gbl_args->appl.if_names[dst_idx], - odp_pktio_to_u64(pktio_src), odp_pktio_to_u64(pktio_dst)); - - /* Loop packets */ - while (!exit_threads) { - pkts = odp_pktio_recv(pktio_src, pkt_tbl, MAX_PKT_BURST); - if (pkts <= 0) - continue; - - /* Drop packets with errors */ - pkts_ok = drop_err_pkts(pkt_tbl, pkts); - if (pkts_ok > 0) - odp_pktio_send(pktio_dst, pkt_tbl, pkts_ok); - - if (odp_unlikely(pkts_ok != pkts)) - stats->drops += pkts - pkts_ok; - - if (pkts_ok == 0) - continue; - - stats->packets += pkts_ok; - } - - free(stats); - return NULL; -} - -/** - * Create a pktio handle, optionally associating a default input queue. - * - * @param dev Name of device to open - * @param pool Pool to associate with device for packet RX/TX - * @param mode Packet processing mode for this device (BURST or QUEUE) - * - * @return The handle of the created pktio object. - * @retval ODP_PKTIO_INVALID if the create fails. - */ -static odp_pktio_t create_pktio(const char *dev, odp_pool_t pool, - int mode) -{ - char inq_name[ODP_QUEUE_NAME_LEN]; - odp_queue_param_t qparam; - odp_queue_t inq_def; - odp_pktio_t pktio; - int ret; - - pktio = odp_pktio_open(dev, pool); - if (pktio == ODP_PKTIO_INVALID) { - EXAMPLE_ERR("Error: failed to open %s\n", dev); - return ODP_PKTIO_INVALID; - } - - printf("created pktio %" PRIu64 " (%s)\n", - odp_pktio_to_u64(pktio), dev); - - /* no further setup needed for burst mode */ - if (mode == APPL_MODE_PKT_BURST) - return pktio; - - qparam.sched.prio = ODP_SCHED_PRIO_DEFAULT; - qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC; - qparam.sched.group = ODP_SCHED_GROUP_DEFAULT; - snprintf(inq_name, sizeof(inq_name), "%" PRIu64 "-pktio_inq_def", - odp_pktio_to_u64(pktio)); - inq_name[ODP_QUEUE_NAME_LEN - 1] = '\0'; - - inq_def = odp_queue_create(inq_name, ODP_QUEUE_TYPE_PKTIN, &qparam); - if (inq_def == ODP_QUEUE_INVALID) { - EXAMPLE_ERR("Error: pktio queue creation failed\n"); - return ODP_PKTIO_INVALID; - } - - ret = odp_pktio_inq_setdef(pktio, inq_def); - if (ret != 0) { - EXAMPLE_ERR("Error: default input-Q setup\n"); - return ODP_PKTIO_INVALID; - } - - return pktio; -} - -/** - * Print statistics - * - * @param num_workers Number of worker threads - * @param thr_stats Pointer to stats storage - * @param duration Number of seconds to loop in - * @param timeout Number of seconds for stats calculation - * - */ -static void print_speed_stats(int num_workers, stats_t **thr_stats, - int duration, int timeout) -{ - uint64_t pkts, pkts_prev = 0, pps, drops, maximum_pps = 0; - int i, elapsed = 0; - int loop_forever = (duration == 0); - - do { - pkts = 0; - drops = 0; - - sleep(timeout); - - for (i = 0; i < num_workers; i++) { - pkts += thr_stats[i]->packets; - drops += thr_stats[i]->drops; - } - pps = (pkts - pkts_prev) / timeout; - if (pps > maximum_pps) - maximum_pps = pps; - printf("%" PRIu64 " pps, %" PRIu64 " max pps, ", pps, - maximum_pps); - - printf(" %" PRIu64 " total drops\n", drops); - - elapsed += timeout; - pkts_prev = pkts; - } while (loop_forever || (elapsed < duration)); - - printf("TEST RESULT: %" PRIu64 " maximum packets per second.\n", - maximum_pps); - return; -} - -/** - * ODP L2 forwarding main function - */ -int main(int argc, char *argv[]) -{ - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; - odp_pool_t pool; - int i; - int cpu; - int num_workers; - odp_shm_t shm; - odp_cpumask_t cpumask; - char cpumaskstr[ODP_CPUMASK_STR_SIZE]; - odp_pool_param_t params; - - /* Init ODP before calling anything else */ - if (odp_init_global(NULL, NULL)) { - EXAMPLE_ERR("Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Init this thread */ - if (odp_init_local()) { - EXAMPLE_ERR("Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - /* Reserve memory for args from shared mem */ - shm = odp_shm_reserve("shm_args", sizeof(args_t), - ODP_CACHE_LINE_SIZE, 0); - gbl_args = odp_shm_addr(shm); - - if (gbl_args == NULL) { - EXAMPLE_ERR("Error: shared mem alloc failed.\n"); - exit(EXIT_FAILURE); - } - memset(gbl_args, 0, sizeof(*gbl_args)); - - /* Parse and store the application arguments */ - parse_args(argc, argv, &gbl_args->appl); - - /* 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) - num_workers = gbl_args->appl.cpu_count; - - /* - * By default CPU #0 runs Linux kernel background tasks. - * Start mapping thread from CPU #1 - */ - num_workers = odph_linux_cpumask_default(&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); - - if (num_workers < gbl_args->appl.if_count) { - EXAMPLE_ERR("Error: CPU count %d less than interface count\n", - num_workers); - exit(EXIT_FAILURE); - } - if (gbl_args->appl.if_count % 2 != 0) { - EXAMPLE_ERR("Error: interface count %d is odd in fwd appl.\n", - gbl_args->appl.if_count); - exit(EXIT_FAILURE); - } - - /* Create packet pool */ - memset(¶ms, 0, sizeof(params)); - params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.len = SHM_PKT_POOL_BUF_SIZE; - params.pkt.num = SHM_PKT_POOL_SIZE/SHM_PKT_POOL_BUF_SIZE; - params.type = ODP_POOL_PACKET; - - pool = odp_pool_create("packet pool", ODP_SHM_NULL, ¶ms); - - if (pool == ODP_POOL_INVALID) { - EXAMPLE_ERR("Error: packet pool create failed.\n"); - exit(EXIT_FAILURE); - } - odp_pool_print(pool); - - for (i = 0; i < gbl_args->appl.if_count; ++i) { - gbl_args->pktios[i] = create_pktio(gbl_args->appl.if_names[i], - pool, gbl_args->appl.mode); - if (gbl_args->pktios[i] == ODP_PKTIO_INVALID) - exit(EXIT_FAILURE); - } - gbl_args->pktios[i] = ODP_PKTIO_INVALID; - - memset(thread_tbl, 0, sizeof(thread_tbl)); - - stats_t **stats = calloc(1, sizeof(stats_t) * num_workers); - - /* Create worker threads */ - cpu = odp_cpumask_first(&cpumask); - for (i = 0; i < num_workers; ++i) { - odp_cpumask_t thd_mask; - void *(*thr_run_func) (void *); - - if (gbl_args->appl.mode == APPL_MODE_PKT_BURST) - thr_run_func = pktio_ifburst_thread; - else /* APPL_MODE_PKT_QUEUE */ - thr_run_func = pktio_queue_thread; - - gbl_args->thread[i].src_idx = i % gbl_args->appl.if_count; - gbl_args->thread[i].stats = &stats[i]; - - odp_cpumask_zero(&thd_mask); - odp_cpumask_set(&thd_mask, cpu); - odph_linux_pthread_create(&thread_tbl[i], &thd_mask, - thr_run_func, - &gbl_args->thread[i]); - cpu = odp_cpumask_next(&cpumask, cpu); - } - - print_speed_stats(num_workers, stats, gbl_args->appl.time, - gbl_args->appl.accuracy); - free(stats); - exit_threads = 1; - - /* Master thread waits for other threads to exit */ - odph_linux_pthread_join(thread_tbl, num_workers); - - free(gbl_args->appl.if_names); - free(gbl_args->appl.if_str); - printf("Exit\n\n"); - - return 0; -} - -/** - * Drop packets which input parsing marked as containing errors. - * - * Frees packets with error and modifies pkt_tbl[] to only contain packets with - * no detected errors. - * - * @param pkt_tbl Array of packet - * @param len Length of pkt_tbl[] - * - * @return Number of packets with no detected error - */ -static int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) -{ - odp_packet_t pkt; - unsigned pkt_cnt = len; - unsigned i, j; - - for (i = 0, j = 0; i < len; ++i) { - pkt = pkt_tbl[i]; - - if (odp_unlikely(odp_packet_has_error(pkt))) { - odp_packet_free(pkt); /* Drop */ - pkt_cnt--; - } else if (odp_unlikely(i != j++)) { - pkt_tbl[j-1] = pkt; - } - } - - return pkt_cnt; -} - -/** - * Parse and store the command line arguments - * - * @param argc argument count - * @param argv[] argument vector - * @param appl_args Store application arguments here - */ -static void parse_args(int argc, char *argv[], appl_args_t *appl_args) -{ - int opt; - int long_index; - char *token; - size_t len; - int i; - static struct option longopts[] = { - {"count", required_argument, NULL, 'c'}, - {"time", required_argument, NULL, 't'}, - {"accuracy", required_argument, NULL, 'a'}, - {"interface", required_argument, NULL, 'i'}, /* return 'i' */ - {"mode", required_argument, NULL, 'm'}, /* return 'm' */ - {"help", no_argument, NULL, 'h'}, /* return 'h' */ - {NULL, 0, NULL, 0} - }; - - appl_args->time = 0; /* loop forever if time to run is 0 */ - appl_args->accuracy = 1; /* get and print pps stats second */ - appl_args->mode = -1; /* Invalid, must be changed by parsing */ - - while (1) { - opt = getopt_long(argc, argv, "+c:+t:+a:i:m:h", - longopts, &long_index); - - if (opt == -1) - break; /* No more options */ - - switch (opt) { - case 'c': - appl_args->cpu_count = atoi(optarg); - break; - case 't': - appl_args->time = atoi(optarg); - break; - case 'a': - appl_args->accuracy = atoi(optarg); - break; - /* parse packet-io interface names */ - case 'i': - len = strlen(optarg); - if (len == 0) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - len += 1; /* add room for '\0' */ - - appl_args->if_str = malloc(len); - if (appl_args->if_str == NULL) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* count the number of tokens separated by ',' */ - strcpy(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; - token = strtok(NULL, ","), i++) - ; - - appl_args->if_count = i; - - if (appl_args->if_count == 0) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - /* allocate storage for the if names */ - appl_args->if_names = - calloc(appl_args->if_count, sizeof(char *)); - - /* store the if names (reset names string) */ - strcpy(appl_args->if_str, optarg); - for (token = strtok(appl_args->if_str, ","), i = 0; - token != NULL; token = strtok(NULL, ","), i++) { - appl_args->if_names[i] = token; - } - break; - - case 'm': - i = atoi(optarg); - if (i == 0) - appl_args->mode = APPL_MODE_PKT_BURST; - else - appl_args->mode = APPL_MODE_PKT_QUEUE; - break; - - case 'h': - usage(argv[0]); - exit(EXIT_SUCCESS); - break; - - default: - break; - } - } - - if (appl_args->if_count == 0 || appl_args->mode == -1) { - usage(argv[0]); - exit(EXIT_FAILURE); - } - - optind = 1; /* reset 'extern optind' from the getopt lib */ -} - -/** - * Print system and application info - */ -static void print_info(char *progname, appl_args_t *appl_args) -{ - int i; - - printf("\n" - "ODP system info\n" - "---------------\n" - "ODP API version: %s\n" - "CPU model: %s\n" - "CPU freq (hz): %"PRIu64"\n" - "Cache line size: %i\n" - "CPU count: %i\n" - "\n", - odp_version_api_str(), odp_sys_cpu_model_str(), odp_sys_cpu_hz(), - odp_sys_cache_line_size(), odp_cpu_count()); - - printf("Running ODP appl: \"%s\"\n" - "-----------------\n" - "IF-count: %i\n" - "Using IFs: ", - progname, appl_args->if_count); - for (i = 0; i < appl_args->if_count; ++i) - printf(" %s", appl_args->if_names[i]); - printf("\n" - "Mode: "); - if (appl_args->mode == APPL_MODE_PKT_BURST) - PRINT_APPL_MODE(APPL_MODE_PKT_BURST); - else - PRINT_APPL_MODE(APPL_MODE_PKT_QUEUE); - printf("\n\n"); - fflush(NULL); -} - -/** - * Prinf usage information - */ -static void usage(char *progname) -{ - printf("\n" - "OpenDataPlane L2 forwarding application.\n" - "\n" - "Usage: %s OPTIONS\n" - " E.g. %s -i eth0,eth1,eth2,eth3 -m 0 -t 1\n" - " In the above example,\n" - " eth0 will send pkts to eth1 and vice versa\n" - " eth2 will send pkts to eth3 and vice versa\n" - "\n" - "Mandatory OPTIONS:\n" - " -i, --interface Eth interfaces (comma-separated, no spaces)\n" - " -m, --mode 0: Burst send&receive packets (no queues)\n" - " 1: Send&receive packets through ODP queues.\n" - "\n" - "Optional OPTIONS\n" - " -c, --count CPU count.\n" - " -t, --time Time in seconds to run.\n" - " -a, --accuracy Time in seconds get print statistics\n" - " (default is 1 second).\n" - " -h, --help Display help and exit.\n\n" - " environment variables: ODP_PKTIO_DISABLE_SOCKET_MMAP\n" - " ODP_PKTIO_DISABLE_SOCKET_MMSG\n" - " ODP_PKTIO_DISABLE_SOCKET_BASIC\n" - " can be used to advanced pkt I/O selection for linux-generic\n" - "\n", NO_PATH(progname), NO_PATH(progname) - ); -} -- cgit v1.2.3