diff mbox

[PATCHv6,5/5] ipc: example app

Message ID 1432222332-21289-6-git-send-email-maxim.uvarov@linaro.org
State New
Headers show

Commit Message

Maxim Uvarov May 21, 2015, 3:32 p.m. UTC
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 <maxim.uvarov@linaro.org>
---
 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

Comments

Ciprian Barbu May 22, 2015, 10:32 a.m. UTC | #1
On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <maxim.uvarov@linaro.org> 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 <maxim.uvarov@linaro.org>
> ---
>  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
> lng-odp@lists.linaro.org
> https://lists.linaro.org/mailman/listinfo/lng-odp
Maxim Uvarov May 22, 2015, 10:58 a.m. UTC | #2
On 05/22/15 13:32, Ciprian Barbu wrote:
> On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <maxim.uvarov@linaro.org> 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 <maxim.uvarov@linaro.org>
>> ---
>>   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.

odp_l2fwd is performance demo. While that one is functional example. 
 From my point
it was useful to print send bunch of packets each second and get them 
back. I'm not sure why
are you asking to redo that to performance demo.  It's not hard to redo 
it. But it's just the other
propose of the this example.  busy_sleep() is used to make compatible 
with odp api and do not use
system sleep().

Maxim.
>> +
>> +               /* 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
>> lng-odp@lists.linaro.org
>> https://lists.linaro.org/mailman/listinfo/lng-odp
Ciprian Barbu May 22, 2015, 11:14 a.m. UTC | #3
On Fri, May 22, 2015 at 1:58 PM, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:
> On 05/22/15 13:32, Ciprian Barbu wrote:
>>
>> On Thu, May 21, 2015 at 6:32 PM, Maxim Uvarov <maxim.uvarov@linaro.org>
>> 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 <maxim.uvarov@linaro.org>
>>> ---
>>>   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.
>
>
> odp_l2fwd is performance demo. While that one is functional example. From my
> point
> it was useful to print send bunch of packets each second and get them back.

It's hard to follow all of those debug printouts. You can leave the
example as a functional one, of course, but I thought it would be more
useful to show how good it performs.

> I'm not sure why
> are you asking to redo that to performance demo.  It's not hard to redo it.
> But it's just the other
> propose of the this example.  busy_sleep() is used to make compatible with
> odp api and do not use
> system sleep().
>
> Maxim.
>
>>> +
>>> +               /* 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
>>> lng-odp@lists.linaro.org
>>> https://lists.linaro.org/mailman/listinfo/lng-odp
>
>
diff mbox

Patch

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);
+
+		/* 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);
+			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);
+		}
+	}
+
+	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)
+	    );
+}