On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <[email protected]> wrote:
> Simple example app creates one packet i/o to external interface
> and one ipc pktio to other process. Then transfer packet from
> external interface to other process and back thought ipc queue.
>
> Signed-off-by: Maxim Uvarov <[email protected]>
> ---
>  configure.ac            |   1 +
>  example/Makefile.am     |   2 +-
>  example/ipc/.gitignore  |   1 +
>  example/ipc/Makefile.am |   7 +
>  example/ipc/odp_ipc.c   | 445 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 455 insertions(+), 1 deletion(-)
>  create mode 100644 example/ipc/.gitignore
>  create mode 100644 example/ipc/Makefile.am
>  create mode 100644 example/ipc/odp_ipc.c
>
> diff --git a/configure.ac b/configure.ac
> index d20bad2..1ceb922 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -274,6 +274,7 @@ AC_CONFIG_FILES([Makefile
>                  example/Makefile
>                  example/classifier/Makefile
>                  example/generator/Makefile
> +                example/ipc/Makefile
>                  example/ipsec/Makefile
>                  example/packet/Makefile
>                  example/timer/Makefile
> diff --git a/example/Makefile.am b/example/Makefile.am
> index 353f397..506963f 100644
> --- a/example/Makefile.am
> +++ b/example/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = classifier generator ipsec packet timer
> +SUBDIRS = classifier generator ipc ipsec packet timer
> diff --git a/example/ipc/.gitignore b/example/ipc/.gitignore
> new file mode 100644
> index 0000000..963d99d
> --- /dev/null
> +++ b/example/ipc/.gitignore
> @@ -0,0 +1 @@
> +odp_ipc
> diff --git a/example/ipc/Makefile.am b/example/ipc/Makefile.am
> new file mode 100644
> index 0000000..3da9549
> --- /dev/null
> +++ b/example/ipc/Makefile.am
> @@ -0,0 +1,7 @@
> +include $(top_srcdir)/example/Makefile.inc
> +
> +bin_PROGRAMS = odp_ipc
> +odp_ipc_LDFLAGS = $(AM_LDFLAGS) -static
> +odp_ipc_CFLAGS = $(AM_CFLAGS) -I${top_srcdir}/example
> +
> +dist_odp_ipc_SOURCES = odp_ipc.c
> diff --git a/example/ipc/odp_ipc.c b/example/ipc/odp_ipc.c
> new file mode 100644
> index 0000000..1120467
> --- /dev/null
> +++ b/example/ipc/odp_ipc.c
> @@ -0,0 +1,445 @@
> +/* Copyright (c) 2015, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +/**
> + * @file
> + *
> + * @example odp_ipc.c  ODP IPC test application.
> + */
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <getopt.h>
> +#include <unistd.h>
> +
> +#include <example_debug.h>
> +
> +#include <odp.h>
> +#include <odp/helper/linux.h>
> +
> +/** @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
> +
> +/** 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))
> +
> +/** Application argument */
> +static char *pktio_name;
> +
> +/* helper funcs */
> +static void parse_args(int argc, char *argv[]);
> +static void print_info(char *progname);
> +static void usage(char *progname);
> +
> +static void busy_sleep(int sec)
> +{
> +       uint64_t start_cycle;
> +       uint64_t cycle;
> +       uint64_t diff;
> +       uint64_t wait;
> +
> +       wait = odp_time_ns_to_cycles(sec * ODP_TIME_SEC);
> +
> +       start_cycle = odp_time_cycles();
> +       while (1) {
> +               cycle = odp_time_cycles();
> +               diff  = odp_time_diff_cycles(start_cycle, cycle);
> +               if (wait < diff)
> +                       break;
> +       }
> +}
> +
> +/**
> + * Create a pktio handle.
> + *
> + * @param dev Name of device to open
> + * @param pool Pool to associate with device for packet RX/TX
> + *
> + * @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)
> +{
> +       odp_pktio_t pktio;
> +       odp_pktio_t ipc_pktio;
> +
> +       /* Open a packet IO instance */
> +       pktio = odp_pktio_open(dev, pool);
> +       if (pktio == ODP_PKTIO_INVALID)
> +               EXAMPLE_ABORT("Error: pktio create failed for %s\n", dev);
> +
> +       printf("pid: %d, create IPC pktio\n", getpid());
> +       ipc_pktio = odp_pktio_open("ipc_pktio", pool);
> +       if (ipc_pktio == ODP_PKTIO_INVALID)
> +               EXAMPLE_ABORT("Error: ipc pktio create failed.\n");
> +
> +       return pktio;
> +}
> +
> +/**
> + * Packet IO loopback worker thread using bursts from/to IO resources
> + *
> + * @param arg  thread arguments of type 'thread_args_t *'
> + */
> +static void *pktio_run_loop(odp_pool_t pool)
> +{
> +       int thr;
> +       odp_pktio_t pktio;
> +       int pkts;
> +       odp_packet_t pkt_tbl[MAX_PKT_BURST];
> +       odp_pktio_t ipc_pktio;
> +
> +       thr = odp_thread_id();
> +
> +       pktio = odp_pktio_lookup(pktio_name);
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               EXAMPLE_ERR("  [%02i] Error: lookup of pktio %s failed\n",
> +                           thr, pktio_name);
> +               return NULL;
> +       }
> +
> +       printf("  [%02i] looked up pktio:%02" PRIu64 ", burst mode\n",
> +              thr, odp_pktio_to_u64(pktio));
> +
> +       ipc_pktio = odp_pktio_lookup("ipc_pktio");
> +       if (pktio == ODP_PKTIO_INVALID) {
> +               EXAMPLE_ERR("  [%02i] Error: lookup of pktio %s failed\n",
> +                           thr, "ipc_pktio");
> +               return NULL;
> +       }
> +       printf("  [%02i] looked up ipc_pktio:%02" PRIu64 ", burst mode\n",
> +              thr, odp_pktio_to_u64(ipc_pktio));
> +
> +       /* packets loop */
> +       for (;;) {
> +               int i;
> +               time_t tm = time(NULL);
> +               char *tm_str = ctime(&tm);
> +               int sent;
> +
> +               /* 1. emulate that pkts packets were recieved  */
> +               odp_random_data((uint8_t *)&pkts, sizeof(pkts), 0);
> +               pkts = ((pkts & 0xffff) % MAX_PKT_BURST) + 1;
> +
> +               for (i = 0; i < pkts; i++) {
> +                       odp_packet_t pkt;
> +
> +                       pkt = odp_packet_alloc(pool, SHM_PKT_POOL_BUF_SIZE);
> +                       if (pkt == ODP_PACKET_INVALID) {
> +                               pkts = i;
> +                               printf("unable to alloc packet\n");
> +                               break;
> +                       }
> +                       pkt_tbl[i] = pkt;
> +               }
> +
> +               /* 2. Copy timestemp to that packets */
> +               for (i = 0; i < pkts; i++) {
> +                       odp_packet_copydata_in(pkt_tbl[i],
> +                                              0,
> +                                              strlen(tm_str),
> +                                              tm_str);
> +                       odp_packet_copydata_in(pkt_tbl[i],
> +                                              strlen(tm_str),
> +                                              1,
> +                                              "\0");
> +               }
> +               /* 3. Send packets to ipc_pktio */
> +               sent = odp_pktio_send(ipc_pktio, pkt_tbl, pkts);
> +               if (sent < 0)
> +                       fprintf(stderr, "error sending to ipc pktio\n");
> +               else
> +                       printf("---main pid %d: ipcsend %d pkts, size %d, 
> data: %s\n",
> +                              getpid(), sent,
> +                              odp_packet_len(pkt_tbl[0]),
> +                              tm_str);
> +
> +               /* 4. Sleep  some time to not overflow debug prints */
> +               busy_sleep(1);

This wasn't what I had in mind, this still wastes cycles that could
otherwise be used to process packets. You need to 'merge' the
busy_sleep loop with the main loop. That is, at the beginning of this
for loop you need to check if a second has elapsed since last time you
printed stats. You also need to count how many packets have been
during a one second period. When a second elapses, you print the
stats, reset the counters, update the last timestamp. But you keep
processing packets and update counters.

Think of this example as a performance example, that measures the
throughput of the IPC pktio (that does memcpy's), in a similar way
that odp_l2fwd measures the throughput of forwarding l2 frames.

> +
> +               /* 5. Recieve packets back from ipc_pktio, print timestemp and
> +                * free that packet
> +                */
> +               while (1) {
> +                       pkts = odp_pktio_recv(ipc_pktio, pkt_tbl,
> +                                             MAX_PKT_BURST);
> +                       if (pkts > 0) {
> +                               for (i = 0; i < pkts; i++) {
> +                                       uint32_t len;
> +                                       char *b;
> +
> +                                       len  = odp_packet_len(pkt_tbl[i]);
> +                                       b = malloc(len);
> +                                       odp_packet_copydata_out(pkt_tbl[i], 0,
> +                                                               
> odp_packet_len(pkt_tbl[i]),
> +                                                               b);
> +                                       printf("---main pid %d: ipcsrecv: 
> size %d, data: %s\n",
> +                                              getpid(),
> +                                              odp_packet_len(pkt_tbl[i]), b);
> +                                       free(b);
> +                                       odp_packet_free(pkt_tbl[i]);
> +                               }
> +                       } else {
> +                               break;
> +                       }
> +               }
> +       }
> +
> +/* unreachable */
> +       return NULL;
> +}
> +
> +static int ipc_second_process(void)
> +{
> +       odp_pktio_t pktio;
> +       odp_packet_t pkt_tbl[MAX_PKT_BURST];
> +       int i;
> +       int pkts;
> +
> +       /* linux shared memory can already have objects with names which
> +        * second process can try to connect. That might be even interrupted
> +        * current application. Might be later I will add magic numbers to
> +        * each ipc object in linux-generic. HW platform should not have that
> +        * problem. So just wait a little while master process will create
> +        * all ipc objects before connecting to them.
> +        */
> +       busy_sleep(3);
> +
> +       /* Do lookup packet I/O in IPC shared memory,
> +        * and link it to local pool. */
> +       while (1) {
> +               pktio = odp_pktio_open("ipc_pktio", ODP_POOL_INVALID);
> +               if (pktio == ODP_PKTIO_INVALID) {
> +                       busy_sleep(1);

This is actually a good place to do regular sleep.

> +                       printf("%s() pid %d: looking for ipc_pktio\n",
> +                              __func__, getpid());
> +                       continue;
> +               }
> +               break;
> +       }
> +
> +       for (;;) {
> +               pkts = odp_pktio_recv(pktio, pkt_tbl, MAX_PKT_BURST);
> +               if (pkts > 0) {
> +                       for (i = 0; i < pkts; i++) {
> +                               char *b = malloc(odp_packet_len(pkt_tbl[i]));
> +
> +                               odp_packet_copydata_out(pkt_tbl[i], 0,
> +                                                       
> odp_packet_len(pkt_tbl[i]),
> +                                                       b);
> +
> +                               printf("++++%s: pid %d, got packet %p, size 
> %d, data: %s\n",
> +                                      __func__, getpid(),
> +                                      (void *)pkt_tbl[i],
> +                                      odp_packet_len(pkt_tbl[i]), b);
> +                               free(b);
> +
> +                               odp_pktio_send(pktio, pkt_tbl, pkts);
> +                       }
> +               } else {
> +                       /* No need to load cpu in example app.*/
> +                       busy_sleep(1);

Same here, you need to count how many packets were received within a
one second period.

> +               }
> +       }
> +
> +       EXAMPLE_ERR("Unexpected close.");
> +       return 0;
> +}
> +
> +/**
> + * ODP packet example main function
> + */
> +int main(int argc, char *argv[])
> +{
> +       odp_pool_t pool;
> +       odp_pool_param_t params;
> +       int f;
> +
> +       /* Parse and store the application arguments */
> +       parse_args(argc, argv);
> +
> +       /* Use fork() before odp_init_global() to have 2 isolated
> +        * processes which need communicate to each other with
> +        * shared memory.
> +        */
> +       f = fork();
> +       if (f) {
> +               printf("Process one pid: %d\n", getpid());
> +               /* 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);
> +               }
> +
> +               ipc_second_process();
> +       } else {
> +               printf("Process two pid: %d\n", getpid());
> +       }
> +
> +       /* 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);
> +       }
> +
> +       /* Print both system and application information */
> +       print_info(NO_PATH(argv[0]));
> +
> +       /* Create packet pool */
> +       memset(&params, 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, &params);
> +       if (pool == ODP_POOL_INVALID) {
> +               EXAMPLE_ERR("Error: packet pool create failed.\n");
> +               exit(EXIT_FAILURE);
> +       }
> +
> +       odp_pool_print(pool);
> +
> +       create_pktio(pktio_name, pool);
> +
> +       pktio_run_loop(pool);
> +
> +       return 0;
> +}
> +
> +/**
> + * 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[])
> +{
> +       int opt;
> +       int long_index;
> +       size_t len;
> +       static struct option longopts[] = {
> +               {"interface", required_argument, NULL, 'i'},    /* return 'i' 
> */
> +               {"help", no_argument, NULL, 'h'},               /* return 'h' 
> */
> +               {NULL, 0, NULL, 0}
> +       };
> +
> +       while (1) {
> +               opt = getopt_long(argc, argv, "i:h",
> +                                 longopts, &long_index);
> +
> +               if (opt == -1)
> +                       break;  /* No more options */
> +
> +               switch (opt) {
> +               case 'i':
> +                       len = strlen(optarg);
> +                       if (len == 0) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +                       len += 1;       /* add room for '\0' */
> +
> +                       pktio_name = malloc(len);
> +                       if (!pktio_name) {
> +                               usage(argv[0]);
> +                               exit(EXIT_FAILURE);
> +                       }
> +                       strcpy(pktio_name, optarg);
> +
> +                       break;
> +               case 'h':
> +                       usage(argv[0]);
> +                       exit(EXIT_SUCCESS);
> +                       break;
> +
> +               default:
> +                       break;
> +               }
> +       }
> +
> +       if (!pktio_name) {
> +               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)
> +{
> +       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"
> +              "Using IF:        %s\n",
> +              progname, pktio_name);
> +       printf("\n\n");
> +       fflush(NULL);
> +}
> +
> +/**
> + * Prinf usage information
> + */
> +static void usage(char *progname)
> +{
> +       printf("\n"
> +              "Usage: %s OPTIONS\n"
> +              "  E.g. %s -i eth0\n"
> +              "\n"
> +              "OpenDataPlane example application.\n"
> +              "\n"
> +              "Mandatory OPTIONS:\n"
> +              "  -i, --interface Eth interface\n"
> +              "\n"
> +              "Optional OPTIONS\n"
> +              "  -h, --help           Display help and exit.\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)
> +           );
> +}
> --
> 1.9.1
>
> _______________________________________________
> lng-odp mailing list
> [email protected]
> https://lists.linaro.org/mailman/listinfo/lng-odp
_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to