On Fri, May 22, 2015 at 1:58 PM, Maxim Uvarov <[email protected]> wrote:
> On 05/22/15 13:32, Ciprian Barbu wrote:
>>
>> 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.
>
>
> 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(¶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);
>>> +
>>> + 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