[dpdk-dev] [PATCH v3] doc: add new targets to "make help" output

2017-07-07 Thread Gabriel Carrillo
Commit aafaea3d3b70 ("devtools: add tags
and cscope index generation") introduced
new make targets. This change updates the
help target output to reflect the additions.

Signed-off-by: Gabriel Carrillo 
---
v3:
* Updated formatting.

 doc/build-sdk-quick.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/doc/build-sdk-quick.txt b/doc/build-sdk-quick.txt
index 8d41052..3507220 100644
--- a/doc/build-sdk-quick.txt
+++ b/doc/build-sdk-quick.txt
@@ -11,6 +11,8 @@ Build commands
examples_clean   clean examples for given targets (T=)
test compile tests and run basic unit tests
test-*   run specific subset of unit tests
+   tags|gtags T=generate tags/gtags for given targets (T=)
+   cscope T=generate cscope database for given targets (T=)
 Build variables
EXTRA_CPPFLAGS   preprocessor options
EXTRA_CFLAGS compiler options
-- 
2.6.4



[dpdk-dev] [PATCH] doc: add new targets to "make help" output

2017-06-05 Thread Gabriel Carrillo
Commit aafaea3d3b70 ("devtools: add tags
and cscope index generation") introduced
new make targets. This change updates the
help target output to reflect the additions.

Signed-off-by: Gabriel Carrillo 
---
 doc/build-sdk-quick.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/doc/build-sdk-quick.txt b/doc/build-sdk-quick.txt
index 8d41052..0b8a309 100644
--- a/doc/build-sdk-quick.txt
+++ b/doc/build-sdk-quick.txt
@@ -11,6 +11,9 @@ Build commands
examples_clean   clean examples for given targets (T=)
test compile tests and run basic unit tests
test-*   run specific subset of unit tests
+   tags T=  generate ctags for given targets (T=)
+   gtags T= generate gtags for given targets (T=)
+   cscope T=generate cscope database for given targets (T=)
 Build variables
EXTRA_CPPFLAGS   preprocessor options
EXTRA_CFLAGS compiler options
-- 
2.6.4



[dpdk-dev] [PATCH v2] doc: add new targets to "make help" output

2017-06-06 Thread Gabriel Carrillo
Commit aafaea3d3b70 ("devtools: add tags
and cscope index generation") introduced
new make targets. This change updates the
help target output to reflect the additions.

Signed-off-by: Gabriel Carrillo 
---
 doc/build-sdk-quick.txt | 21 +++--
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/doc/build-sdk-quick.txt b/doc/build-sdk-quick.txt
index 8d41052..8ed9d80 100644
--- a/doc/build-sdk-quick.txt
+++ b/doc/build-sdk-quick.txt
@@ -1,16 +1,17 @@
 Basic build
make config T=x86_64-native-linuxapp-gcc && make
 Build commands
-   config   get configuration from target template (T=)
-   all  same as build (default rule)
-   buildbuild in a configured directory
-   cleanremove files but keep configuration
-   install T=   configure, build and install a target in DESTDIR
-   install  install optionally staged in DESTDIR
-   examples build examples for given targets (T=)
-   examples_clean   clean examples for given targets (T=)
-   test compile tests and run basic unit tests
-   test-*   run specific subset of unit tests
+   config  get configuration from target template (T=)
+   all same as build (default rule)
+   build   build in a configured directory
+   clean   remove files but keep configuration
+   install T=  configure, build and install a target in DESTDIR
+   install install optionally staged in DESTDIR
+   examplesbuild examples for given targets (T=)
+   examples_clean  clean examples for given targets (T=)
+   testcompile tests and run basic unit tests
+   test-*  run specific subset of unit tests
+   tags|gtags|cscope [T=]  generate tags or cscope index
 Build variables
EXTRA_CPPFLAGS   preprocessor options
EXTRA_CFLAGS compiler options
-- 
2.6.4



[dpdk-dev] [PATCH 0/3] *** timer library enhancements ***

2017-08-23 Thread Gabriel Carrillo
In the current implementation of the DPDK timer library, timers can be
created and set to be handled by a target lcore by adding it to a
skiplist that corresponds to that lcore.  However, if an application
enables multiple lcores, and each of these lcores repeatedly attempts
to install timers on the same target lcore, overall application
throughput will be reduced as all lcores contend to acquire the lock
guarding the single skiplist of pending timers. 

This patchset addresses this scenario by adding an array of skiplists
to each lcore's priv_timer struct, such that when lcore i installs a
timer on lcore k, the timer will be added to the ith skiplist for
lcore k.  If lcore j installs a timer on lcore k simultaneously,
lcores i and j can both proceed since they will be acquiring different
locks for different lists. 

When lcore k processes its pending timers, it will traverse each skiplist
in its array and acquire a skiplist's lock while a run list is broken
out; meanwhile, all other lists can continue to be modified.  Then, all
run lists for lcore k are collected and traversed together so timers are
executed in their global order. 

Gabriel Carrillo (3):
  timer: add per-installer pending lists for each lcore
  timer: handle timers installed from non-EAL threads
  doc: update timer lib docs

 doc/guides/prog_guide/timer_lib.rst |  19 ++-
 lib/librte_timer/rte_timer.c| 329 +++-
 lib/librte_timer/rte_timer.h|   9 +-
 3 files changed, 231 insertions(+), 126 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH 1/3] timer: add per-installer pending lists for each lcore

2017-08-23 Thread Gabriel Carrillo
Instead of each priv_timer struct containing a single skiplist, this
commit adds a skiplist for each enabled lcore to priv_timer. In the case
that multiple lcores repeatedly install timers on the same target lcore,
this change reduces lock contention for the target lcore's skiplists and
increases performance.

Signed-off-by: Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c | 309 +++
 lib/librte_timer/rte_timer.h |   9 +-
 2 files changed, 202 insertions(+), 116 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 5ee0840..2db74c1 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -37,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -56,17 +57,19 @@
 
 LIST_HEAD(rte_timer_list, rte_timer);
 
+struct skiplist {
+   struct rte_timer head;  /**< dummy timer instance to head up list */
+   rte_spinlock_t lock;/**< lock to protect list access */
+   unsigned depth; /**< track the current depth of the skiplist */
+} __rte_cache_aligned;
+
 struct priv_timer {
-   struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
-   rte_spinlock_t list_lock;   /**< lock to protect list access */
+   /** one pending list per enabled lcore */
+   struct skiplist pending_lists[RTE_MAX_LCORE];
 
/** per-core variable that true if a timer was updated on this
 *  core since last reset of the variable */
int updated;
-
-   /** track the current depth of the skiplist */
-   unsigned curr_skiplist_depth;
-
unsigned prev_lcore;  /**< used for lcore round robin */
 
/** running timer on this lcore now */
@@ -81,6 +84,10 @@ struct priv_timer {
 /** per-lcore private info for timers */
 static struct priv_timer priv_timer[RTE_MAX_LCORE];
 
+/** cache of IDs of enabled lcores */
+static unsigned enabled_lcores[RTE_MAX_LCORE];
+static int n_enabled_lcores;
+
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
 #define __TIMER_STAT_ADD(name, n) do { \
@@ -96,14 +103,25 @@ static struct priv_timer priv_timer[RTE_MAX_LCORE];
 void
 rte_timer_subsystem_init(void)
 {
-   unsigned lcore_id;
+   unsigned lcore_id1, lcore_id2;
+   struct skiplist *list;
+   int i, j;
+
+   RTE_LCORE_FOREACH(lcore_id1)
+   enabled_lcores[n_enabled_lcores++] = lcore_id1;
 
/* since priv_timer is static, it's zeroed by default, so only init some
 * fields.
 */
-   for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++) {
-   rte_spinlock_init(&priv_timer[lcore_id].list_lock);
-   priv_timer[lcore_id].prev_lcore = lcore_id;
+   for (i = 0, lcore_id1 = enabled_lcores[i]; i < n_enabled_lcores;
+lcore_id1 = enabled_lcores[++i]) {
+   priv_timer[lcore_id1].prev_lcore = lcore_id1;
+
+   for (j = 0, lcore_id2 = enabled_lcores[j]; j < n_enabled_lcores;
+lcore_id2 = enabled_lcores[++j]) {
+   list = &priv_timer[lcore_id1].pending_lists[lcore_id2];
+   rte_spinlock_init(&list->lock);
+   }
}
 }
 
@@ -114,7 +132,8 @@ rte_timer_init(struct rte_timer *tim)
union rte_timer_status status;
 
status.state = RTE_TIMER_STOP;
-   status.owner = RTE_TIMER_NO_OWNER;
+   status.installer = RTE_TIMER_NO_LCORE;
+   status.owner = RTE_TIMER_NO_LCORE;
tim->status.u32 = status.u32;
 }
 
@@ -142,7 +161,7 @@ timer_set_config_state(struct rte_timer *tim,
 * or ready to run on local core, exit
 */
if (prev_status.state == RTE_TIMER_RUNNING &&
-   (prev_status.owner != (uint16_t)lcore_id ||
+   (prev_status.owner != (int)lcore_id ||
 tim != priv_timer[lcore_id].running_tim))
return -1;
 
@@ -153,7 +172,8 @@ timer_set_config_state(struct rte_timer *tim,
/* here, we know that timer is stopped or pending,
 * mark it atomically as being configured */
status.state = RTE_TIMER_CONFIG;
-   status.owner = (int16_t)lcore_id;
+   status.installer = RTE_TIMER_NO_LCORE;
+   status.owner = lcore_id;
success = rte_atomic32_cmpset(&tim->status.u32,
  prev_status.u32,
  status.u32);
@@ -185,7 +205,8 @@ timer_set_running_state(struct rte_timer *tim)
/* here, we know that timer is stopped or pending,
 * mark it atomically as being configured */
status.state = RTE_TIMER_RUNNING;
-   status.owner = (int1

[dpdk-dev] [PATCH 2/3] timer: handle timers installed from non-EAL threads

2017-08-23 Thread Gabriel Carrillo
This commit adds support for timers being created from
non-EAL threads;  it maps timers from all such threads to
lcore id RTE_MAX_LCORE, and puts them all in a corresponding
skiplist.

Signed-off-by: Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c | 48 ++--
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 2db74c1..a493874 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -64,8 +64,8 @@ struct skiplist {
 } __rte_cache_aligned;
 
 struct priv_timer {
-   /** one pending list per enabled lcore */
-   struct skiplist pending_lists[RTE_MAX_LCORE];
+   /** one pending list per lcore, plus one for non-EAL threads */
+   struct skiplist pending_lists[RTE_MAX_LCORE + 1];
 
/** per-core variable that true if a timer was updated on this
 *  core since last reset of the variable */
@@ -85,7 +85,7 @@ struct priv_timer {
 static struct priv_timer priv_timer[RTE_MAX_LCORE];
 
 /** cache of IDs of enabled lcores */
-static unsigned enabled_lcores[RTE_MAX_LCORE];
+static unsigned enabled_lcores[RTE_MAX_LCORE + 1];
 static int n_enabled_lcores;
 
 /* when debug is enabled, store some statistics */
@@ -103,23 +103,33 @@ static int n_enabled_lcores;
 void
 rte_timer_subsystem_init(void)
 {
-   unsigned lcore_id1, lcore_id2;
+   unsigned target_lcore, installer_lcore;
struct skiplist *list;
+   struct priv_timer *priv_tim;
int i, j;
 
-   RTE_LCORE_FOREACH(lcore_id1)
-   enabled_lcores[n_enabled_lcores++] = lcore_id1;
+   RTE_LCORE_FOREACH(target_lcore)
+   enabled_lcores[n_enabled_lcores++] = target_lcore;
+
+   /* To handle timers coming from non-EAL threads */
+   enabled_lcores[n_enabled_lcores++] = RTE_MAX_LCORE;
 
/* since priv_timer is static, it's zeroed by default, so only init some
 * fields.
 */
-   for (i = 0, lcore_id1 = enabled_lcores[i]; i < n_enabled_lcores;
-lcore_id1 = enabled_lcores[++i]) {
-   priv_timer[lcore_id1].prev_lcore = lcore_id1;
+   for (i = 0, target_lcore = enabled_lcores[i]; i < n_enabled_lcores;
+target_lcore = enabled_lcores[++i]) {
+   /* Don't use this value to index the priv_timer array */
+   if (target_lcore == RTE_MAX_LCORE)
+   continue;
 
-   for (j = 0, lcore_id2 = enabled_lcores[j]; j < n_enabled_lcores;
-lcore_id2 = enabled_lcores[++j]) {
-   list = &priv_timer[lcore_id1].pending_lists[lcore_id2];
+   priv_tim = &priv_timer[target_lcore];
+   priv_tim->prev_lcore = target_lcore;
+
+   for (j = 0, installer_lcore = enabled_lcores[j];
+j < n_enabled_lcores;
+installer_lcore = enabled_lcores[++j]) {
+   list = &priv_tim->pending_lists[installer_lcore];
rte_spinlock_init(&list->lock);
}
}
@@ -300,10 +310,16 @@ timer_get_prev_entries_for_node(struct rte_timer *tim, 
struct skiplist *list,
 static void
 timer_add(struct rte_timer *tim, unsigned tim_lcore, int local_is_locked)
 {
-   unsigned lcore_id = rte_lcore_id();
+   unsigned installer_lcore, lcore_id = rte_lcore_id();
unsigned lvl;
struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
-   struct skiplist *list = &priv_timer[tim_lcore].pending_lists[lcore_id];
+   struct skiplist *list;
+
+   /* Check if timer being installed from non-EAL thread */
+   installer_lcore = (lcore_id == LCORE_ID_ANY) ? RTE_MAX_LCORE :
+   lcore_id;
+
+   list = &priv_timer[tim_lcore].pending_lists[installer_lcore];
 
/* if timer needs to be scheduled on another core, we need to
 * lock the list; if it is on local core, we need to lock if
@@ -439,7 +455,9 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
 * the state so we don't need to use cmpset() here */
rte_wmb();
status.state = RTE_TIMER_PENDING;
-   status.installer = lcore_id;
+   /* Check if installer is non-EAL thread */
+   status.installer = (lcore_id == LCORE_ID_ANY) ? RTE_MAX_LCORE :
+  lcore_id;
status.owner = tim_lcore;
tim->status.u32 = status.u32;
 
-- 
2.6.4



[dpdk-dev] [PATCH 3/3] doc: update timer lib docs

2017-08-23 Thread Gabriel Carrillo
This change updates the timer library documentation to
reflect a change to the organization of the skiplists
in the implementation.

Signed-off-by: Gabriel Carrillo 
---
 doc/guides/prog_guide/timer_lib.rst | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/doc/guides/prog_guide/timer_lib.rst 
b/doc/guides/prog_guide/timer_lib.rst
index f437417..f94ffaa 100644
--- a/doc/guides/prog_guide/timer_lib.rst
+++ b/doc/guides/prog_guide/timer_lib.rst
@@ -1,5 +1,5 @@
 ..  BSD LICENSE
-Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -53,16 +53,17 @@ Refer to the `callout manual 
<http://www.daemon-systems.org/man/callout.9.html>`
 Implementation Details
 --
 
-Timers are tracked on a per-lcore basis,
-with all pending timers for a core being maintained in order of timer expiry 
in a skiplist data structure.
-The skiplist used has ten levels and each entry in the table appears in each 
level with probability ¼^level.
+Timers are tracked in a per-lcore array of skiplist data structures; each
+lcore has one skiplist corresponding to each other lcore that could load a 
timer on it. All pending
+timers in each skiplist are maintained in order of timer expiry.
+Each skiplist has ten levels and each entry in the table appears in each level 
with probability ¼^level.
 This means that all entries are present in level 0, 1 in every 4 entries is 
present at level 1,
 one in every 16 at level 2 and so on up to level 9.
 This means that adding and removing entries from the timer list for a core can 
be done in log(n) time,
 up to 4^10 entries, that is, approximately 1,000,000 timers per lcore.
 
 A timer structure contains a special field called status,
-which is a union of a timer state (stopped, pending, running, config) and an 
owner (lcore id).
+which is a union of a timer state (stopped, pending, running, config), an 
installer (lcore id), and an owner (lcore id).
 Depending on the timer state, we know if a timer is present in a list or not:
 
 *   STOPPED: no owner, not in a list
@@ -77,17 +78,17 @@ Resetting or stopping a timer while it is in a CONFIG or 
RUNNING state is not al
 When modifying the state of a timer,
 a Compare And Swap instruction should be used to guarantee that the status 
(state+owner) is modified atomically.
 
-Inside the rte_timer_manage() function,
-the skiplist is used as a regular list by iterating along the level 0 list, 
which contains all timer entries,
+Inside the rte_timer_manage() function, each of an lcore's skiplists is 
traversed in sequence.
+Each skiplist is used as a regular list by iterating along the level 0 list, 
which contains all timer entries,
 until an entry which has not yet expired has been encountered.
-To improve performance in the case where there are entries in the timer list 
but none of those timers have yet expired,
+To improve performance in the case where there are entries in a skiplist but 
none of those timers have yet expired,
 the expiry time of the first list entry is maintained within the per-core 
timer list structure itself.
 On 64-bit platforms, this value can be checked without the need to take a lock 
on the overall structure.
 (Since expiry times are maintained as 64-bit values,
 a check on the value cannot be done on 32-bit platforms without using either a 
compare-and-swap (CAS) instruction or using a lock,
 so this additional check is skipped in favor of checking as normal once the 
lock has been taken.)
 On both 64-bit and 32-bit platforms,
-a call to rte_timer_manage() returns without taking a lock in the case where 
the timer list for the calling core is empty.
+rte_timer_manage() can continue on to an lcore's next skiplist without taking 
a lock in the case where a timer list is empty.
 
 Use Cases
 -
-- 
2.6.4



[dpdk-dev] [PATCH v2 0/3] *** timer library enhancements ***

2017-08-25 Thread Gabriel Carrillo
In the current implementation of the DPDK timer library, timers can be
created and set to be handled by a target lcore by adding it to a
skiplist that corresponds to that lcore.  However, if an application
enables multiple lcores, and each of these lcores repeatedly attempts
to install timers on the same target lcore, overall application
throughput will be reduced as all lcores contend to acquire the lock
guarding the single skiplist of pending timers. 

This patchset addresses this scenario by adding an array of skiplists
to each lcore's priv_timer struct, such that when lcore i installs a
timer on lcore k, the timer will be added to the ith skiplist for
lcore k.  If lcore j installs a timer on lcore k simultaneously,
lcores i and j can both proceed since they will be acquiring different
locks for different lists. 

When lcore k processes its pending timers, it will traverse each skiplist
in its array and acquire a skiplist's lock while a run list is broken
out; meanwhile, all other lists can continue to be modified.  Then, all
run lists for lcore k are collected and traversed together so timers are
executed in their relative order. 

Gabriel Carrillo (3):
  timer: add per-installer pending lists for each lcore
  timer: handle timers installed from non-EAL threads
  doc: update timer lib docs

 doc/guides/prog_guide/timer_lib.rst |  19 ++-
 lib/librte_timer/rte_timer.c| 329 +++-
 lib/librte_timer/rte_timer.h|   9 +-
 3 files changed, 231 insertions(+), 126 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v2 1/3] timer: add per-installer pending lists for each lcore

2017-08-25 Thread Gabriel Carrillo
Instead of each priv_timer struct containing a single skiplist, this
commit adds a skiplist for each enabled lcore to priv_timer. In the case
that multiple lcores repeatedly install timers on the same target lcore,
this change reduces lock contention for the target lcore's skiplists and
increases performance.

Signed-off-by: Gabriel Carrillo 
---
v2:
* Address checkpatch warnings

 lib/librte_timer/rte_timer.c | 309 +++
 lib/librte_timer/rte_timer.h |   9 +-
 2 files changed, 202 insertions(+), 116 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 5ee0840..da2fc1a 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -37,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -56,17 +57,19 @@
 
 LIST_HEAD(rte_timer_list, rte_timer);
 
+struct skiplist {
+   struct rte_timer head;  /**< dummy timer instance to head up list */
+   rte_spinlock_t lock;/**< lock to protect list access */
+   unsigned int depth; /**< track the current depth of the skiplist */
+} __rte_cache_aligned;
+
 struct priv_timer {
-   struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
-   rte_spinlock_t list_lock;   /**< lock to protect list access */
+   /** one pending list per enabled lcore */
+   struct skiplist pending_lists[RTE_MAX_LCORE];
 
/** per-core variable that true if a timer was updated on this
 *  core since last reset of the variable */
int updated;
-
-   /** track the current depth of the skiplist */
-   unsigned curr_skiplist_depth;
-
unsigned prev_lcore;  /**< used for lcore round robin */
 
/** running timer on this lcore now */
@@ -81,6 +84,10 @@ struct priv_timer {
 /** per-lcore private info for timers */
 static struct priv_timer priv_timer[RTE_MAX_LCORE];
 
+/** cache of IDs of enabled lcores */
+static unsigned int enabled_lcores[RTE_MAX_LCORE];
+static int n_enabled_lcores;
+
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
 #define __TIMER_STAT_ADD(name, n) do { \
@@ -96,14 +103,25 @@ static struct priv_timer priv_timer[RTE_MAX_LCORE];
 void
 rte_timer_subsystem_init(void)
 {
-   unsigned lcore_id;
+   unsigned int lcore_id1, lcore_id2;
+   struct skiplist *list;
+   int i, j;
+
+   RTE_LCORE_FOREACH(lcore_id1)
+   enabled_lcores[n_enabled_lcores++] = lcore_id1;
 
/* since priv_timer is static, it's zeroed by default, so only init some
 * fields.
 */
-   for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++) {
-   rte_spinlock_init(&priv_timer[lcore_id].list_lock);
-   priv_timer[lcore_id].prev_lcore = lcore_id;
+   for (i = 0, lcore_id1 = enabled_lcores[i]; i < n_enabled_lcores;
+lcore_id1 = enabled_lcores[++i]) {
+   priv_timer[lcore_id1].prev_lcore = lcore_id1;
+
+   for (j = 0, lcore_id2 = enabled_lcores[j]; j < n_enabled_lcores;
+lcore_id2 = enabled_lcores[++j]) {
+   list = &priv_timer[lcore_id1].pending_lists[lcore_id2];
+   rte_spinlock_init(&list->lock);
+   }
}
 }
 
@@ -114,7 +132,8 @@ rte_timer_init(struct rte_timer *tim)
union rte_timer_status status;
 
status.state = RTE_TIMER_STOP;
-   status.owner = RTE_TIMER_NO_OWNER;
+   status.installer = RTE_TIMER_NO_LCORE;
+   status.owner = RTE_TIMER_NO_LCORE;
tim->status.u32 = status.u32;
 }
 
@@ -142,7 +161,7 @@ timer_set_config_state(struct rte_timer *tim,
 * or ready to run on local core, exit
 */
if (prev_status.state == RTE_TIMER_RUNNING &&
-   (prev_status.owner != (uint16_t)lcore_id ||
+   (prev_status.owner != (int)lcore_id ||
 tim != priv_timer[lcore_id].running_tim))
return -1;
 
@@ -153,7 +172,8 @@ timer_set_config_state(struct rte_timer *tim,
/* here, we know that timer is stopped or pending,
 * mark it atomically as being configured */
status.state = RTE_TIMER_CONFIG;
-   status.owner = (int16_t)lcore_id;
+   status.installer = RTE_TIMER_NO_LCORE;
+   status.owner = lcore_id;
success = rte_atomic32_cmpset(&tim->status.u32,
  prev_status.u32,
  status.u32);
@@ -185,7 +205,8 @@ timer_set_running_state(struct rte_timer *tim)
/* here, we know that timer is stopped or pending,
 * mark it atomically as being configured */
status.state

[dpdk-dev] [PATCH v2 2/3] timer: handle timers installed from non-EAL threads

2017-08-25 Thread Gabriel Carrillo
This commit adds support for timers being created from
non-EAL threads;  it maps timers from all such threads to
lcore id RTE_MAX_LCORE, and puts them all in a corresponding
skiplist.

Signed-off-by: Gabriel Carrillo 
---
v2:
* Address checkpatch warnings

 lib/librte_timer/rte_timer.c | 48 ++--
 1 file changed, 33 insertions(+), 15 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index da2fc1a..ca7b80c 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -64,8 +64,8 @@ struct skiplist {
 } __rte_cache_aligned;
 
 struct priv_timer {
-   /** one pending list per enabled lcore */
-   struct skiplist pending_lists[RTE_MAX_LCORE];
+   /** one pending list per lcore, plus one for non-EAL threads */
+   struct skiplist pending_lists[RTE_MAX_LCORE + 1];
 
/** per-core variable that true if a timer was updated on this
 *  core since last reset of the variable */
@@ -85,7 +85,7 @@ struct priv_timer {
 static struct priv_timer priv_timer[RTE_MAX_LCORE];
 
 /** cache of IDs of enabled lcores */
-static unsigned int enabled_lcores[RTE_MAX_LCORE];
+static unsigned int enabled_lcores[RTE_MAX_LCORE + 1];
 static int n_enabled_lcores;
 
 /* when debug is enabled, store some statistics */
@@ -103,23 +103,33 @@ static int n_enabled_lcores;
 void
 rte_timer_subsystem_init(void)
 {
-   unsigned int lcore_id1, lcore_id2;
+   unsigned int target_lcore, installer_lcore;
struct skiplist *list;
+   struct priv_timer *priv_tim;
int i, j;
 
-   RTE_LCORE_FOREACH(lcore_id1)
-   enabled_lcores[n_enabled_lcores++] = lcore_id1;
+   RTE_LCORE_FOREACH(target_lcore)
+   enabled_lcores[n_enabled_lcores++] = target_lcore;
+
+   /* To handle timers coming from non-EAL threads */
+   enabled_lcores[n_enabled_lcores++] = RTE_MAX_LCORE;
 
/* since priv_timer is static, it's zeroed by default, so only init some
 * fields.
 */
-   for (i = 0, lcore_id1 = enabled_lcores[i]; i < n_enabled_lcores;
-lcore_id1 = enabled_lcores[++i]) {
-   priv_timer[lcore_id1].prev_lcore = lcore_id1;
+   for (i = 0, target_lcore = enabled_lcores[i]; i < n_enabled_lcores;
+target_lcore = enabled_lcores[++i]) {
+   /* Don't use this value to index the priv_timer array */
+   if (target_lcore == RTE_MAX_LCORE)
+   continue;
 
-   for (j = 0, lcore_id2 = enabled_lcores[j]; j < n_enabled_lcores;
-lcore_id2 = enabled_lcores[++j]) {
-   list = &priv_timer[lcore_id1].pending_lists[lcore_id2];
+   priv_tim = &priv_timer[target_lcore];
+   priv_tim->prev_lcore = target_lcore;
+
+   for (j = 0, installer_lcore = enabled_lcores[j];
+j < n_enabled_lcores;
+installer_lcore = enabled_lcores[++j]) {
+   list = &priv_tim->pending_lists[installer_lcore];
rte_spinlock_init(&list->lock);
}
}
@@ -300,10 +310,16 @@ timer_get_prev_entries_for_node(struct rte_timer *tim, 
struct skiplist *list,
 static void
 timer_add(struct rte_timer *tim, unsigned tim_lcore, int local_is_locked)
 {
-   unsigned lcore_id = rte_lcore_id();
+   unsigned int installer_lcore, lcore_id = rte_lcore_id();
unsigned lvl;
struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
-   struct skiplist *list = &priv_timer[tim_lcore].pending_lists[lcore_id];
+   struct skiplist *list;
+
+   /* Check if timer being installed from non-EAL thread */
+   installer_lcore = (lcore_id == LCORE_ID_ANY) ? RTE_MAX_LCORE :
+   lcore_id;
+
+   list = &priv_timer[tim_lcore].pending_lists[installer_lcore];
 
/* if timer needs to be scheduled on another core, we need to
 * lock the list; if it is on local core, we need to lock if
@@ -439,7 +455,9 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
 * the state so we don't need to use cmpset() here */
rte_wmb();
status.state = RTE_TIMER_PENDING;
-   status.installer = lcore_id;
+   /* Check if installer is non-EAL thread */
+   status.installer = (lcore_id == LCORE_ID_ANY) ? RTE_MAX_LCORE :
+  lcore_id;
status.owner = tim_lcore;
tim->status.u32 = status.u32;
 
-- 
2.6.4



[dpdk-dev] [PATCH v2 3/3] doc: update timer lib docs

2017-08-25 Thread Gabriel Carrillo
This change updates the timer library documentation to
reflect a change to the organization of the skiplists
in the implementation.

Signed-off-by: Gabriel Carrillo 
---
 doc/guides/prog_guide/timer_lib.rst | 19 ++-
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/doc/guides/prog_guide/timer_lib.rst 
b/doc/guides/prog_guide/timer_lib.rst
index f437417..f94ffaa 100644
--- a/doc/guides/prog_guide/timer_lib.rst
+++ b/doc/guides/prog_guide/timer_lib.rst
@@ -1,5 +1,5 @@
 ..  BSD LICENSE
-Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -53,16 +53,17 @@ Refer to the `callout manual 
<http://www.daemon-systems.org/man/callout.9.html>`
 Implementation Details
 --
 
-Timers are tracked on a per-lcore basis,
-with all pending timers for a core being maintained in order of timer expiry 
in a skiplist data structure.
-The skiplist used has ten levels and each entry in the table appears in each 
level with probability ¼^level.
+Timers are tracked in a per-lcore array of skiplist data structures; each
+lcore has one skiplist corresponding to each other lcore that could load a 
timer on it. All pending
+timers in each skiplist are maintained in order of timer expiry.
+Each skiplist has ten levels and each entry in the table appears in each level 
with probability ¼^level.
 This means that all entries are present in level 0, 1 in every 4 entries is 
present at level 1,
 one in every 16 at level 2 and so on up to level 9.
 This means that adding and removing entries from the timer list for a core can 
be done in log(n) time,
 up to 4^10 entries, that is, approximately 1,000,000 timers per lcore.
 
 A timer structure contains a special field called status,
-which is a union of a timer state (stopped, pending, running, config) and an 
owner (lcore id).
+which is a union of a timer state (stopped, pending, running, config), an 
installer (lcore id), and an owner (lcore id).
 Depending on the timer state, we know if a timer is present in a list or not:
 
 *   STOPPED: no owner, not in a list
@@ -77,17 +78,17 @@ Resetting or stopping a timer while it is in a CONFIG or 
RUNNING state is not al
 When modifying the state of a timer,
 a Compare And Swap instruction should be used to guarantee that the status 
(state+owner) is modified atomically.
 
-Inside the rte_timer_manage() function,
-the skiplist is used as a regular list by iterating along the level 0 list, 
which contains all timer entries,
+Inside the rte_timer_manage() function, each of an lcore's skiplists is 
traversed in sequence.
+Each skiplist is used as a regular list by iterating along the level 0 list, 
which contains all timer entries,
 until an entry which has not yet expired has been encountered.
-To improve performance in the case where there are entries in the timer list 
but none of those timers have yet expired,
+To improve performance in the case where there are entries in a skiplist but 
none of those timers have yet expired,
 the expiry time of the first list entry is maintained within the per-core 
timer list structure itself.
 On 64-bit platforms, this value can be checked without the need to take a lock 
on the overall structure.
 (Since expiry times are maintained as 64-bit values,
 a check on the value cannot be done on 32-bit platforms without using either a 
compare-and-swap (CAS) instruction or using a lock,
 so this additional check is skipped in favor of checking as normal once the 
lock has been taken.)
 On both 64-bit and 32-bit platforms,
-a call to rte_timer_manage() returns without taking a lock in the case where 
the timer list for the calling core is empty.
+rte_timer_manage() can continue on to an lcore's next skiplist without taking 
a lock in the case where a timer list is empty.
 
 Use Cases
 -
-- 
2.6.4



[PATCH] service: fix early move to inactive status

2022-10-20 Thread Erik Gabriel Carrillo
Assume thread T2 is a service lcore that is in the middle of executing
a service function.  Also, assume thread T1 concurrently calls
rte_service_lcore_stop(), which will set the "service_active_on_lcore"
state to false.  If thread T1 then calls rte_service_may_be_active(),
it can return zero even though T2 is still running the service function.
If T1 then proceeds to free data being used by T2, a crash can ensue.

Move the logic that clears the "service_active_on_lcore" state from the
rte_service_lcore_stop() function to the service_runner_func() to
ensure that we:
- don't let the "service_active_on_lcore" state linger as 1
- don't clear the state early

Fixes: 6550113be62d ("service: fix lingering active status")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/eal/common/rte_service.c | 13 +++--
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/lib/eal/common/rte_service.c b/lib/eal/common/rte_service.c
index 81c9514149..bcc2e19077 100644
--- a/lib/eal/common/rte_service.c
+++ b/lib/eal/common/rte_service.c
@@ -479,6 +479,7 @@ static int32_t
 service_runner_func(void *arg)
 {
RTE_SET_USED(arg);
+   uint8_t i;
const int lcore = rte_lcore_id();
struct core_state *cs = &lcore_states[lcore];
 
@@ -494,7 +495,6 @@ service_runner_func(void *arg)
const uint64_t service_mask = cs->service_mask;
uint8_t start_id;
uint8_t end_id;
-   uint8_t i;
 
if (service_mask == 0)
continue;
@@ -510,6 +510,12 @@ service_runner_func(void *arg)
__atomic_store_n(&cs->loops, cs->loops + 1, __ATOMIC_RELAXED);
}
 
+   /* Switch off this core for all services, to ensure that future
+* calls to may_be_active() know this core is switched off.
+*/
+   for (i = 0; i < RTE_SERVICE_NUM_MAX; i++)
+   cs->service_active_on_lcore[i] = 0;
+
/* Use SEQ CST memory ordering to avoid any re-ordering around
 * this store, ensuring that once this store is visible, the service
 * lcore thread really is done in service cores code.
@@ -806,11 +812,6 @@ rte_service_lcore_stop(uint32_t lcore)
__atomic_load_n(&rte_services[i].num_mapped_cores,
__ATOMIC_RELAXED));
 
-   /* Switch off this core for all services, to ensure that future
-* calls to may_be_active() know this core is switched off.
-*/
-   cs->service_active_on_lcore[i] = 0;
-
/* if the core is mapped, and the service is running, and this
 * is the only core that is mapped, the service would cease to
 * run if this core stopped, so fail instead.
-- 
2.23.0



[PATCH v4] eventdev/timer: add API to get remaining ticks

2023-01-13 Thread Erik Gabriel Carrillo
Introduce an event timer adapter API which allows users to determine how
many adapter ticks remain until an event timer expires.

Signed-off-by: Erik Gabriel Carrillo 
---
v4:
* Rename API to rte_event_timer_remaining_ticks_get
* Return error if API out param is NULL instead asserting it is non-NULL
* Update documentation

v3:
* Handle ENOTSUP case in unit test

v2:
* Rename API to rte_event_timer_get_remaining_ticks
* Assert that API out param is non-NULL instead of checking and returning
  error

 app/test/test_event_timer_adapter.c| 75 ++
 lib/eventdev/event_timer_adapter_pmd.h |  7 +++
 lib/eventdev/rte_event_timer_adapter.c | 53 ++
 lib/eventdev/rte_event_timer_adapter.h | 27 ++
 lib/eventdev/version.map   |  3 ++
 5 files changed, 165 insertions(+)

diff --git a/app/test/test_event_timer_adapter.c 
b/app/test/test_event_timer_adapter.c
index 1a440dfd10..5e7feec1c7 100644
--- a/app/test/test_event_timer_adapter.c
+++ b/app/test/test_event_timer_adapter.c
@@ -1920,6 +1920,79 @@ adapter_create_max(void)
return TEST_SUCCESS;
 }
 
+static inline int
+test_timer_ticks_remaining(void)
+{
+   uint64_t ticks_remaining = UINT64_MAX;
+   struct rte_event_timer *ev_tim;
+   struct rte_event ev;
+   int ret, i;
+   const struct rte_event_timer tim = {
+   .ev.op = RTE_EVENT_OP_NEW,
+   .ev.queue_id = 0,
+   .ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+   .ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+   .ev.event_type =  RTE_EVENT_TYPE_TIMER,
+   .state = RTE_EVENT_TIMER_NOT_ARMED,
+   };
+
+   rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+   *ev_tim = tim;
+   ev_tim->ev.event_ptr = ev_tim;
+#define TEST_TICKS 5
+   ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
+
+   ret = rte_event_timer_remaining_ticks_get(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret == -ENOTSUP) {
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+   printf("API not supported, skipping test\n");
+   return TEST_SKIPPED;
+   }
+
+   /* Test that unarmed timer returns error */
+   TEST_ASSERT_FAIL(ret,
+"Didn't fail to get ticks for unarmed event timer");
+
+   TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+ "Failed to arm timer with proper timeout.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+   for (i = 0; i < TEST_TICKS; i++) {
+   ret = rte_event_timer_remaining_ticks_get(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret < 0)
+   return TEST_FAILED;
+
+   TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
+ "Expected %d ticks remaining, got %"PRIu64"",
+ TEST_TICKS - i, ticks_remaining);
+
+   rte_delay_ms(100);
+   }
+
+   rte_delay_ms(100);
+
+   TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+ "Armed timer failed to trigger.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
+
+   /* Test that timer that fired returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_remaining_ticks_get(timdev, ev_tim,
+  &ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+#undef TEST_TICKS
+   return TEST_SUCCESS;
+}
+
+
 static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
.suite_name = "event timer functional test suite",
.setup = testsuite_setup,
@@ -1982,6 +2055,8 @@ static struct unit_test_suite 
event_timer_adptr_functional_testsuite  = {
TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
adapter_tick_resolution),
TEST_CASE(adapter_create_max),
+   TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+   test_timer_ticks_remaining),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
diff --git a/lib/eventdev/event_timer_adapter_pmd.h 
b/lib/eventdev/event_timer_adapter_p

[PATCH] eventdev/timer: fix overflow issue

2023-01-24 Thread Erik Gabriel Carrillo
The software timer adapter converts event timer timeout ticks to a
number of CPU cycles at which an rte_timer should expire. The
computation uses integer operations that can result in overflow.

Use floating point operations instead to perform the computation, and
convert the final result back to an integer type when returning. Also
move the logic that checks the timeout range into the function that
performs the above computation.

Fixes: 6750b21bd6af ("eventdev: add default software timer adapter")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/eventdev/rte_event_timer_adapter.c | 72 +-
 1 file changed, 35 insertions(+), 37 deletions(-)

diff --git a/lib/eventdev/rte_event_timer_adapter.c 
b/lib/eventdev/rte_event_timer_adapter.c
index d357f7403a..dbfb91ec1c 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -719,13 +719,29 @@ swtim_callback(struct rte_timer *tim)
}
 }
 
-static __rte_always_inline uint64_t
+static __rte_always_inline int
 get_timeout_cycles(struct rte_event_timer *evtim,
-  const struct rte_event_timer_adapter *adapter)
+  const struct rte_event_timer_adapter *adapter,
+  uint64_t *timeout_cycles)
 {
struct swtim *sw = swtim_pmd_priv(adapter);
-   uint64_t timeout_ns = evtim->timeout_ticks * sw->timer_tick_ns;
-   return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+   uint64_t timeout_nsecs;
+   double cycles_per_nsec;
+
+   cycles_per_nsec = (double)rte_get_timer_hz() / NSECPERSEC;
+
+   timeout_nsecs = evtim->timeout_ticks * sw->timer_tick_ns;
+   if (timeout_nsecs > sw->max_tmo_ns ||
+   timeout_nsecs > UINT64_MAX / cycles_per_nsec)
+   return -1;
+   if (timeout_nsecs < sw->timer_tick_ns)
+   return -2;
+
+   if (timeout_cycles)
+   *timeout_cycles = (uint64_t)ceil(timeout_nsecs *
+cycles_per_nsec);
+
+   return 0;
 }
 
 /* This function returns true if one or more (adapter) ticks have occurred 
since
@@ -759,23 +775,6 @@ swtim_did_tick(struct swtim *sw)
return false;
 }
 
-/* Check that event timer timeout value is in range */
-static __rte_always_inline int
-check_timeout(struct rte_event_timer *evtim,
- const struct rte_event_timer_adapter *adapter)
-{
-   uint64_t tmo_nsec;
-   struct swtim *sw = swtim_pmd_priv(adapter);
-
-   tmo_nsec = evtim->timeout_ticks * sw->timer_tick_ns;
-   if (tmo_nsec > sw->max_tmo_ns)
-   return -1;
-   if (tmo_nsec < sw->timer_tick_ns)
-   return -2;
-
-   return 0;
-}
-
 /* Check that event timer event queue sched type matches destination event 
queue
  * sched type
  */
@@ -1195,21 +1194,6 @@ __swtim_arm_burst(const struct rte_event_timer_adapter 
*adapter,
break;
}
 
-   ret = check_timeout(evtims[i], adapter);
-   if (unlikely(ret == -1)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TOOLATE,
-   __ATOMIC_RELAXED);
-   rte_errno = EINVAL;
-   break;
-   } else if (unlikely(ret == -2)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TOOEARLY,
-   __ATOMIC_RELAXED);
-   rte_errno = EINVAL;
-   break;
-   }
-
if (unlikely(check_destination_event_queue(evtims[i],
   adapter) < 0)) {
__atomic_store_n(&evtims[i]->state,
@@ -1225,7 +1209,21 @@ __swtim_arm_burst(const struct rte_event_timer_adapter 
*adapter,
evtims[i]->impl_opaque[0] = (uintptr_t)tim;
evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
 
-   cycles = get_timeout_cycles(evtims[i], adapter);
+   ret = get_timeout_cycles(evtims[i], adapter, &cycles);
+   if (unlikely(ret == -1)) {
+   __atomic_store_n(&evtims[i]->state,
+   RTE_EVENT_TIMER_ERROR_TOOLATE,
+   __ATOMIC_RELAXED);
+   rte_errno = EINVAL;
+   break;
+   } else if (unlikely(ret == -2)) {
+   __atomic_store_n(&evtims[i]->state,
+   RTE_EVENT_TIMER_ERROR_TOOEARLY,
+   __ATOMIC_RELAXED);
+   rte_errno = EINVAL;
+   break;
+   }
+
r

[PATCH v2] eventdev/timer: fix overflow issue

2023-01-24 Thread Erik Gabriel Carrillo
The software timer adapter converts event timer timeout ticks to a
number of CPU cycles at which an rte_timer should expire. The
computation uses integer operations that can result in overflow.

Use floating point operations instead to perform the computation, and
convert the final result back to an integer type when returning. Also
move the logic that checks the timeout range into the function that
performs the above computation.

Fixes: 6750b21bd6af ("eventdev: add default software timer adapter")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
v2:
* Fix implicit int to float conversion build warning on Clang

 lib/eventdev/rte_event_timer_adapter.c | 71 --
 1 file changed, 34 insertions(+), 37 deletions(-)

diff --git a/lib/eventdev/rte_event_timer_adapter.c 
b/lib/eventdev/rte_event_timer_adapter.c
index d357f7403a..2efeb73bce 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -719,13 +719,28 @@ swtim_callback(struct rte_timer *tim)
}
 }
 
-static __rte_always_inline uint64_t
+static __rte_always_inline int
 get_timeout_cycles(struct rte_event_timer *evtim,
-  const struct rte_event_timer_adapter *adapter)
+  const struct rte_event_timer_adapter *adapter,
+  uint64_t *timeout_cycles)
 {
struct swtim *sw = swtim_pmd_priv(adapter);
-   uint64_t timeout_ns = evtim->timeout_ticks * sw->timer_tick_ns;
-   return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+   uint64_t timeout_nsecs;
+   double cycles_per_nsec;
+
+   cycles_per_nsec = (double)rte_get_timer_hz() / NSECPERSEC;
+
+   timeout_nsecs = evtim->timeout_ticks * sw->timer_tick_ns;
+   if (timeout_nsecs > sw->max_tmo_ns)
+   return -1;
+   if (timeout_nsecs < sw->timer_tick_ns)
+   return -2;
+
+   if (timeout_cycles)
+   *timeout_cycles = (uint64_t)ceil(timeout_nsecs *
+cycles_per_nsec);
+
+   return 0;
 }
 
 /* This function returns true if one or more (adapter) ticks have occurred 
since
@@ -759,23 +774,6 @@ swtim_did_tick(struct swtim *sw)
return false;
 }
 
-/* Check that event timer timeout value is in range */
-static __rte_always_inline int
-check_timeout(struct rte_event_timer *evtim,
- const struct rte_event_timer_adapter *adapter)
-{
-   uint64_t tmo_nsec;
-   struct swtim *sw = swtim_pmd_priv(adapter);
-
-   tmo_nsec = evtim->timeout_ticks * sw->timer_tick_ns;
-   if (tmo_nsec > sw->max_tmo_ns)
-   return -1;
-   if (tmo_nsec < sw->timer_tick_ns)
-   return -2;
-
-   return 0;
-}
-
 /* Check that event timer event queue sched type matches destination event 
queue
  * sched type
  */
@@ -1195,21 +1193,6 @@ __swtim_arm_burst(const struct rte_event_timer_adapter 
*adapter,
break;
}
 
-   ret = check_timeout(evtims[i], adapter);
-   if (unlikely(ret == -1)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TOOLATE,
-   __ATOMIC_RELAXED);
-   rte_errno = EINVAL;
-   break;
-   } else if (unlikely(ret == -2)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TOOEARLY,
-   __ATOMIC_RELAXED);
-   rte_errno = EINVAL;
-   break;
-   }
-
if (unlikely(check_destination_event_queue(evtims[i],
   adapter) < 0)) {
__atomic_store_n(&evtims[i]->state,
@@ -1225,7 +1208,21 @@ __swtim_arm_burst(const struct rte_event_timer_adapter 
*adapter,
evtims[i]->impl_opaque[0] = (uintptr_t)tim;
evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
 
-   cycles = get_timeout_cycles(evtims[i], adapter);
+   ret = get_timeout_cycles(evtims[i], adapter, &cycles);
+   if (unlikely(ret == -1)) {
+   __atomic_store_n(&evtims[i]->state,
+   RTE_EVENT_TIMER_ERROR_TOOLATE,
+   __ATOMIC_RELAXED);
+   rte_errno = EINVAL;
+   break;
+   } else if (unlikely(ret == -2)) {
+   __atomic_store_n(&evtims[i]->state,
+   RTE_EVENT_TIMER_ERROR_TOOEARLY,
+   __ATOMIC_RELAXED);
+   rte_errno = EINVAL;
+  

[dpdk-dev] [PATCH] eventdev: fix free of adapters storage

2021-10-20 Thread Erik Gabriel Carrillo
Fix a typo that can cause the hugepage memory that backs the adapters
array to be freed unexpectedly.

Fixes: e9caa6a09a "eventdev: move timer adapters memory to hugepage")

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/eventdev/rte_event_timer_adapter.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/eventdev/rte_event_timer_adapter.c 
b/lib/eventdev/rte_event_timer_adapter.c
index 86b6c3fc6f..0e21b7c475 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -407,7 +407,7 @@ rte_event_timer_adapter_free(struct rte_event_timer_adapter 
*adapter)
ret = 0;
for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++)
if (adapters[i].allocated)
-   ret = adapter[i].allocated;
+   ret = adapters[i].allocated;
 
if (!ret) {
rte_free(adapters);
-- 
2.23.0



[PATCH v3] eventdev/timer: fix overflow issue

2023-02-09 Thread Erik Gabriel Carrillo
The software timer adapter converts event timer timeout ticks to a
number of TSC cycles at which an rte_timer should expire. The
computation uses an integer multiplication that can result in overflow.

If necessary, reduce the timeout_nsecs value by the number of whole
seconds it contains to keep the value of the multiplier within a
range that will not result in overflow.  Add the saved value back later
to get the final result. Also, move the logic that checks the timeout
range into the function that performs the above computation.

Fixes: 6750b21bd6af ("eventdev: add default software timer adapter")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
v3:
* Use integer operations instead of floating point, and use
  rte_reciprocal_divide() for division.

v2:
* Fix implicit int to float conversion build warning on Clang

 lib/eventdev/rte_event_timer_adapter.c | 97 --
 1 file changed, 59 insertions(+), 38 deletions(-)

diff --git a/lib/eventdev/rte_event_timer_adapter.c 
b/lib/eventdev/rte_event_timer_adapter.c
index 7f4f347369..23eb1d4a7d 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "event_timer_adapter_pmd.h"
 #include "eventdev_pmd.h"
@@ -734,13 +735,51 @@ swtim_callback(struct rte_timer *tim)
}
 }
 
-static __rte_always_inline uint64_t
+static __rte_always_inline int
 get_timeout_cycles(struct rte_event_timer *evtim,
-  const struct rte_event_timer_adapter *adapter)
+  const struct rte_event_timer_adapter *adapter,
+  uint64_t *timeout_cycles)
 {
-   struct swtim *sw = swtim_pmd_priv(adapter);
-   uint64_t timeout_ns = evtim->timeout_ticks * sw->timer_tick_ns;
-   return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+   static struct rte_reciprocal_u64 nsecpersec_inverse;
+   static uint64_t timer_hz;
+   uint64_t rem_cycles, secs_cycles = 0;
+   uint64_t secs, timeout_nsecs;
+   uint64_t nsecpersec;
+   struct swtim *sw;
+
+   sw = swtim_pmd_priv(adapter);
+   nsecpersec = (uint64_t)NSECPERSEC;
+
+   timeout_nsecs = evtim->timeout_ticks * sw->timer_tick_ns;
+   if (timeout_nsecs > sw->max_tmo_ns)
+   return -1;
+   if (timeout_nsecs < sw->timer_tick_ns)
+   return -2;
+
+   /* Set these values in the first invocation */
+   if (!timer_hz) {
+   timer_hz = rte_get_timer_hz();
+   nsecpersec_inverse = rte_reciprocal_value_u64(nsecpersec);
+   }
+
+   /* If timeout_nsecs > nsecpersec, decrease timeout_nsecs by the number
+* of whole seconds it contains and convert that value to a number
+* of cycles. This keeps timeout_nsecs in the interval [0..nsecpersec)
+* in order to avoid overflow when we later multiply by timer_hz.
+*/
+   if (timeout_nsecs > nsecpersec) {
+   secs = rte_reciprocal_divide_u64(timeout_nsecs,
+&nsecpersec_inverse);
+   secs_cycles = secs * timer_hz;
+   timeout_nsecs -= secs * nsecpersec;
+   }
+
+   rem_cycles = rte_reciprocal_divide_u64(timeout_nsecs * timer_hz,
+  &nsecpersec_inverse);
+
+   *timeout_cycles = secs_cycles + rem_cycles;
+
+   return 0;
 }
 
 /* This function returns true if one or more (adapter) ticks have occurred 
since
@@ -774,23 +813,6 @@ swtim_did_tick(struct swtim *sw)
return false;
 }
 
-/* Check that event timer timeout value is in range */
-static __rte_always_inline int
-check_timeout(struct rte_event_timer *evtim,
- const struct rte_event_timer_adapter *adapter)
-{
-   uint64_t tmo_nsec;
-   struct swtim *sw = swtim_pmd_priv(adapter);
-
-   tmo_nsec = evtim->timeout_ticks * sw->timer_tick_ns;
-   if (tmo_nsec > sw->max_tmo_ns)
-   return -1;
-   if (tmo_nsec < sw->timer_tick_ns)
-   return -2;
-
-   return 0;
-}
-
 /* Check that event timer event queue sched type matches destination event 
queue
  * sched type
  */
@@ -1210,21 +1232,6 @@ __swtim_arm_burst(const struct rte_event_timer_adapter 
*adapter,
break;
}
 
-   ret = check_timeout(evtims[i], adapter);
-   if (unlikely(ret == -1)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TOOLATE,
-   __ATOMIC_RELAXED);
-   rte_errno = EINVAL;
-   break;
-   } else if (unlikely(ret == -2)) {
-   __atomic_store_n(&evtims[i]->state,
-   RTE_EVENT_TIMER_ERROR_TO

[PATCH] eventdev/timer: move buffer flush call

2023-04-12 Thread Erik Gabriel Carrillo
The SW event timer adapter attempts to flush its event buffer on every
adapter tick. If events remain in the buffer after the attempt, another
attempt to flush won't occur until the next adapter tick, which delays
the enqueue of those events to the event device unecessarily.

Move the buffer flush call so that it happens with every invocation of
the service function, rather than on every adapter tick, to avoid the
delay.

Fixes: cc7b73ea9e3b ("eventdev: add new software timer adapter")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/eventdev/rte_event_timer_adapter.c | 17 +
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/lib/eventdev/rte_event_timer_adapter.c 
b/lib/eventdev/rte_event_timer_adapter.c
index 23eb1d4a7d..427c4c6287 100644
--- a/lib/eventdev/rte_event_timer_adapter.c
+++ b/lib/eventdev/rte_event_timer_adapter.c
@@ -855,17 +855,18 @@ swtim_service_func(void *arg)
 sw->n_expired_timers);
sw->n_expired_timers = 0;
 
-   event_buffer_flush(&sw->buffer,
-  adapter->data->event_dev_id,
-  adapter->data->event_port_id,
-  &nb_evs_flushed,
-  &nb_evs_invalid);
-
-   sw->stats.ev_enq_count += nb_evs_flushed;
-   sw->stats.ev_inv_count += nb_evs_invalid;
sw->stats.adapter_tick_count++;
}
 
+   event_buffer_flush(&sw->buffer,
+  adapter->data->event_dev_id,
+  adapter->data->event_port_id,
+  &nb_evs_flushed,
+  &nb_evs_invalid);
+
+   sw->stats.ev_enq_count += nb_evs_flushed;
+   sw->stats.ev_inv_count += nb_evs_invalid;
+
rte_event_maintain(adapter->data->event_dev_id,
   adapter->data->event_port_id, 0);
 
-- 
2.23.0



[PATCH] eventdev/timer: add API to get remaining ticks

2022-12-16 Thread Erik Gabriel Carrillo
Introduce an event timer adapter API which allows users to determine how
many adapter ticks remain until an event timer fires.

Signed-off-by: Erik Gabriel Carrillo 
---
 app/test/test_event_timer_adapter.c| 68 ++
 lib/eventdev/event_timer_adapter_pmd.h |  7 +++
 lib/eventdev/rte_event_timer_adapter.c | 52 
 lib/eventdev/rte_event_timer_adapter.h | 27 ++
 lib/eventdev/version.map   |  3 ++
 5 files changed, 157 insertions(+)

diff --git a/app/test/test_event_timer_adapter.c 
b/app/test/test_event_timer_adapter.c
index 1a440dfd10..6529b14ff9 100644
--- a/app/test/test_event_timer_adapter.c
+++ b/app/test/test_event_timer_adapter.c
@@ -1920,6 +1920,72 @@ adapter_create_max(void)
return TEST_SUCCESS;
 }
 
+static inline int
+test_timer_ticks_remaining(void)
+{
+   uint64_t ticks_remaining = UINT64_MAX;
+   struct rte_event_timer *ev_tim;
+   struct rte_event ev;
+   int ret, i;
+   const struct rte_event_timer tim = {
+   .ev.op = RTE_EVENT_OP_NEW,
+   .ev.queue_id = 0,
+   .ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+   .ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+   .ev.event_type =  RTE_EVENT_TYPE_TIMER,
+   .state = RTE_EVENT_TIMER_NOT_ARMED,
+   };
+
+   rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+   *ev_tim = tim;
+   ev_tim->ev.event_ptr = ev_tim;
+#define TEST_TICKS 5
+   ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
+
+   /* Test that unarmed timer returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+&ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+ "Failed to arm timer with proper timeout.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+   for (i = 0; i < TEST_TICKS; i++) {
+   ret = rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret < 0)
+   return TEST_FAILED;
+
+   TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
+ "Expected %d ticks remaining, got %"PRIu64"",
+ TEST_TICKS - i, ticks_remaining);
+
+   rte_delay_ms(100);
+   }
+
+   rte_delay_ms(100);
+
+   TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+ "Armed timer failed to trigger.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
+
+   /* Test that timer that fired returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_ticks_remaining_get(timdev, ev_tim,
+  &ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+#undef TEST_TICKS
+   return TEST_SUCCESS;
+}
+
+
 static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
.suite_name = "event timer functional test suite",
.setup = testsuite_setup,
@@ -1982,6 +2048,8 @@ static struct unit_test_suite 
event_timer_adptr_functional_testsuite  = {
TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
adapter_tick_resolution),
TEST_CASE(adapter_create_max),
+   TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+   test_timer_ticks_remaining),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
diff --git a/lib/eventdev/event_timer_adapter_pmd.h 
b/lib/eventdev/event_timer_adapter_pmd.h
index 189017b5c1..c19ff3576a 100644
--- a/lib/eventdev/event_timer_adapter_pmd.h
+++ b/lib/eventdev/event_timer_adapter_pmd.h
@@ -52,6 +52,11 @@ typedef int (*rte_event_timer_adapter_stats_get_t)(
 typedef int (*rte_event_timer_adapter_stats_reset_t)(
const struct rte_event_timer_adapter *adapter);
 /**< @internal Reset statistics for event timer adapter */
+typedef int (*rte_event_timer_ticks_remaining_get_t)(
+   const struct rte_event_timer_adapter *adapter,
+   const struct rte_event_timer *evtim,
+   uint64_t *t

[PATCH v2] eventdev/timer: add API to get remaining ticks

2022-12-19 Thread Erik Gabriel Carrillo
Introduce an event timer adapter API which allows users to determine how
many adapter ticks remain until an event timer fires.

Signed-off-by: Erik Gabriel Carrillo 
---
v2:
* Rename API to rte_event_timer_get_remaining_ticks
* Assert that API out param is non-NULL instead of checking and returning
  error

 app/test/test_event_timer_adapter.c| 68 ++
 lib/eventdev/event_timer_adapter_pmd.h |  7 +++
 lib/eventdev/rte_event_timer_adapter.c | 52 
 lib/eventdev/rte_event_timer_adapter.h | 27 ++
 lib/eventdev/version.map   |  3 ++
 5 files changed, 157 insertions(+)

diff --git a/app/test/test_event_timer_adapter.c 
b/app/test/test_event_timer_adapter.c
index 1a440dfd10..1a1fb48b24 100644
--- a/app/test/test_event_timer_adapter.c
+++ b/app/test/test_event_timer_adapter.c
@@ -1920,6 +1920,72 @@ adapter_create_max(void)
return TEST_SUCCESS;
 }
 
+static inline int
+test_timer_ticks_remaining(void)
+{
+   uint64_t ticks_remaining = UINT64_MAX;
+   struct rte_event_timer *ev_tim;
+   struct rte_event ev;
+   int ret, i;
+   const struct rte_event_timer tim = {
+   .ev.op = RTE_EVENT_OP_NEW,
+   .ev.queue_id = 0,
+   .ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+   .ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+   .ev.event_type =  RTE_EVENT_TYPE_TIMER,
+   .state = RTE_EVENT_TIMER_NOT_ARMED,
+   };
+
+   rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+   *ev_tim = tim;
+   ev_tim->ev.event_ptr = ev_tim;
+#define TEST_TICKS 5
+   ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
+
+   /* Test that unarmed timer returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+&ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+ "Failed to arm timer with proper timeout.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+   for (i = 0; i < TEST_TICKS; i++) {
+   ret = rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret < 0)
+   return TEST_FAILED;
+
+   TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
+ "Expected %d ticks remaining, got %"PRIu64"",
+ TEST_TICKS - i, ticks_remaining);
+
+   rte_delay_ms(100);
+   }
+
+   rte_delay_ms(100);
+
+   TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+ "Armed timer failed to trigger.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
+
+   /* Test that timer that fired returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+  &ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+#undef TEST_TICKS
+   return TEST_SUCCESS;
+}
+
+
 static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
.suite_name = "event timer functional test suite",
.setup = testsuite_setup,
@@ -1982,6 +2048,8 @@ static struct unit_test_suite 
event_timer_adptr_functional_testsuite  = {
TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
adapter_tick_resolution),
TEST_CASE(adapter_create_max),
+   TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+   test_timer_ticks_remaining),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
diff --git a/lib/eventdev/event_timer_adapter_pmd.h 
b/lib/eventdev/event_timer_adapter_pmd.h
index 189017b5c1..7ba9df463b 100644
--- a/lib/eventdev/event_timer_adapter_pmd.h
+++ b/lib/eventdev/event_timer_adapter_pmd.h
@@ -52,6 +52,11 @@ typedef int (*rte_event_timer_adapter_stats_get_t)(
 typedef int (*rte_event_timer_adapter_stats_reset_t)(
const struct rte_event_timer_adapter *adapter);
 /**< @internal Reset statistics for event timer adapter */
+typedef int (*rte_event_timer_get_remaining_ticks_t)(
+  

[PATCH v3] eventdev/timer: add API to get remaining ticks

2022-12-19 Thread Erik Gabriel Carrillo
Introduce an event timer adapter API which allows users to determine how
many adapter ticks remain until an event timer fires.

Signed-off-by: Erik Gabriel Carrillo 
---
v3:
* Handle ENOTSUP case in unit test

v2:
* Rename API to rte_event_timer_get_remaining_ticks
* Assert that API out param is non-NULL instead of checking and returning
  error

 app/test/test_event_timer_adapter.c| 75 ++
 lib/eventdev/event_timer_adapter_pmd.h |  7 +++
 lib/eventdev/rte_event_timer_adapter.c | 52 ++
 lib/eventdev/rte_event_timer_adapter.h | 27 ++
 lib/eventdev/version.map   |  3 ++
 5 files changed, 164 insertions(+)

diff --git a/app/test/test_event_timer_adapter.c 
b/app/test/test_event_timer_adapter.c
index 1a440dfd10..6241a70597 100644
--- a/app/test/test_event_timer_adapter.c
+++ b/app/test/test_event_timer_adapter.c
@@ -1920,6 +1920,79 @@ adapter_create_max(void)
return TEST_SUCCESS;
 }
 
+static inline int
+test_timer_ticks_remaining(void)
+{
+   uint64_t ticks_remaining = UINT64_MAX;
+   struct rte_event_timer *ev_tim;
+   struct rte_event ev;
+   int ret, i;
+   const struct rte_event_timer tim = {
+   .ev.op = RTE_EVENT_OP_NEW,
+   .ev.queue_id = 0,
+   .ev.sched_type = RTE_SCHED_TYPE_ATOMIC,
+   .ev.priority = RTE_EVENT_DEV_PRIORITY_NORMAL,
+   .ev.event_type =  RTE_EVENT_TYPE_TIMER,
+   .state = RTE_EVENT_TIMER_NOT_ARMED,
+   };
+
+   rte_mempool_get(eventdev_test_mempool, (void **)&ev_tim);
+   *ev_tim = tim;
+   ev_tim->ev.event_ptr = ev_tim;
+#define TEST_TICKS 5
+   ev_tim->timeout_ticks = CALC_TICKS(TEST_TICKS);
+
+   ret = rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret == -ENOTSUP) {
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+   printf("API not supported, skipping test\n");
+   return TEST_SKIPPED;
+   }
+
+   /* Test that unarmed timer returns error */
+   TEST_ASSERT_FAIL(ret,
+"Didn't fail to get ticks for unarmed event timer");
+
+   TEST_ASSERT_EQUAL(rte_event_timer_arm_burst(timdev, &ev_tim, 1), 1,
+ "Failed to arm timer with proper timeout.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_ARMED, ev_tim->state);
+
+   for (i = 0; i < TEST_TICKS; i++) {
+   ret = rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+ &ticks_remaining);
+   if (ret < 0)
+   return TEST_FAILED;
+
+   TEST_ASSERT_EQUAL((int)ticks_remaining, TEST_TICKS - i,
+ "Expected %d ticks remaining, got %"PRIu64"",
+ TEST_TICKS - i, ticks_remaining);
+
+   rte_delay_ms(100);
+   }
+
+   rte_delay_ms(100);
+
+   TEST_ASSERT_EQUAL(rte_event_dequeue_burst(evdev, 0, &ev, 1, 0), 1,
+ "Armed timer failed to trigger.");
+   TEST_ASSERT_EQUAL(ev_tim->state, RTE_EVENT_TIMER_NOT_ARMED,
+ "Improper timer state set expected %d returned %d",
+ RTE_EVENT_TIMER_NOT_ARMED, ev_tim->state);
+
+   /* Test that timer that fired returns error */
+   TEST_ASSERT_FAIL(rte_event_timer_get_remaining_ticks(timdev, ev_tim,
+  &ticks_remaining),
+"Didn't fail to get ticks for unarmed event timer");
+
+   rte_mempool_put(eventdev_test_mempool, (void *)ev_tim);
+
+#undef TEST_TICKS
+   return TEST_SUCCESS;
+}
+
+
 static struct unit_test_suite event_timer_adptr_functional_testsuite  = {
.suite_name = "event timer functional test suite",
.setup = testsuite_setup,
@@ -1982,6 +2055,8 @@ static struct unit_test_suite 
event_timer_adptr_functional_testsuite  = {
TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
adapter_tick_resolution),
TEST_CASE(adapter_create_max),
+   TEST_CASE_ST(timdev_setup_msec, timdev_teardown,
+   test_timer_ticks_remaining),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
diff --git a/lib/eventdev/event_timer_adapter_pmd.h 
b/lib/eventdev/event_timer_adapter_pmd.h
index 189017b5c1..7ba9df463b 100644
--- a/lib/eventdev/event_timer_adapter_pmd.h
+++ b/lib/eventdev/event_timer_adapter_pmd.h
@@ -52,6 +52,11 @@ typedef int (*rte_event_t

[dpdk-dev] [PATCH v2] app/eventdev: detect deadlock for timer event producer

2018-12-03 Thread Erik Gabriel Carrillo
If timer events get dropped for some reason, the thread that launched
producer and worker cores will never exit, because the deadlock check
doesn't currently apply to the event timer adapter case. This commit
fixes this.

Fixes: d008f20bce23 ("app/eventdev: add event timer adapter as a
producer")

Signed-off-by: Erik Gabriel Carrillo 
---
v2:
 - Add a fixline to commit message

 app/test-eventdev/test_perf_common.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/test-eventdev/test_perf_common.c 
b/app/test-eventdev/test_perf_common.c
index 8618775..f99a6a6 100644
--- a/app/test-eventdev/test_perf_common.c
+++ b/app/test-eventdev/test_perf_common.c
@@ -327,7 +327,8 @@ perf_launch_lcores(struct evt_test *test, struct 
evt_options *opt,
}
 
if (new_cycles - dead_lock_cycles > dead_lock_sample &&
-   opt->prod_type == EVT_PROD_TYPE_SYNT) {
+   (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR)) {
remaining = t->outstand_pkts - processed_pkts(t);
if (dead_lock_remaining == remaining) {
rte_event_dev_dump(opt->dev_id, stdout);
-- 
2.6.4



[dpdk-dev] [PATCH v3] app/eventdev: detect deadlock for timer event producer

2018-12-03 Thread Erik Gabriel Carrillo
If timer events get dropped for some reason, the thread that launched
producer and worker cores will never exit, because the deadlock check
doesn't currently apply to the event timer adapter case. This commit
fixes this.

Fixes: d008f20bce23 ("app/eventdev: add event timer adapter as a
producer")

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
v3:
 - Forgot to add Jerin's ack line.
v2:
 - Add a fixline to commit message (Jerin)

 app/test-eventdev/test_perf_common.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/test-eventdev/test_perf_common.c 
b/app/test-eventdev/test_perf_common.c
index 8618775..f99a6a6 100644
--- a/app/test-eventdev/test_perf_common.c
+++ b/app/test-eventdev/test_perf_common.c
@@ -327,7 +327,8 @@ perf_launch_lcores(struct evt_test *test, struct 
evt_options *opt,
}
 
if (new_cycles - dead_lock_cycles > dead_lock_sample &&
-   opt->prod_type == EVT_PROD_TYPE_SYNT) {
+   (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR)) {
remaining = t->outstand_pkts - processed_pkts(t);
if (dead_lock_remaining == remaining) {
rte_event_dev_dump(opt->dev_id, stdout);
-- 
2.6.4



[dpdk-dev] [PATCH v2 1/2] timer: allow timer management in shared memory

2018-12-07 Thread Erik Gabriel Carrillo
Currently, the timer library uses a per-process table of structures to
manage skiplists of timers presumably because timers contain arbitrary
function pointers whose value may not resolve properly in other
processes.

However, if the same callback is used handle all timers, and that
callback is only invoked in one process, then it woud be safe to allow
the data structures to be allocated in shared memory, and to allow
secondary processes to modify the timer lists.  This would let timers be
used in more multi-process scenarios.

The library's global variables are wrapped with a struct, and an array
of these structures is created in shared memory.  The original APIs
are updated to reference the zeroth entry in the array. This maintains
the original behavior for both primary and secondary processes since
the set intersection of their coremasks should be empty [1].  New APIs
are introduced to enable the allocation/deallocation of other entries
in the array.

New variants of the APIs used to start and stop timers are introduced;
they allow a caller to specify which array entry should be used to
locate the timer list to insert into or delete from.

Finally, a new variant of rte_timer_manage() is introduced, which
allows a caller to specify which array entry should be used to locate
the timer lists to process; it can also process multiple timer lists per
invocation.

[1] 
https://doc.dpdk.org/guides/prog_guide/multi_proc_support.html#multi-process-limitations

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 519 ++---
 lib/librte_timer/rte_timer.h   | 226 +-
 lib/librte_timer/rte_timer_version.map |  22 ++
 4 files changed, 723 insertions(+), 45 deletions(-)

diff --git a/lib/librte_timer/Makefile b/lib/librte_timer/Makefile
index 4ebd528..8ec63f4 100644
--- a/lib/librte_timer/Makefile
+++ b/lib/librte_timer/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 # library name
 LIB = librte_timer.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 LDLIBS += -lrte_eal
 
diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 30c7b0a..571fb3f 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,11 +22,15 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include "rte_timer.h"
 
-LIST_HEAD(rte_timer_list, rte_timer);
-
+/**
+ * Per-lcore info for timers.
+ */
 struct priv_timer {
struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
rte_spinlock_t list_lock;   /**< lock to protect list access */
@@ -48,25 +53,84 @@ struct priv_timer {
 #endif
 } __rte_cache_aligned;
 
-/** per-lcore private info for timers */
-static struct priv_timer priv_timer[RTE_MAX_LCORE];
+#define FL_ALLOCATED   (1 << 0)
+struct rte_timer_data {
+   struct priv_timer priv_timer[RTE_MAX_LCORE];
+   uint8_t internal_flags;
+};
+
+#define RTE_MAX_DATA_ELS 64
+static struct rte_timer_data *rte_timer_data_arr;
+static uint32_t default_data_id;  // id set to zero automatically
+static uint32_t rte_timer_subsystem_initialized;
+
+/* For maintaining older interfaces for a period */
+static struct rte_timer_data default_timer_data;
 
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
-#define __TIMER_STAT_ADD(name, n) do { \
+#define __TIMER_STAT_ADD(priv_timer, name, n) do { \
unsigned __lcore_id = rte_lcore_id();   \
if (__lcore_id < RTE_MAX_LCORE) \
priv_timer[__lcore_id].stats.name += (n);   \
} while(0)
 #else
-#define __TIMER_STAT_ADD(name, n) do {} while(0)
+#define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0)
 #endif
 
-/* Init the timer library. */
+static inline int
+timer_data_valid(uint32_t id)
+{
+   return !!(rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
+}
+
+/* validate ID and retrieve timer data pointer, or return error value */
+#define TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, retval) do {   \
+   if (id >= RTE_MAX_DATA_ELS || !timer_data_valid(id))\
+   return retval;  \
+   timer_data = &rte_timer_data_arr[id];   \
+} while (0)
+
+int __rte_experimental
+rte_timer_data_alloc(uint32_t *id_ptr)
+{
+   int i;
+   struct rte_timer_data *data;
+
+   if (!rte_timer_subsystem_initialized)
+   return -ENOMEM;
+
+   for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
+   data = &rte_timer_data_arr[i];
+   if (!(data->internal_flags & FL_ALL

[dpdk-dev] [PATCH v2 0/2] Timer library changes

2018-12-07 Thread Erik Gabriel Carrillo
This patch series modifies the timer library in such a way that 
structures that used to be statically allocated in a process's data
segment are now allocated in shared memory.  As these structures contain
lists of timers, new APIs are introduced that allow a caller to specify
the particular structure instance into which a timer should be inserted
or from which a timer should be removed.  This enables primary and secondary
processes to modify the same timer list, which enables some
multi-process use cases that were not previously possible; e.g. a
secondary process can start a timer whose expiration is detected in a
primary process running a new flavor of timer_manage().

The original library API is mostly unchanged, though implementations are
updated to call into newly added functions with a default structure instance
ID that provides the original behavior.  New functions are introduced to
enable applications to allocate structure instances to house timer
lists, and to reference them with an identifier when starting and
stopping timers, and finally, to manage the timer lists referenced with
an identifier.

My initial performance testing with the "timer_perf_autotest" test shows
no performance regression or improvement, and inspection of the
generated optimized code shows that the extra function call gets inlined
in the functions that now have an extra function call. 

Depends on: https://patches.dpdk.org/patch/48417/

Changes in v2:
 - split these changes out into their own series
 - version the symbols where the existing ABI was updated, and
   provide alternate implementation with behavior equivalent to original
   behavior. Validate ABI compatibility with validate-abi.sh
 - refactor changes to simplify patches

Erik Gabriel Carrillo (2):
  timer: allow timer management in shared memory
  timer: add function to stop all timers in a list

 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 558 ++---
 lib/librte_timer/rte_timer.h   | 258 ++-
 lib/librte_timer/rte_timer_version.map |  23 ++
 4 files changed, 795 insertions(+), 45 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v2 2/2] timer: add function to stop all timers in a list

2018-12-07 Thread Erik Gabriel Carrillo
Add a function to the timer API that allows a caller to traverse a
specified set of timer lists, stopping each timer in each list,
and invoking a callback function.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c   | 39 ++
 lib/librte_timer/rte_timer.h   | 32 
 lib/librte_timer/rte_timer_version.map |  1 +
 3 files changed, 72 insertions(+)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 571fb3f..23c755c 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -999,6 +999,45 @@ rte_timer_alt_manage(uint32_t timer_data_id,
return 0;
 }
 
+/* Walk pending lists, stopping timers and calling user-specified function */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores,
+  rte_timer_stop_all_cb_t f, void *f_arg)
+{
+   int i;
+   struct priv_timer *priv_timer;
+   uint32_t walk_lcore;
+   struct rte_timer *tim, *next_tim;
+   struct rte_timer_data *timer_data;
+
+   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
+
+   for (i = 0, walk_lcore = walk_lcores[i];
+i < nb_walk_lcores;
+walk_lcore = walk_lcores[++i]) {
+   priv_timer = &timer_data->priv_timer[walk_lcore];
+
+   rte_spinlock_lock(&priv_timer->list_lock);
+
+   for (tim = priv_timer->pending_head.sl_next[0];
+tim != NULL;
+tim = next_tim) {
+   next_tim = tim->sl_next[0];
+
+   /* Call timer_stop with lock held */
+   __rte_timer_stop(tim, 1, timer_data);
+
+   if (f)
+   f(tim, f_arg);
+   }
+
+   rte_spinlock_unlock(&priv_timer->list_lock);
+   }
+
+   return 0;
+}
+
 /* dump statistics about timers */
 static void
 __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f)
diff --git a/lib/librte_timer/rte_timer.h b/lib/librte_timer/rte_timer.h
index 82f5fba..b01bd97 100644
--- a/lib/librte_timer/rte_timer.h
+++ b/lib/librte_timer/rte_timer.h
@@ -500,6 +500,38 @@ rte_timer_alt_manage(uint32_t timer_data_id, unsigned int 
*poll_lcores,
 int n_poll_lcores, rte_timer_alt_manage_cb_t f);
 
 /**
+ * Callback function type for rte_timer_stop_all().
+ */
+typedef void (*rte_timer_stop_all_cb_t)(struct rte_timer *tim, void *arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Walk the pending timer lists for the specified lcore IDs, and for each timer
+ * that is encountered, stop it and call the specified callback function to
+ * process it further.
+ *
+ * @param timer_data_id
+ *   An identifier indicating which instance of timer data should be used for
+ *   this operation.
+ * @param walk_lcores
+ *   An array of lcore ids identifying the timer lists that should be 
processed.
+ * @param nb_walk_lcores
+ *   The size of the walk_lcores array.
+ * @param f
+ *   The callback function which should be called for each timers. Can be NULL.
+ * @param f_arg
+ *   An arbitrary argument that will be passed to f, if it is called.
+ * @return
+ *   - 0: success
+ *   - EINVAL: invalid timer_data_id
+ */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores, rte_timer_stop_all_cb_t f, void *f_arg);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
  *
diff --git a/lib/librte_timer/rte_timer_version.map 
b/lib/librte_timer/rte_timer_version.map
index b3f4b6c..278b2af 100644
--- a/lib/librte_timer/rte_timer_version.map
+++ b/lib/librte_timer/rte_timer_version.map
@@ -33,5 +33,6 @@ EXPERIMENTAL {
rte_timer_alt_stop;
rte_timer_data_alloc;
rte_timer_data_dealloc;
+   rte_timer_stop_all;
rte_timer_subsystem_finalize;
 };
-- 
2.6.4



[dpdk-dev] [PATCH v2 0/1] New software event timer adapter

2018-12-07 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD [1]. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a service
core in the primary process dequeued them and processed them further.  To
improve performance, this version does away with the ring and lets lcores in
both primary and secondary processes insert timers directly into timer
skiplist data structures; the service core directly accesses the lists as
well, when looking for timers that have expired. (This behavior requires
the patch to the timer library that is referenced below.)

Depends on: https://patches.dpdk.org/project/dpdk/list/?series=2699

[1] https://doc.dpdk.org/guides/prog_guide/event_timer_adapter.html

Changes in v2:
 - split this change out into its own patch series

Erik Gabriel Carrillo (1):
  eventdev: add new software event timer adapter

 lib/librte_eventdev/rte_event_timer_adapter.c | 687 +++---
 1 file changed, 275 insertions(+), 412 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v2 1/1] eventdev: add new software event timer adapter

2018-12-07 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a
service core in the primary process dequeued them and processed them
further.  To improve performance, this version does away with the ring
and lets lcores in both primary and secondary processes insert timers
directly into timer skiplist data structures; the service core directly
accesses the lists as well, when looking for timers that have expired.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 687 +++---
 1 file changed, 275 insertions(+), 412 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 79070d4..9c528cb 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -19,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -34,7 +36,7 @@ static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
-static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+static const struct rte_event_timer_adapter_ops swtim_ops;
 
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
@@ -211,7 +213,7 @@ rte_event_timer_adapter_create_ext(
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
@@ -334,7 +336,7 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
@@ -491,6 +493,7 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
}
 
*nb_events_inv = 0;
+
*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 &events[tail_idx], n);
if (*nb_events_flushed != n && rte_errno == -EINVAL) {
@@ -498,137 +501,123 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
(*nb_events_inv)++;
}
 
+   if (*nb_events_flushed > 0)
+   EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event "
+ "device", *nb_events_flushed);
+
bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
 }
 
 /*
  * Software event timer adapter implementation
  */
-
-struct rte_event_timer_adapter_sw_data {
-   /* List of messages for outstanding timers */
-   TAILQ_HEAD(, msg) msgs_tailq_head;
-   /* Lock to guard tailq and armed count */
-   rte_spinlock_t msgs_tailq_sl;
+struct swtim {
/* Identifier of service executing timer management logic. */
uint32_t service_id;
/* The cycle count at which the adapter should next tick */
uint64_t next_tick_cycles;
-   /* Incremented as the service moves through phases of an iteration */
-   volatile int service_phase;
/* The tick resolution used by adapter instance. May have been
 * adjusted from what user requested
 */
uint64_t timer_tick_ns;
/* Maximum timeout in nanoseconds allowed by adapter instance. */
uint64_t max_tmo_ns;
-   /* Ring containing messages to arm or cancel event timers */
-   struct rte_ring *msg_ring;
-   /* Mempool containing msg objects */
-   struct rte_mempool *msg_pool;
/* Buffered timer expiry events to be enqueued to an event device. */
struct event_buffer buffer;
/* Statistics */
struct rte_event_timer_adapter_stats stats;
-   /* The number of threads currently adding to the message ring */
-   rte_atomic16_t message_producer_count;
+   /* Mempool of timer objects */
+   struct rte_mempool *tim_pool;
+   /* Back pointer for convenience */
+   struct rte_event_timer_adapter *adapter;
+   /* Identifier of timer data instance */
+   uint32_t timer_data_id;
+   /* Track which cores have actually armed a timer */
+   rte_atomic16_t in_use[RTE_MAX_LCORE];
+   /* Track which cores' timer lists should be polled */
+   unsigned int poll_lcores[RTE_MAX_LCORE];
+   

[dpdk-dev] [PATCH v3 1/2] timer: allow timer management in shared memory

2018-12-13 Thread Erik Gabriel Carrillo
Currently, the timer library uses a per-process table of structures to
manage skiplists of timers presumably because timers contain arbitrary
function pointers whose value may not resolve properly in other
processes.

However, if the same callback is used handle all timers, and that
callback is only invoked in one process, then it woud be safe to allow
the data structures to be allocated in shared memory, and to allow
secondary processes to modify the timer lists.  This would let timers be
used in more multi-process scenarios.

The library's global variables are wrapped with a struct, and an array
of these structures is created in shared memory.  The original APIs
are updated to reference the zeroth entry in the array. This maintains
the original behavior for both primary and secondary processes since
the set intersection of their coremasks should be empty [1].  New APIs
are introduced to enable the allocation/deallocation of other entries
in the array.

New variants of the APIs used to start and stop timers are introduced;
they allow a caller to specify which array entry should be used to
locate the timer list to insert into or delete from.

Finally, a new variant of rte_timer_manage() is introduced, which
allows a caller to specify which array entry should be used to locate
the timer lists to process; it can also process multiple timer lists per
invocation.

[1] 
https://doc.dpdk.org/guides/prog_guide/multi_proc_support.html#multi-process-limitations

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 519 ++---
 lib/librte_timer/rte_timer.h   | 226 +-
 lib/librte_timer/rte_timer_version.map |  22 ++
 4 files changed, 723 insertions(+), 45 deletions(-)

diff --git a/lib/librte_timer/Makefile b/lib/librte_timer/Makefile
index 4ebd528..8ec63f4 100644
--- a/lib/librte_timer/Makefile
+++ b/lib/librte_timer/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 # library name
 LIB = librte_timer.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 LDLIBS += -lrte_eal
 
diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 30c7b0a..d761cda 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,11 +22,15 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include "rte_timer.h"
 
-LIST_HEAD(rte_timer_list, rte_timer);
-
+/**
+ * Per-lcore info for timers.
+ */
 struct priv_timer {
struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
rte_spinlock_t list_lock;   /**< lock to protect list access */
@@ -48,25 +53,84 @@ struct priv_timer {
 #endif
 } __rte_cache_aligned;
 
-/** per-lcore private info for timers */
-static struct priv_timer priv_timer[RTE_MAX_LCORE];
+#define FL_ALLOCATED   (1 << 0)
+struct rte_timer_data {
+   struct priv_timer priv_timer[RTE_MAX_LCORE];
+   uint8_t internal_flags;
+};
+
+#define RTE_MAX_DATA_ELS 64
+static struct rte_timer_data *rte_timer_data_arr;
+static uint32_t default_data_id;
+static uint32_t rte_timer_subsystem_initialized;
+
+/* For maintaining older interfaces for a period */
+static struct rte_timer_data default_timer_data;
 
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
-#define __TIMER_STAT_ADD(name, n) do { \
+#define __TIMER_STAT_ADD(priv_timer, name, n) do { \
unsigned __lcore_id = rte_lcore_id();   \
if (__lcore_id < RTE_MAX_LCORE) \
priv_timer[__lcore_id].stats.name += (n);   \
} while(0)
 #else
-#define __TIMER_STAT_ADD(name, n) do {} while(0)
+#define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0)
 #endif
 
-/* Init the timer library. */
+static inline int
+timer_data_valid(uint32_t id)
+{
+   return !!(rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
+}
+
+/* validate ID and retrieve timer data pointer, or return error value */
+#define TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, retval) do {   \
+   if (id >= RTE_MAX_DATA_ELS || !timer_data_valid(id))\
+   return retval;  \
+   timer_data = &rte_timer_data_arr[id];   \
+} while (0)
+
+int __rte_experimental
+rte_timer_data_alloc(uint32_t *id_ptr)
+{
+   int i;
+   struct rte_timer_data *data;
+
+   if (!rte_timer_subsystem_initialized)
+   return -ENOMEM;
+
+   for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
+   data = &rte_timer_data_arr[i];
+   if (!(data->internal_flags & FL_ALLOCATED)) {
+   data->in

[dpdk-dev] [PATCH v3 2/2] timer: add function to stop all timers in a list

2018-12-13 Thread Erik Gabriel Carrillo
Add a function to the timer API that allows a caller to traverse a
specified set of timer lists, stopping each timer in each list,
and invoking a callback function.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c   | 39 ++
 lib/librte_timer/rte_timer.h   | 32 
 lib/librte_timer/rte_timer_version.map |  1 +
 3 files changed, 72 insertions(+)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index d761cda..0fa68f7 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -999,6 +999,45 @@ rte_timer_alt_manage(uint32_t timer_data_id,
return 0;
 }
 
+/* Walk pending lists, stopping timers and calling user-specified function */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores,
+  rte_timer_stop_all_cb_t f, void *f_arg)
+{
+   int i;
+   struct priv_timer *priv_timer;
+   uint32_t walk_lcore;
+   struct rte_timer *tim, *next_tim;
+   struct rte_timer_data *timer_data;
+
+   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
+
+   for (i = 0, walk_lcore = walk_lcores[i];
+i < nb_walk_lcores;
+walk_lcore = walk_lcores[++i]) {
+   priv_timer = &timer_data->priv_timer[walk_lcore];
+
+   rte_spinlock_lock(&priv_timer->list_lock);
+
+   for (tim = priv_timer->pending_head.sl_next[0];
+tim != NULL;
+tim = next_tim) {
+   next_tim = tim->sl_next[0];
+
+   /* Call timer_stop with lock held */
+   __rte_timer_stop(tim, 1, timer_data);
+
+   if (f)
+   f(tim, f_arg);
+   }
+
+   rte_spinlock_unlock(&priv_timer->list_lock);
+   }
+
+   return 0;
+}
+
 /* dump statistics about timers */
 static void
 __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f)
diff --git a/lib/librte_timer/rte_timer.h b/lib/librte_timer/rte_timer.h
index 82f5fba..b01bd97 100644
--- a/lib/librte_timer/rte_timer.h
+++ b/lib/librte_timer/rte_timer.h
@@ -500,6 +500,38 @@ rte_timer_alt_manage(uint32_t timer_data_id, unsigned int 
*poll_lcores,
 int n_poll_lcores, rte_timer_alt_manage_cb_t f);
 
 /**
+ * Callback function type for rte_timer_stop_all().
+ */
+typedef void (*rte_timer_stop_all_cb_t)(struct rte_timer *tim, void *arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Walk the pending timer lists for the specified lcore IDs, and for each timer
+ * that is encountered, stop it and call the specified callback function to
+ * process it further.
+ *
+ * @param timer_data_id
+ *   An identifier indicating which instance of timer data should be used for
+ *   this operation.
+ * @param walk_lcores
+ *   An array of lcore ids identifying the timer lists that should be 
processed.
+ * @param nb_walk_lcores
+ *   The size of the walk_lcores array.
+ * @param f
+ *   The callback function which should be called for each timers. Can be NULL.
+ * @param f_arg
+ *   An arbitrary argument that will be passed to f, if it is called.
+ * @return
+ *   - 0: success
+ *   - EINVAL: invalid timer_data_id
+ */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores, rte_timer_stop_all_cb_t f, void *f_arg);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
  *
diff --git a/lib/librte_timer/rte_timer_version.map 
b/lib/librte_timer/rte_timer_version.map
index b3f4b6c..278b2af 100644
--- a/lib/librte_timer/rte_timer_version.map
+++ b/lib/librte_timer/rte_timer_version.map
@@ -33,5 +33,6 @@ EXPERIMENTAL {
rte_timer_alt_stop;
rte_timer_data_alloc;
rte_timer_data_dealloc;
+   rte_timer_stop_all;
rte_timer_subsystem_finalize;
 };
-- 
2.6.4



[dpdk-dev] [PATCH v3 0/2] Timer library changes

2018-12-13 Thread Erik Gabriel Carrillo
This patch series modifies the timer library in such a way that
structures that used to be statically allocated in a process's data
segment are now allocated in shared memory.  As these structures contain
lists of timers, new APIs are introduced that allow a caller to specify
the particular structure instance into which a timer should be inserted
or from which a timer should be removed.  This enables primary and
secondary processes to modify the same timer list, which enables some
multi-process use cases that were not previously possible; e.g. a
secondary process can start a timer whose expiration is detected in a
primary process running a new flavor of timer_manage().

The original library API is mostly unchanged, though implementations are
updated to call into newly added functions with a default structure
instance ID that provides the original behavior.  New functions are
introduced to enable applications to allocate structure instances to
house timer lists, and to reference them with an identifier when
starting and stopping timers, and finally, to manage the timer lists
referenced with an identifier.

My initial performance testing with the "timer_perf_autotest" test shows
no performance regression or improvement, and inspection of the
generated optimized code shows that the extra function call gets inlined
in the functions that now have an extra function call. 

Depends on: https://patches.dpdk.org/patch/48417/

Changes in v3:
 - remove C++ style comment in first patch in series (Stephen)

Changes in v2:
 - split these changes out into their own series
 - version the symbols where the existing ABI was updated, and
   provide alternate implementation with behavior equivalent to original
   behavior. Validated ABI compatibility with validate-abi.sh
 - refactor changes to simplify patches

Erik Gabriel Carrillo (2):
  timer: allow timer management in shared memory
  timer: add function to stop all timers in a list

 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 558 ++---
 lib/librte_timer/rte_timer.h   | 258 ++-
 lib/librte_timer/rte_timer_version.map |  23 ++
 4 files changed, 795 insertions(+), 45 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v3 0/1] New software event timer adapter

2018-12-14 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD [1]. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a service
core in the primary process dequeued them and processed them further.  To
improve performance, this version does away with the ring and lets lcores in
both primary and secondary processes insert timers directly into timer
skiplist data structures; the service core directly accesses the lists as
well, when looking for timers that have expired. (This behavior requires
the patch to the timer library that is referenced below.)

Depends on: https://patches.dpdk.org/project/dpdk/list/?series=2767

[1] https://doc.dpdk.org/guides/prog_guide/event_timer_adapter.html

Changes in v3:
 - Addressed comments from Mattias Ronnblom:
   - remove unnecessary header include
   - remove unnecessary cast in mempool_put() call
   - update alignment of elements of array to avoid false sharing issue

Changes in v2:
 - split this change out into its own patch series

Erik Gabriel Carrillo (1):
  eventdev: add new software event timer adapter

 lib/librte_eventdev/rte_event_timer_adapter.c | 688 +++---
 1 file changed, 276 insertions(+), 412 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v3 1/1] eventdev: add new software event timer adapter

2018-12-14 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a
service core in the primary process dequeued them and processed them
further.  To improve performance, this version does away with the ring
and lets lcores in both primary and secondary processes insert timers
directly into timer skiplist data structures; the service core directly
accesses the lists as well, when looking for timers that have expired.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 688 +++---
 1 file changed, 276 insertions(+), 412 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 79070d4..029a45a 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -34,7 +35,7 @@ static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
-static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+static const struct rte_event_timer_adapter_ops swtim_ops;
 
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
@@ -211,7 +212,7 @@ rte_event_timer_adapter_create_ext(
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
@@ -334,7 +335,7 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
@@ -491,6 +492,7 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
}
 
*nb_events_inv = 0;
+
*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 &events[tail_idx], n);
if (*nb_events_flushed != n && rte_errno == -EINVAL) {
@@ -498,137 +500,125 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
(*nb_events_inv)++;
}
 
+   if (*nb_events_flushed > 0)
+   EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event "
+ "device", *nb_events_flushed);
+
bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
 }
 
 /*
  * Software event timer adapter implementation
  */
-
-struct rte_event_timer_adapter_sw_data {
-   /* List of messages for outstanding timers */
-   TAILQ_HEAD(, msg) msgs_tailq_head;
-   /* Lock to guard tailq and armed count */
-   rte_spinlock_t msgs_tailq_sl;
+struct swtim {
/* Identifier of service executing timer management logic. */
uint32_t service_id;
/* The cycle count at which the adapter should next tick */
uint64_t next_tick_cycles;
-   /* Incremented as the service moves through phases of an iteration */
-   volatile int service_phase;
/* The tick resolution used by adapter instance. May have been
 * adjusted from what user requested
 */
uint64_t timer_tick_ns;
/* Maximum timeout in nanoseconds allowed by adapter instance. */
uint64_t max_tmo_ns;
-   /* Ring containing messages to arm or cancel event timers */
-   struct rte_ring *msg_ring;
-   /* Mempool containing msg objects */
-   struct rte_mempool *msg_pool;
/* Buffered timer expiry events to be enqueued to an event device. */
struct event_buffer buffer;
/* Statistics */
struct rte_event_timer_adapter_stats stats;
-   /* The number of threads currently adding to the message ring */
-   rte_atomic16_t message_producer_count;
+   /* Mempool of timer objects */
+   struct rte_mempool *tim_pool;
+   /* Back pointer for convenience */
+   struct rte_event_timer_adapter *adapter;
+   /* Identifier of timer data instance */
+   uint32_t timer_data_id;
+   /* Track which cores have actually armed a timer */
+   struct {
+   rte_atomic16_t v;
+   } __rte_cache_aligned in_use[RTE_MAX_LCORE];
+   /* Track which cores' timer lists should be polled */
+   unsigned int poll_lcores[RTE_MAX_LCORE];
+   /* The num

[dpdk-dev] [PATCH v4 0/1] New software event timer adapter

2018-12-14 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD [1]. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a service
core in the primary process dequeued them and processed them further.  To
improve performance, this version does away with the ring and lets lcores in
both primary and secondary processes insert timers directly into timer
skiplist data structures; the service core directly accesses the lists as
well, when looking for timers that have expired. (This behavior requires
the patch to the timer library that is referenced below.)

Depends on: https://patches.dpdk.org/project/dpdk/list/?series=2767

[1] https://doc.dpdk.org/guides/prog_guide/event_timer_adapter.html

Changes in v4:
 - Addressed the following comments from Mattias Ronnblom:
   - remove unnecessary header include
   - add missing read barrier in timer cancel function

Changes in v3:
 - Addressed comments from Mattias Ronnblom:
   - remove unnecessary header include
   - remove unnecessary cast in mempool_put() call
   - update alignment of elements of array to avoid false sharing issue

Changes in v2:
 - split this change out into its own patch series

Erik Gabriel Carrillo (1):
  eventdev: add new software event timer adapter

 lib/librte_eventdev/rte_event_timer_adapter.c | 689 +++---
 1 file changed, 277 insertions(+), 412 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v4 1/1] eventdev: add new software event timer adapter

2018-12-14 Thread Erik Gabriel Carrillo
This patch introduces a new version of the event timer adapter software
PMD. In the original design, timer event producer lcores in the primary
and secondary processes enqueued event timers into a ring, and a
service core in the primary process dequeued them and processed them
further.  To improve performance, this version does away with the ring
and lets lcores in both primary and secondary processes insert timers
directly into timer skiplist data structures; the service core directly
accesses the lists as well, when looking for timers that have expired.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 689 +++---
 1 file changed, 277 insertions(+), 412 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 79070d4..3851896 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -34,7 +34,7 @@ static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
-static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+static const struct rte_event_timer_adapter_ops swtim_ops;
 
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
@@ -211,7 +211,7 @@ rte_event_timer_adapter_create_ext(
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
@@ -334,7 +334,7 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
@@ -491,6 +491,7 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
}
 
*nb_events_inv = 0;
+
*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 &events[tail_idx], n);
if (*nb_events_flushed != n && rte_errno == -EINVAL) {
@@ -498,137 +499,125 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
(*nb_events_inv)++;
}
 
+   if (*nb_events_flushed > 0)
+   EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event "
+ "device", *nb_events_flushed);
+
bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
 }
 
 /*
  * Software event timer adapter implementation
  */
-
-struct rte_event_timer_adapter_sw_data {
-   /* List of messages for outstanding timers */
-   TAILQ_HEAD(, msg) msgs_tailq_head;
-   /* Lock to guard tailq and armed count */
-   rte_spinlock_t msgs_tailq_sl;
+struct swtim {
/* Identifier of service executing timer management logic. */
uint32_t service_id;
/* The cycle count at which the adapter should next tick */
uint64_t next_tick_cycles;
-   /* Incremented as the service moves through phases of an iteration */
-   volatile int service_phase;
/* The tick resolution used by adapter instance. May have been
 * adjusted from what user requested
 */
uint64_t timer_tick_ns;
/* Maximum timeout in nanoseconds allowed by adapter instance. */
uint64_t max_tmo_ns;
-   /* Ring containing messages to arm or cancel event timers */
-   struct rte_ring *msg_ring;
-   /* Mempool containing msg objects */
-   struct rte_mempool *msg_pool;
/* Buffered timer expiry events to be enqueued to an event device. */
struct event_buffer buffer;
/* Statistics */
struct rte_event_timer_adapter_stats stats;
-   /* The number of threads currently adding to the message ring */
-   rte_atomic16_t message_producer_count;
+   /* Mempool of timer objects */
+   struct rte_mempool *tim_pool;
+   /* Back pointer for convenience */
+   struct rte_event_timer_adapter *adapter;
+   /* Identifier of timer data instance */
+   uint32_t timer_data_id;
+   /* Track which cores have actually armed a timer */
+   struct {
+   rte_atomic16_t v;
+   } __rte_cache_aligned in_use[RTE_MAX_LCORE];
+   /* Track which cores' timer lists should be polled */
+   unsigned int poll_lcores[RTE_MAX_LCORE];
+   /* The number of lists that should be polled */
+   int n_poll_lcores;
+   /* Lock to atomically access the above two variables */
+   rte_spinlock_t poll_lc

[dpdk-dev] [PATCH v2] timer: fix race condition

2018-12-19 Thread Erik Gabriel Carrillo
rte_timer_manage() adds expired timers to a "run list", and walks the
list, transitioning each timer from the PENDING to the RUNNING state.
If another lcore resets or stops the timer at precisely this
moment, the timer state would instead be set to CONFIG by that other
lcore, which would cause timer_manage() to skip over it. This is
expected behavior.

However, if a timer expires quickly enough, there exists the
following race condition that causes the timer_manage() routine to
misinterpret a timer in CONFIG state, resulting in lost timers:

- Thread A:
  - starts a timer with rte_timer_reset()
  - the timer is moved to CONFIG state
  - the spinlock associated with the appropriate skiplist is acquired
  - timer is inserted into the skiplist
  - the spinlock is released
- Thread B:
  - executes rte_timer_manage()
  - find above timer as expired, add it to run list
  - walk run list, see above timer still in CONFIG state, unlink it from
run list and continue on
- Thread A:
  - move timer to PENDING state
  - return from rte_timer_reset()
  - timer is now in PENDING state, but not actually linked into a
pending list or a run list and will never get processed further
by rte_timer_manage()

This commit fixes this race condition by only releasing the spinlock
after the timer state has been transitioned from CONFIG to PENDING,
which prevents rte_timer_manage() from seeing an incorrect state.

Fixes: 9b15ba895b9f ("timer: use a skip list")
Signed-off-by: Erik Gabriel Carrillo 
Reviewed-by: Gavin Hu 
---
v2:
 - Add more detail to commit message (Gavin Hu)

 lib/librte_timer/rte_timer.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 590488c..30c7b0a 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -241,24 +241,17 @@ timer_get_prev_entries_for_node(struct rte_timer *tim, 
unsigned tim_lcore,
}
 }
 
-/*
- * add in list, lock if needed
+/* call with lock held as necessary
+ * add in list
  * timer must be in config state
  * timer must not be in a list
  */
 static void
-timer_add(struct rte_timer *tim, unsigned tim_lcore, int local_is_locked)
+timer_add(struct rte_timer *tim, unsigned int tim_lcore)
 {
-   unsigned lcore_id = rte_lcore_id();
unsigned lvl;
struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
 
-   /* if timer needs to be scheduled on another core, we need to
-* lock the list; if it is on local core, we need to lock if
-* we are not called from rte_timer_manage() */
-   if (tim_lcore != lcore_id || !local_is_locked)
-   rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
-
/* find where exactly this element goes in the list of elements
 * for each depth. */
timer_get_prev_entries(tim->expire, tim_lcore, prev);
@@ -282,9 +275,6 @@ timer_add(struct rte_timer *tim, unsigned tim_lcore, int 
local_is_locked)
 * NOTE: this is not atomic on 32-bit*/
priv_timer[tim_lcore].pending_head.expire = priv_timer[tim_lcore].\
pending_head.sl_next[0]->expire;
-
-   if (tim_lcore != lcore_id || !local_is_locked)
-   rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
 }
 
 /*
@@ -379,8 +369,15 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
tim->f = fct;
tim->arg = arg;
 
+   /* if timer needs to be scheduled on another core, we need to
+* lock the destination list; if it is on local core, we need to lock if
+* we are not called from rte_timer_manage()
+*/
+   if (tim_lcore != lcore_id || !local_is_locked)
+   rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
+
__TIMER_STAT_ADD(pending, 1);
-   timer_add(tim, tim_lcore, local_is_locked);
+   timer_add(tim, tim_lcore);
 
/* update state: as we are in CONFIG state, only us can modify
 * the state so we don't need to use cmpset() here */
@@ -389,6 +386,9 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
status.owner = (int16_t)tim_lcore;
tim->status.u32 = status.u32;
 
+   if (tim_lcore != lcore_id || !local_is_locked)
+   rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
+
return 0;
 }
 
-- 
2.6.4



[dpdk-dev] [PATCH 1/1] timer: fix race condition

2018-11-29 Thread Erik Gabriel Carrillo
rte_timer_manage() adds expired timers to a "run list", and walks the
list, transitioning each timer from the PENDING to the RUNNING state.
If another lcore resets or stops the timer at precisely this
moment, the timer state would instead be set to CONFIG by that other
lcore, which would cause timer_manage() to skip over it. This is
expected behavior.

However, if a timer expires quickly enough, there exists the
following race condition that causes the timer_manage() routine to
misinterpret a timer in CONFIG state, resulting in lost timers:

- Thread A:
  - starts a timer with rte_timer_reset()
  - the timer is moved to CONFIG state
  - the spinlock associated with the appropriate skiplist is acquired
  - timer is inserted into the skiplist
  - the spinlock is released
- Thread B:
  - executes rte_timer_manage()
  - find above timer as expired, add it to run list
  - walk run list, see above timer still in CONFIG state, unlink it from
run list and continue on
- Thread A:
  - move timer to PENDING state
  - return from rte_timer_reset()
  - timer is now in PENDING state, but not actually linked into skiplist
and will never get processed further by rte_timer_manage()

This commit fixes this race condition by only releasing the spinlock
after the timer state has been transitioned from CONFIG to PENDING,
which prevents rte_timer_manage() from seeing an incorrect state.

Fixes: 9b15ba895b9f ("timer: use a skip list")
Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 590488c..30c7b0a 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -241,24 +241,17 @@ timer_get_prev_entries_for_node(struct rte_timer *tim, 
unsigned tim_lcore,
}
 }
 
-/*
- * add in list, lock if needed
+/* call with lock held as necessary
+ * add in list
  * timer must be in config state
  * timer must not be in a list
  */
 static void
-timer_add(struct rte_timer *tim, unsigned tim_lcore, int local_is_locked)
+timer_add(struct rte_timer *tim, unsigned int tim_lcore)
 {
-   unsigned lcore_id = rte_lcore_id();
unsigned lvl;
struct rte_timer *prev[MAX_SKIPLIST_DEPTH+1];
 
-   /* if timer needs to be scheduled on another core, we need to
-* lock the list; if it is on local core, we need to lock if
-* we are not called from rte_timer_manage() */
-   if (tim_lcore != lcore_id || !local_is_locked)
-   rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
-
/* find where exactly this element goes in the list of elements
 * for each depth. */
timer_get_prev_entries(tim->expire, tim_lcore, prev);
@@ -282,9 +275,6 @@ timer_add(struct rte_timer *tim, unsigned tim_lcore, int 
local_is_locked)
 * NOTE: this is not atomic on 32-bit*/
priv_timer[tim_lcore].pending_head.expire = priv_timer[tim_lcore].\
pending_head.sl_next[0]->expire;
-
-   if (tim_lcore != lcore_id || !local_is_locked)
-   rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
 }
 
 /*
@@ -379,8 +369,15 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
tim->f = fct;
tim->arg = arg;
 
+   /* if timer needs to be scheduled on another core, we need to
+* lock the destination list; if it is on local core, we need to lock if
+* we are not called from rte_timer_manage()
+*/
+   if (tim_lcore != lcore_id || !local_is_locked)
+   rte_spinlock_lock(&priv_timer[tim_lcore].list_lock);
+
__TIMER_STAT_ADD(pending, 1);
-   timer_add(tim, tim_lcore, local_is_locked);
+   timer_add(tim, tim_lcore);
 
/* update state: as we are in CONFIG state, only us can modify
 * the state so we don't need to use cmpset() here */
@@ -389,6 +386,9 @@ __rte_timer_reset(struct rte_timer *tim, uint64_t expire,
status.owner = (int16_t)tim_lcore;
tim->status.u32 = status.u32;
 
+   if (tim_lcore != lcore_id || !local_is_locked)
+   rte_spinlock_unlock(&priv_timer[tim_lcore].list_lock);
+
return 0;
 }
 
-- 
2.6.4



[dpdk-dev] [PATCH 1/1] app/eventdev: detect deadlock for timer event producer

2018-11-29 Thread Erik Gabriel Carrillo
If timer events get dropped for some reason, the thread that launched
producer and worker cores will never exit, because the deadlock check
doesn't currently apply to the event timer adapter case. This commit
fixes this.

Signed-off-by: Erik Gabriel Carrillo 
---
 app/test-eventdev/test_perf_common.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/test-eventdev/test_perf_common.c 
b/app/test-eventdev/test_perf_common.c
index 8618775..f99a6a6 100644
--- a/app/test-eventdev/test_perf_common.c
+++ b/app/test-eventdev/test_perf_common.c
@@ -327,7 +327,8 @@ perf_launch_lcores(struct evt_test *test, struct 
evt_options *opt,
}
 
if (new_cycles - dead_lock_cycles > dead_lock_sample &&
-   opt->prod_type == EVT_PROD_TYPE_SYNT) {
+   (opt->prod_type == EVT_PROD_TYPE_SYNT ||
+opt->prod_type == EVT_PROD_TYPE_EVENT_TIMER_ADPTR)) {
remaining = t->outstand_pkts - processed_pkts(t);
if (dead_lock_remaining == remaining) {
rte_event_dev_dump(opt->dev_id, stdout);
-- 
2.6.4



[dpdk-dev] [PATCH] eventdev: remove redundant timer adapter function prototypes

2018-11-29 Thread Erik Gabriel Carrillo
Fixes: a6562f6d6f8e ("eventdev: introduce event timer adapter")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.h | 57 +--
 1 file changed, 2 insertions(+), 55 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
index d4ea6f1..db98dec 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -461,61 +461,8 @@ rte_event_timer_adapter_stats_get(struct 
rte_event_timer_adapter *adapter,
  *   - 0: Successfully reset;
  *   - <0: Failure; error code returned.
  */
-int __rte_experimental rte_event_timer_adapter_stats_reset(
-   struct rte_event_timer_adapter *adapter);
-
-/**
- * Retrieve the service ID of the event timer adapter. If the adapter doesn't
- * use an rte_service function, this function returns -ESRCH.
- *
- * @param adapter
- *   A pointer to an event timer adapter.
- *
- * @param [out] service_id
- *   A pointer to a uint32_t, to be filled in with the service id.
- *
- * @return
- *   - 0: Success
- *   - <0: Error code on failure, if the event dev doesn't use a rte_service
- *   function, this function returns -ESRCH.
- */
-int
-rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
-  uint32_t *service_id);
-
-/**
- * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
- *
- * Retrieve statistics for an event timer adapter instance.
- *
- * @param adapter
- *   A pointer to an event timer adapter structure.
- * @param[out] stats
- *   A pointer to a structure to fill with statistics.
- *
- * @return
- *   - 0: Successfully retrieved.
- *   - <0: Failure; error code returned.
- */
-int rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
-   struct rte_event_timer_adapter_stats *stats);
-
-/**
- * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
- *
- * Reset statistics for an event timer adapter instance.
- *
- * @param adapter
- *   A pointer to an event timer adapter structure.
- *
- * @return
- *   - 0: Successfully reset;
- *   - <0: Failure; error code returned.
- */
-int rte_event_timer_adapter_stats_reset(
-   struct rte_event_timer_adapter *adapter);
+int __rte_experimental
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter);
 
 /**
  * @warning
-- 
2.6.4



[dpdk-dev] [PATCH 1/3] timer: allow timer management in shared memory

2018-11-29 Thread Erik Gabriel Carrillo
Currently, the timer library uses a per-process table of structures to
manage skiplists of timers presumably because timers contain arbitrary
function pointers whose value may not resolve properly in other
processes.

However, if the same callback is used handle all timers, and that
callback is only invoked in one process, then it woud be safe to allow
the data structures to be allocated in shared memory, and to allow
secondary processes to modify the timer lists.  This would let timers be
used in more multi-process scenarios.

The library's global variables are wrapped with a struct, and an array
of these structures is created in shared memory.  The original APIs
are updated to reference the zeroth entry in the array. This maintains
the original behavior for both primary and secondary processes since
the set intersection of their coremasks should be empty [1].  New APIs
are introduced to enable the allocation/deallocation of other entries
in the array.

New variants of the APIs used to start and stop timers are introduced;
they allow a caller to specify which array entry should be used to
locate the timer list to insert into or delete from.

Finally, a new variant of rte_timer_manage() is introduced, which
allows a caller to specify which array entry should be used to locate
the timer lists to process; it can also process multiple timer lists per
invocation.

[1] 
https://doc.dpdk.org/guides/prog_guide/multi_proc_support.html#multi-process-limitations

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 526 +++--
 lib/librte_timer/rte_timer.h   | 168 ++-
 lib/librte_timer/rte_timer_version.map |  21 +-
 4 files changed, 614 insertions(+), 102 deletions(-)

diff --git a/lib/librte_timer/Makefile b/lib/librte_timer/Makefile
index 4ebd528..8ec63f4 100644
--- a/lib/librte_timer/Makefile
+++ b/lib/librte_timer/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 # library name
 LIB = librte_timer.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 LDLIBS += -lrte_eal
 
diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 30c7b0a..a76be8b 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,23 +22,27 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include "rte_timer.h"
 
-LIST_HEAD(rte_timer_list, rte_timer);
-
+/**
+ * Per-lcore info for timers.
+ */
 struct priv_timer {
-   struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
+   struct rte_timer pending_head;  /**< dummy timer to head up list */
rte_spinlock_t list_lock;   /**< lock to protect list access */
 
/** per-core variable that true if a timer was updated on this
-*  core since last reset of the variable */
+*  core since last reset of the variable
+*/
int updated;
 
/** track the current depth of the skiplist */
-   unsigned curr_skiplist_depth;
+   unsigned int curr_skiplist_depth;
 
-   unsigned prev_lcore;  /**< used for lcore round robin */
+   unsigned int prev_lcore;/**< used for lcore round robin */
 
/** running timer on this lcore now */
struct rte_timer *running_tim;
@@ -48,33 +53,140 @@ struct priv_timer {
 #endif
 } __rte_cache_aligned;
 
-/** per-lcore private info for timers */
-static struct priv_timer priv_timer[RTE_MAX_LCORE];
+#define FL_ALLOCATED   (1 << 0)
+struct rte_timer_data {
+   struct priv_timer priv_timer[RTE_MAX_LCORE];
+   uint8_t internal_flags;
+};
+
+#define RTE_MAX_DATA_ELS 64
+static struct rte_timer_data *rte_timer_data_arr;
+static uint32_t default_data_id;  // id set to zero automatically
+static uint32_t rte_timer_subsystem_initialized;
 
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
-#define __TIMER_STAT_ADD(name, n) do { \
+#define __TIMER_STAT_ADD(data, name, n) do {   \
unsigned __lcore_id = rte_lcore_id();   \
if (__lcore_id < RTE_MAX_LCORE) \
-   priv_timer[__lcore_id].stats.name += (n);   \
+   data->priv_timer[__lcore_id].stats.name += (n); \
} while(0)
 #else
-#define __TIMER_STAT_ADD(name, n) do {} while(0)
+#define __TIMER_STAT_ADD(data, name, n) do {} while (0)
 #endif
 
-/* Init the timer library. */
-void
+static inline int
+timer_data_valid(uint32_t id)
+{
+   return !!(rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
+}
+
+/* validate ID and retrieve timer data pointer, or return error value */
+#define TIMER_DATA_VALID_GET_OR_ERR_RET(i

[dpdk-dev] [PATCH 2/3] timer: add function to stop all timers in a list

2018-11-29 Thread Erik Gabriel Carrillo
Add a function to the timer API that allows a caller to traverse a
specified set of timer lists, stopping each timer in each list,
and invoking a callback function.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c   | 81 +++---
 lib/librte_timer/rte_timer.h   | 32 ++
 lib/librte_timer/rte_timer_version.map |  1 +
 3 files changed, 97 insertions(+), 17 deletions(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index a76be8b..1eaf755 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -559,39 +559,30 @@ rte_timer_reset_sync(struct rte_timer *tim, uint64_t 
ticks,
rte_pause();
 }
 
-/* Stop the timer associated with the timer handle tim */
-int
-rte_timer_stop(struct rte_timer *tim)
-{
-   return rte_timer_alt_stop(default_data_id, tim);
-}
-
-int __rte_experimental
-rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim)
+static int
+__rte_timer_stop(struct rte_timer *tim, int local_is_locked,
+struct rte_timer_data *data)
 {
union rte_timer_status prev_status, status;
unsigned lcore_id = rte_lcore_id();
int ret;
-   struct rte_timer_data *timer_data;
-
-   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
 
/* wait that the timer is in correct status before update,
 * and mark it as being configured */
-   ret = timer_set_config_state(tim, &prev_status, timer_data);
+   ret = timer_set_config_state(tim, &prev_status, data);
if (ret < 0)
return -1;
 
-   __TIMER_STAT_ADD(timer_data, stop, 1);
+   __TIMER_STAT_ADD(data, stop, 1);
if (prev_status.state == RTE_TIMER_RUNNING &&
lcore_id < RTE_MAX_LCORE) {
-   timer_data->priv_timer[lcore_id].updated = 1;
+   data->priv_timer[lcore_id].updated = 1;
}
 
/* remove it from list */
if (prev_status.state == RTE_TIMER_PENDING) {
-   timer_del(tim, prev_status, 0, timer_data);
-   __TIMER_STAT_ADD(timer_data, pending, -1);
+   timer_del(tim, prev_status, local_is_locked, data);
+   __TIMER_STAT_ADD(data, pending, -1);
}
 
/* mark timer as stopped */
@@ -603,6 +594,23 @@ rte_timer_alt_stop(uint32_t timer_data_id, struct 
rte_timer *tim)
return 0;
 }
 
+/* Stop the timer associated with the timer handle tim */
+int
+rte_timer_stop(struct rte_timer *tim)
+{
+   return rte_timer_alt_stop(default_data_id, tim);
+}
+
+int __rte_experimental
+rte_timer_alt_stop(uint32_t timer_data_id, struct rte_timer *tim)
+{
+   struct rte_timer_data *timer_data;
+
+   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
+
+   return __rte_timer_stop(tim, 0, timer_data);
+}
+
 /* loop until rte_timer_stop() succeed */
 void
 rte_timer_stop_sync(struct rte_timer *tim)
@@ -912,6 +920,45 @@ rte_timer_alt_manage(uint32_t timer_data_id,
return 0;
 }
 
+/* Walk pending lists, stopping timers and calling user-specified function */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores,
+  rte_timer_stop_all_cb_t f, void *f_arg)
+{
+   int i;
+   struct priv_timer *priv_timer;
+   uint32_t walk_lcore;
+   struct rte_timer *tim, *next_tim;
+   struct rte_timer_data *timer_data;
+
+   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
+
+   for (i = 0, walk_lcore = walk_lcores[i];
+i < nb_walk_lcores;
+walk_lcore = walk_lcores[++i]) {
+   priv_timer = &timer_data->priv_timer[walk_lcore];
+
+   rte_spinlock_lock(&priv_timer->list_lock);
+
+   for (tim = priv_timer->pending_head.sl_next[0];
+tim != NULL;
+tim = next_tim) {
+   next_tim = tim->sl_next[0];
+
+   /* Call timer_stop with lock held */
+   __rte_timer_stop(tim, 1, timer_data);
+
+   if (f)
+   f(tim, f_arg);
+   }
+
+   rte_spinlock_unlock(&priv_timer->list_lock);
+   }
+
+   return 0;
+}
+
 /* dump statistics about timers */
 void rte_timer_dump_stats(FILE *f)
 {
diff --git a/lib/librte_timer/rte_timer.h b/lib/librte_timer/rte_timer.h
index 9daa334..27b1ebd 100644
--- a/lib/librte_timer/rte_timer.h
+++ b/lib/librte_timer/rte_timer.h
@@ -446,6 +446,38 @@ rte_timer_alt_manage(uint32_t timer_data_id, unsigned int 
*poll_lcores,
 int n_poll_lcores, rte_timer_alt_manage_cb_t f);
 
 /**
+ * Callback function type for rte_timer_stop_all().
+ */
+typedef void (*rte_timer_stop_all_cb_t)(struct rte_timer *tim, void *arg);
+
+/**
+ * @warn

[dpdk-dev] [PATCH 3/3] eventdev: add new software event timer adapter

2018-11-29 Thread Erik Gabriel Carrillo
This commit updates the implementation of the software event timer
adapter.  The original version used rings to let producer cores (and
secondary processes) send timers to a service core, which would then arm
or cancel the timers, depending on what the application had requested.
The ring can be a bottleneck, so we replace the original implementation
with one that uses new APIs introduced in the timer library.  The new
APIs allow the underlying timer skiplists to be allocated in shared
memory, which allows the producer cores in both primary and secondary
processes to install timers directly into the lists, obviating the need
for a ring.  Each producer core also gets a unique timer list to insert
timers into, so no contention occurs there. The adapter's service
function can utilize a new flavor of rte_timer_manage() that can traverse
multiple timer lists, and also accepts a callback function.  The callback
function is only called from the primary process, since that's where the
service runs, and the callback is the same for all timers - it is defined
to enqueue a timer expiry event in the event device.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 687 +++---
 1 file changed, 275 insertions(+), 412 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 79070d4..9c528cb 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -19,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -34,7 +36,7 @@ static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
-static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+static const struct rte_event_timer_adapter_ops swtim_ops;
 
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
@@ -211,7 +213,7 @@ rte_event_timer_adapter_create_ext(
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
@@ -334,7 +336,7 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
 * implementation.
 */
if (adapter->ops == NULL)
-   adapter->ops = &sw_event_adapter_timer_ops;
+   adapter->ops = &swtim_ops;
 
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
@@ -491,6 +493,7 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
}
 
*nb_events_inv = 0;
+
*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 &events[tail_idx], n);
if (*nb_events_flushed != n && rte_errno == -EINVAL) {
@@ -498,137 +501,123 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
(*nb_events_inv)++;
}
 
+   if (*nb_events_flushed > 0)
+   EVTIM_BUF_LOG_DBG("enqueued %"PRIu16" timer events to event "
+ "device", *nb_events_flushed);
+
bufp->tail = bufp->tail + *nb_events_flushed + *nb_events_inv;
 }
 
 /*
  * Software event timer adapter implementation
  */
-
-struct rte_event_timer_adapter_sw_data {
-   /* List of messages for outstanding timers */
-   TAILQ_HEAD(, msg) msgs_tailq_head;
-   /* Lock to guard tailq and armed count */
-   rte_spinlock_t msgs_tailq_sl;
+struct swtim {
/* Identifier of service executing timer management logic. */
uint32_t service_id;
/* The cycle count at which the adapter should next tick */
uint64_t next_tick_cycles;
-   /* Incremented as the service moves through phases of an iteration */
-   volatile int service_phase;
/* The tick resolution used by adapter instance. May have been
 * adjusted from what user requested
 */
uint64_t timer_tick_ns;
/* Maximum timeout in nanoseconds allowed by adapter instance. */
uint64_t max_tmo_ns;
-   /* Ring containing messages to arm or cancel event timers */
-   struct rte_ring *msg_ring;
-   /* Mempool containing msg objects */
-   struct rte_mempool *msg_pool;
/* Buffered timer expiry events to be enqueued to an event device. */
struct event_buffer buffer;
/* Statistics */
struct rte_event_timer_adapter_stats stats;
-   /* The number of 

[dpdk-dev] [PATCH 0/3] new software event timer adapter

2018-11-29 Thread Erik Gabriel Carrillo
This patch series introduces a new version of the event timer 
adapter software PMD [1].  In the original design, timer event producer
lcores in the primary and secondary processes enqueued event timers
into a ring, and a service core in the primary process dequeued them
and processed them further.  To improve performance, this version does
away with the ring and lets the lcores in both primary and secondary
processes insert timers into directly into the timer skiplist data
structures; the service core directly accesses the lists as well. 
To achieve this, however, modifications to the timer library [2] are
required to enable the timer skiplists to be created and accessed in
shared memory.  New APIs are introduced in the timer library to enable
selecting from multiple instances of the timer skiplists. Instances of
the event timer adapter, as well as the original APIs of the timer
library, can then each access distinct timer lists.

Future versions of this series will hopefully improve the names
used for the data structures and APIs in the timer library.

This series depends on the following patch:
https://patches.dpdk.org/patch/48417/

[1] https://doc.dpdk.org/guides/prog_guide/event_timer_adapter.html
[2] https://doc.dpdk.org/guides/prog_guide/timer_lib.html

Erik Gabriel Carrillo (3):
  timer: allow timer management in shared memory
  timer: add function to stop all timers in a list
  eventdev: add new software event timer adapter

 lib/librte_eventdev/rte_event_timer_adapter.c | 687 +++---
 lib/librte_timer/Makefile |   1 +
 lib/librte_timer/rte_timer.c  | 579 ++
 lib/librte_timer/rte_timer.h  | 200 +++-
 lib/librte_timer/rte_timer_version.map|  22 +-
 5 files changed, 972 insertions(+), 517 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v1 1/1] service: Add service lcore attr APIs

2018-05-04 Thread Erik Gabriel Carrillo
Add a counter that gets bumped each time the service runner loop goes
around, and APIs to query and reset the attribute values.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eal/common/include/rte_service.h | 30 
 lib/librte_eal/common/rte_service.c | 43 -
 lib/librte_eal/rte_eal_version.map  |  2 +
 test/test/test_service_cores.c  | 73 +
 4 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/lib/librte_eal/common/include/rte_service.h 
b/lib/librte_eal/common/include/rte_service.h
index aea4d91..05d51a2 100644
--- a/lib/librte_eal/common/include/rte_service.h
+++ b/lib/librte_eal/common/include/rte_service.h
@@ -363,6 +363,36 @@ int32_t rte_service_attr_get(uint32_t id, uint32_t attr_id,
  */
 int32_t rte_service_attr_reset_all(uint32_t id);
 
+/**
+ * Returns the number of times the service runner has looped.
+ */
+#define RTE_SERVICE_LCORE_ATTR_LOOPS 0
+
+/**
+ * Get an attribute from a service core.
+ *
+ * @param lcore Id of the service core.
+ * @param attr_id Id of the attribute to be retrieved.
+ * @param [out] attr_value Pointer to storage in which to write retrieved 
value.
+ * @retval 0 Success, the attribute value has been written to *attr_value*.
+ * -EINVAL Invalid lcore, attr_id or attr_value was NULL.
+ * -ENOTSUP lcore is not a service core.
+ */
+int32_t __rte_experimental
+rte_service_lcore_attr_get(uint32_t lcore, uint32_t attr_id,
+  uint64_t *attr_value);
+
+/**
+ * Reset all attribute values of a service core.
+ *
+ * @param lcore The service core to reset all the statistics of
+ * @retval 0 Successfully reset attributes
+ * -EINVAL Invalid service id provided
+ * -ENOTSUP lcore is not a service core.
+ */
+int32_t __rte_experimental
+rte_service_lcore_attr_reset_all(uint32_t lcore);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/common/rte_service.c 
b/lib/librte_eal/common/rte_service.c
index 73507aa..fa15f66 100644
--- a/lib/librte_eal/common/rte_service.c
+++ b/lib/librte_eal/common/rte_service.c
@@ -61,7 +61,7 @@ struct core_state {
uint8_t runstate; /* running or stopped */
uint8_t is_service_core; /* set if core is currently a service core */
 
-   /* extreme statistics */
+   uint64_t loops;
uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
 } __rte_cache_aligned;
 
@@ -422,6 +422,8 @@ rte_service_runner_func(void *arg)
service_run(i, cs, service_mask);
}
 
+   cs->loops++;
+
rte_smp_rmb();
}
 
@@ -729,6 +731,28 @@ rte_service_attr_get(uint32_t id, uint32_t attr_id, 
uint32_t *attr_value)
}
 }
 
+int32_t __rte_experimental
+rte_service_lcore_attr_get(uint32_t lcore, uint32_t attr_id,
+  uint64_t *attr_value)
+{
+   struct core_state *cs;
+
+   if (lcore >= RTE_MAX_LCORE || !attr_value)
+   return -EINVAL;
+
+   cs = &lcore_states[lcore];
+   if (!cs->is_service_core)
+   return -ENOTSUP;
+
+   switch (attr_id) {
+   case RTE_SERVICE_LCORE_ATTR_LOOPS:
+   *attr_value = cs->loops;
+   return 0;
+   default:
+   return -EINVAL;
+   }
+}
+
 static void
 rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,
 uint64_t all_cycles, uint32_t reset)
@@ -764,6 +788,23 @@ rte_service_attr_reset_all(uint32_t id)
return 0;
 }
 
+int32_t __rte_experimental
+rte_service_lcore_attr_reset_all(uint32_t lcore)
+{
+   struct core_state *cs;
+
+   if (lcore >= RTE_MAX_LCORE)
+   return -EINVAL;
+
+   cs = &lcore_states[lcore];
+   if (!cs->is_service_core)
+   return -ENOTSUP;
+
+   cs->loops = 0;
+
+   return 0;
+}
+
 static void
 service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)
 {
diff --git a/lib/librte_eal/rte_eal_version.map 
b/lib/librte_eal/rte_eal_version.map
index 8597239..5af7233 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -297,6 +297,8 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+   rte_service_lcore_attr_get;
+   rte_service_lcore_attr_reset_all;
rte_socket_count;
rte_socket_id_by_idx;
rte_vfio_dma_map;
diff --git a/test/test/test_service_cores.c b/test/test/test_service_cores.c
index 86b4073..9f21d59 100644
--- a/test/test/test_service_cores.c
+++ b/test/test/test_service_cores.c
@@ -325,6 +325,78 @@ service_attr_get(void)
return unregister_all();
 }
 
+/* verify service lcore attr get */
+static int
+service_lcore_attr_get(void)
+{
+   /* ensure all services unregistered so cycle counts are zero */
+   unregister_all();
+
+   struct rte_service_spec service;
+   memset(&service, 

[dpdk-dev] [PATCH v1 0/1] Add service lcore attributes API

2018-05-04 Thread Erik Gabriel Carrillo
This patch proposes the addition of an API which allows an application to
query the attributes of a service lcore.  It adds one such new attribute,
named "loops", which is a counter that tracks the number of times the service
core has looped in the service runner function (the driver function that
invokes services mapped to a service core).  This is useful to applications
that desire a "liveness" check to make sure a service core is not stuck.

Erik Gabriel Carrillo (1):
  service: Add service lcore attr APIs

 lib/librte_eal/common/include/rte_service.h | 30 
 lib/librte_eal/common/rte_service.c | 43 -
 lib/librte_eal/rte_eal_version.map  |  2 +
 test/test/test_service_cores.c  | 73 +
 4 files changed, 147 insertions(+), 1 deletion(-)

-- 
2.6.4



[dpdk-dev] [PATCH v1 1/1] test: fix build with GCC 4.8.5

2018-05-04 Thread Erik Gabriel Carrillo
Build errors occur on CentOS 7 with GCC 4.8.5 20150623 in the
event_timer_adapter_test autotest; the
-Werror=missing-field-initializers option causes the compiler to emit
messages like "error: missing initializer for field ‘priority’ of
‘struct ’" in several places.

Add -Wno-missing-field-initializers to the test's CFLAGS to allow the
current syntax if we are using GCC 5.0 or lower.

Signed-off-by: Erik Gabriel Carrillo 
---
 test/test/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/test/Makefile b/test/test/Makefile
index 2630ab4..2011857 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -211,6 +211,7 @@ CFLAGS_test_memcpy_perf.o += -fno-var-tracking-assignments
 # designated initializers.
 ifeq ($(shell test $(GCC_VERSION) -le 50 && echo 1), 1)
 CFLAGS_test_eventdev_sw.o += -Wno-missing-field-initializers
+CFLAGS_test_event_timer_adapter.o += -Wno-missing-field-initializers
 endif
 endif
 endif
-- 
2.6.4



[dpdk-dev] [PATCH v2 1/1] test: fix build with GCC 4.8.5

2018-05-07 Thread Erik Gabriel Carrillo
Build errors occur on CentOS 7 with GCC 4.8.5 20150623 in the
event_timer_adapter_test autotest; the
-Werror=missing-field-initializers option causes the compiler to emit
messages like "error: missing initializer for field ‘priority’ of
‘struct ’" in several places.

Add -Wno-missing-field-initializers to the test's CFLAGS to allow the
current syntax if we are using GCC 5.0 or lower.

Fixes: d1f3385d0076 ("test: add event timer adapter auto-test")

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---

v2:
- Add the 'Fixes' tag. (Jerin)

 test/test/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/test/test/Makefile b/test/test/Makefile
index 2630ab4..2011857 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -211,6 +211,7 @@ CFLAGS_test_memcpy_perf.o += -fno-var-tracking-assignments
 # designated initializers.
 ifeq ($(shell test $(GCC_VERSION) -le 50 && echo 1), 1)
 CFLAGS_test_eventdev_sw.o += -Wno-missing-field-initializers
+CFLAGS_test_event_timer_adapter.o += -Wno-missing-field-initializers
 endif
 endif
 endif
-- 
2.6.4



[dpdk-dev] [PATCH v2 1/1] service: Add service lcore attr APIs

2018-05-09 Thread Erik Gabriel Carrillo
Add APIs that allow an application to query and reset the attributes of
a service lcore.  Add one such new attribute, "loops", which is a
counter that tracks the number of times the service core has looped in
the service runner function.  This is useful to applications that desire
a "liveness" check to make sure a service core is not stuck.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Harry van Haaren 
---
v2:
 - Update doxygen comments to indicate that APIs are experimental
 - Move cover letter description of patch to commit message (Harry)

 lib/librte_eal/common/include/rte_service.h | 36 ++
 lib/librte_eal/common/rte_service.c | 43 -
 lib/librte_eal/rte_eal_version.map  |  2 +
 test/test/test_service_cores.c  | 73 +
 4 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/lib/librte_eal/common/include/rte_service.h 
b/lib/librte_eal/common/include/rte_service.h
index aea4d91..ba2c3cd 100644
--- a/lib/librte_eal/common/include/rte_service.h
+++ b/lib/librte_eal/common/include/rte_service.h
@@ -363,6 +363,42 @@ int32_t rte_service_attr_get(uint32_t id, uint32_t attr_id,
  */
 int32_t rte_service_attr_reset_all(uint32_t id);
 
+/**
+ * Returns the number of times the service runner has looped.
+ */
+#define RTE_SERVICE_LCORE_ATTR_LOOPS 0
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Get an attribute from a service core.
+ *
+ * @param lcore Id of the service core.
+ * @param attr_id Id of the attribute to be retrieved.
+ * @param [out] attr_value Pointer to storage in which to write retrieved 
value.
+ * @retval 0 Success, the attribute value has been written to *attr_value*.
+ * -EINVAL Invalid lcore, attr_id or attr_value was NULL.
+ * -ENOTSUP lcore is not a service core.
+ */
+int32_t __rte_experimental
+rte_service_lcore_attr_get(uint32_t lcore, uint32_t attr_id,
+  uint64_t *attr_value);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Reset all attribute values of a service core.
+ *
+ * @param lcore The service core to reset all the statistics of
+ * @retval 0 Successfully reset attributes
+ * -EINVAL Invalid service id provided
+ * -ENOTSUP lcore is not a service core.
+ */
+int32_t __rte_experimental
+rte_service_lcore_attr_reset_all(uint32_t lcore);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/common/rte_service.c 
b/lib/librte_eal/common/rte_service.c
index 73507aa..fa15f66 100644
--- a/lib/librte_eal/common/rte_service.c
+++ b/lib/librte_eal/common/rte_service.c
@@ -61,7 +61,7 @@ struct core_state {
uint8_t runstate; /* running or stopped */
uint8_t is_service_core; /* set if core is currently a service core */
 
-   /* extreme statistics */
+   uint64_t loops;
uint64_t calls_per_service[RTE_SERVICE_NUM_MAX];
 } __rte_cache_aligned;
 
@@ -422,6 +422,8 @@ rte_service_runner_func(void *arg)
service_run(i, cs, service_mask);
}
 
+   cs->loops++;
+
rte_smp_rmb();
}
 
@@ -729,6 +731,28 @@ rte_service_attr_get(uint32_t id, uint32_t attr_id, 
uint32_t *attr_value)
}
 }
 
+int32_t __rte_experimental
+rte_service_lcore_attr_get(uint32_t lcore, uint32_t attr_id,
+  uint64_t *attr_value)
+{
+   struct core_state *cs;
+
+   if (lcore >= RTE_MAX_LCORE || !attr_value)
+   return -EINVAL;
+
+   cs = &lcore_states[lcore];
+   if (!cs->is_service_core)
+   return -ENOTSUP;
+
+   switch (attr_id) {
+   case RTE_SERVICE_LCORE_ATTR_LOOPS:
+   *attr_value = cs->loops;
+   return 0;
+   default:
+   return -EINVAL;
+   }
+}
+
 static void
 rte_service_dump_one(FILE *f, struct rte_service_spec_impl *s,
 uint64_t all_cycles, uint32_t reset)
@@ -764,6 +788,23 @@ rte_service_attr_reset_all(uint32_t id)
return 0;
 }
 
+int32_t __rte_experimental
+rte_service_lcore_attr_reset_all(uint32_t lcore)
+{
+   struct core_state *cs;
+
+   if (lcore >= RTE_MAX_LCORE)
+   return -EINVAL;
+
+   cs = &lcore_states[lcore];
+   if (!cs->is_service_core)
+   return -ENOTSUP;
+
+   cs->loops = 0;
+
+   return 0;
+}
+
 static void
 service_dump_calls_per_lcore(FILE *f, uint32_t lcore, uint32_t reset)
 {
diff --git a/lib/librte_eal/rte_eal_version.map 
b/lib/librte_eal/rte_eal_version.map
index 8597239..5af7233 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -297,6 +297,8 @@ EXPERIMENTAL {
rte_mp_request_sync;
rte_mp_request_async;
rte_mp_sendmsg;
+   rte_service_lcore_attr_get;
+   rte_service_lcore_attr_reset_all;
rte_socket_count;
rte_socket_

[dpdk-dev] [PATCH v4 0/2] Timer library changes

2019-03-06 Thread Erik Gabriel Carrillo
This patch series modifies the timer library in such a way that
structures that used to be statically allocated in a process's data
segment are now allocated in shared memory.  As these structures contain
lists of timers, new APIs are introduced that allow a caller to specify
the particular structure instance into which a timer should be inserted
or from which a timer should be removed.  This enables primary and
secondary processes to modify the same timer list, which enables some
multi-process use cases that were not previously possible; e.g. a
secondary process can start a timer whose expiration is detected in a
primary process running a new flavor of timer_manage().

The original library API is mostly unchanged, though implementations are
updated to call into newly added functions with a default structure
instance ID that provides the original behavior.  New functions are
introduced to enable applications to allocate structure instances to
house timer lists, and to reference them with an identifier when
starting and stopping timers, and finally, to manage the timer lists
referenced with an identifier.

My initial performance testing with the "timer_perf_autotest" test shows
no performance regression or improvement, and inspection of the
generated optimized code shows that the extra function call gets inlined
in the functions that now have an extra function call. 

Changes in v4:
 - Updated versioned symbols so that they correspond to the next
   release. Checked ABI compatibility again with validate-abi.sh.

Changes in v3:
 - remove C++ style comment in first patch in series (Stephen)

Changes in v2:
 - split these changes out into their own series
 - version the symbols where the existing ABI was updated, and
   provide alternate implementation with behavior equivalent to original
   behavior. Validated ABI compatibility with validate-abi.sh
 - refactor changes to simplify patches

Erik Gabriel Carrillo (2):
  timer: allow timer management in shared memory
  timer: add function to stop all timers in a list

 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 558 ++---
 lib/librte_timer/rte_timer.h   | 258 ++-
 lib/librte_timer/rte_timer_version.map |  23 ++
 4 files changed, 795 insertions(+), 45 deletions(-)

-- 
2.6.4



[dpdk-dev] [PATCH v4 2/2] timer: add function to stop all timers in a list

2019-03-06 Thread Erik Gabriel Carrillo
Add a function to the timer API that allows a caller to traverse a
specified set of timer lists, stopping each timer in each list,
and invoking a callback function.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c   | 39 ++
 lib/librte_timer/rte_timer.h   | 32 
 lib/librte_timer/rte_timer_version.map |  1 +
 3 files changed, 72 insertions(+)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 2bd49d0..539926f 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -999,6 +999,45 @@ rte_timer_alt_manage(uint32_t timer_data_id,
return 0;
 }
 
+/* Walk pending lists, stopping timers and calling user-specified function */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores,
+  rte_timer_stop_all_cb_t f, void *f_arg)
+{
+   int i;
+   struct priv_timer *priv_timer;
+   uint32_t walk_lcore;
+   struct rte_timer *tim, *next_tim;
+   struct rte_timer_data *timer_data;
+
+   TIMER_DATA_VALID_GET_OR_ERR_RET(timer_data_id, timer_data, -EINVAL);
+
+   for (i = 0, walk_lcore = walk_lcores[i];
+i < nb_walk_lcores;
+walk_lcore = walk_lcores[++i]) {
+   priv_timer = &timer_data->priv_timer[walk_lcore];
+
+   rte_spinlock_lock(&priv_timer->list_lock);
+
+   for (tim = priv_timer->pending_head.sl_next[0];
+tim != NULL;
+tim = next_tim) {
+   next_tim = tim->sl_next[0];
+
+   /* Call timer_stop with lock held */
+   __rte_timer_stop(tim, 1, timer_data);
+
+   if (f)
+   f(tim, f_arg);
+   }
+
+   rte_spinlock_unlock(&priv_timer->list_lock);
+   }
+
+   return 0;
+}
+
 /* dump statistics about timers */
 static void
 __rte_timer_dump_stats(struct rte_timer_data *timer_data __rte_unused, FILE *f)
diff --git a/lib/librte_timer/rte_timer.h b/lib/librte_timer/rte_timer.h
index bee1676..ca8a052 100644
--- a/lib/librte_timer/rte_timer.h
+++ b/lib/librte_timer/rte_timer.h
@@ -500,6 +500,38 @@ rte_timer_alt_manage(uint32_t timer_data_id, unsigned int 
*poll_lcores,
 int n_poll_lcores, rte_timer_alt_manage_cb_t f);
 
 /**
+ * Callback function type for rte_timer_stop_all().
+ */
+typedef void (*rte_timer_stop_all_cb_t)(struct rte_timer *tim, void *arg);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Walk the pending timer lists for the specified lcore IDs, and for each timer
+ * that is encountered, stop it and call the specified callback function to
+ * process it further.
+ *
+ * @param timer_data_id
+ *   An identifier indicating which instance of timer data should be used for
+ *   this operation.
+ * @param walk_lcores
+ *   An array of lcore ids identifying the timer lists that should be 
processed.
+ * @param nb_walk_lcores
+ *   The size of the walk_lcores array.
+ * @param f
+ *   The callback function which should be called for each timers. Can be NULL.
+ * @param f_arg
+ *   An arbitrary argument that will be passed to f, if it is called.
+ * @return
+ *   - 0: success
+ *   - EINVAL: invalid timer_data_id
+ */
+int __rte_experimental
+rte_timer_stop_all(uint32_t timer_data_id, unsigned int *walk_lcores,
+  int nb_walk_lcores, rte_timer_stop_all_cb_t f, void *f_arg);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
  *
diff --git a/lib/librte_timer/rte_timer_version.map 
b/lib/librte_timer/rte_timer_version.map
index c2e5836..72f75c8 100644
--- a/lib/librte_timer/rte_timer_version.map
+++ b/lib/librte_timer/rte_timer_version.map
@@ -33,5 +33,6 @@ EXPERIMENTAL {
rte_timer_alt_stop;
rte_timer_data_alloc;
rte_timer_data_dealloc;
+   rte_timer_stop_all;
rte_timer_subsystem_finalize;
 };
-- 
2.6.4



[dpdk-dev] [PATCH v4 1/2] timer: allow timer management in shared memory

2019-03-06 Thread Erik Gabriel Carrillo
Currently, the timer library uses a per-process table of structures to
manage skiplists of timers presumably because timers contain arbitrary
function pointers whose value may not resolve properly in other
processes.

However, if the same callback is used handle all timers, and that
callback is only invoked in one process, then it woud be safe to allow
the data structures to be allocated in shared memory, and to allow
secondary processes to modify the timer lists.  This would let timers be
used in more multi-process scenarios.

The library's global variables are wrapped with a struct, and an array
of these structures is created in shared memory.  The original APIs
are updated to reference the zeroth entry in the array. This maintains
the original behavior for both primary and secondary processes since
the set intersection of their coremasks should be empty [1].  New APIs
are introduced to enable the allocation/deallocation of other entries
in the array.

New variants of the APIs used to start and stop timers are introduced;
they allow a caller to specify which array entry should be used to
locate the timer list to insert into or delete from.

Finally, a new variant of rte_timer_manage() is introduced, which
allows a caller to specify which array entry should be used to locate
the timer lists to process; it can also process multiple timer lists per
invocation.

[1] 
https://doc.dpdk.org/guides/prog_guide/multi_proc_support.html#multi-process-limitations

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/Makefile  |   1 +
 lib/librte_timer/rte_timer.c   | 519 ++---
 lib/librte_timer/rte_timer.h   | 226 +-
 lib/librte_timer/rte_timer_version.map |  22 ++
 4 files changed, 723 insertions(+), 45 deletions(-)

diff --git a/lib/librte_timer/Makefile b/lib/librte_timer/Makefile
index 4ebd528..8ec63f4 100644
--- a/lib/librte_timer/Makefile
+++ b/lib/librte_timer/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 # library name
 LIB = librte_timer.a
 
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
 LDLIBS += -lrte_eal
 
diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 30c7b0a..2bd49d0 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -5,6 +5,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -21,11 +22,15 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 #include "rte_timer.h"
 
-LIST_HEAD(rte_timer_list, rte_timer);
-
+/**
+ * Per-lcore info for timers.
+ */
 struct priv_timer {
struct rte_timer pending_head;  /**< dummy timer instance to head up 
list */
rte_spinlock_t list_lock;   /**< lock to protect list access */
@@ -48,25 +53,84 @@ struct priv_timer {
 #endif
 } __rte_cache_aligned;
 
-/** per-lcore private info for timers */
-static struct priv_timer priv_timer[RTE_MAX_LCORE];
+#define FL_ALLOCATED   (1 << 0)
+struct rte_timer_data {
+   struct priv_timer priv_timer[RTE_MAX_LCORE];
+   uint8_t internal_flags;
+};
+
+#define RTE_MAX_DATA_ELS 64
+static struct rte_timer_data *rte_timer_data_arr;
+static uint32_t default_data_id;
+static uint32_t rte_timer_subsystem_initialized;
+
+/* For maintaining older interfaces for a period */
+static struct rte_timer_data default_timer_data;
 
 /* when debug is enabled, store some statistics */
 #ifdef RTE_LIBRTE_TIMER_DEBUG
-#define __TIMER_STAT_ADD(name, n) do { \
+#define __TIMER_STAT_ADD(priv_timer, name, n) do { \
unsigned __lcore_id = rte_lcore_id();   \
if (__lcore_id < RTE_MAX_LCORE) \
priv_timer[__lcore_id].stats.name += (n);   \
} while(0)
 #else
-#define __TIMER_STAT_ADD(name, n) do {} while(0)
+#define __TIMER_STAT_ADD(priv_timer, name, n) do {} while (0)
 #endif
 
-/* Init the timer library. */
+static inline int
+timer_data_valid(uint32_t id)
+{
+   return !!(rte_timer_data_arr[id].internal_flags & FL_ALLOCATED);
+}
+
+/* validate ID and retrieve timer data pointer, or return error value */
+#define TIMER_DATA_VALID_GET_OR_ERR_RET(id, timer_data, retval) do {   \
+   if (id >= RTE_MAX_DATA_ELS || !timer_data_valid(id))\
+   return retval;  \
+   timer_data = &rte_timer_data_arr[id];   \
+} while (0)
+
+int __rte_experimental
+rte_timer_data_alloc(uint32_t *id_ptr)
+{
+   int i;
+   struct rte_timer_data *data;
+
+   if (!rte_timer_subsystem_initialized)
+   return -ENOMEM;
+
+   for (i = 0; i < RTE_MAX_DATA_ELS; i++) {
+   data = &rte_timer_data_arr[i];
+   if (!(data->internal_flags & FL_ALLOCATED)) {
+   data->in

[dpdk-dev] [PATCH] maintainers: claim responsibility for timer lib

2019-03-11 Thread Erik Gabriel Carrillo
Add myself as co-maintainer for the timer library.

Signed-off-by: Erik Gabriel Carrillo 
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 097cfb4..4b0beec 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1192,6 +1192,7 @@ F: doc/guides/sample_app_ug/vm_power_management.rst
 
 Timers
 M: Robert Sanford 
+M: Erik Gabriel Carrillo 
 F: lib/librte_timer/
 F: doc/guides/prog_guide/timer_lib.rst
 F: app/test/test_timer*
-- 
2.6.4



[dpdk-dev] [PATCH v10 0/9] eventtimer: introduce event timer adapter

2018-04-03 Thread Erik Gabriel Carrillo
This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v10
- remove stale references to rte_event_timer_init API and update docs (Jerin)
- rebase to latest dpdk-next-eventdev tree (Jerin)
- make sw_event_adapter_timer_ops var static (Pavan)

v9
- Addressed comments on previous series from Pavan:
  - Don't assume services exist in HW cases
  - Adjust retry logic in a couple of tests
- Addressed comments on previous series from Jerin:
  - Fix build warning
- Addressed comments on previous series from Hemant:
  - Adjust copyright text

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS   |7 +
 config/common_base|1 +
 config/rte_config.h   |1 +
 doc/api/doxy-api-index.md   

[dpdk-dev] [PATCH v10 2/9] eventdev: convert to SPDX license tag in header

2018-04-03 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Hemant Agrawal 
Acked-by: Jerin Jacob 
---
 lib/librte_eventdev/rte_eventdev.h | 37 +
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h 
b/lib/librte_eventdev/rte_eventdev.h
index a1f0749..86df4be 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in
- *   the documentation and/or other materials provided with the
- *   distribution.
- * * Neither the name of Cavium, Inc nor the names of its
- *   contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright 2016 NXP
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4



[dpdk-dev] [PATCH v10 1/9] eventtimer: introduce event timer adapter

2018-04-03 Thread Erik Gabriel Carrillo
Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob 
Signed-off-by: Pavan Nikhilesh 
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 lib/librte_eventdev/Makefile  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++
 lib/librte_eventdev/rte_eventdev.h|   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *   timer_tick_ns
+ *   +
+ *  +---+|
+ *  |   ||
+ *  +---+ bkt 0 +v---+
+ *  |   |   ||
+ *  |   +---+|
+ *  +---+---++---+---+  +---+---+---+---+
+ *  |   ||   |  |   |   |   |   |
+ *  | bkt n || bkt 1 |<-> t0| t1| t2| tn|
+ *  |   ||   |  |   |   |   |   |
+ *  +---+---++---+---+  +---+---+---+---+
+ *  | Timer adapter  |
+ *  +---+---++---+---+
+ *  |   ||   |
+ *  | bkt 4 || bkt 2 |<--- Current bucket
+ *  |   ||   |
+ *  +---+---++---+---+
+ *   |  +---+   |
+ *   |  |   |   |
+ *   +--+ bkt 3 +---+
+ *  |   |
+ *  +---+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in 
ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will 
be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may als

[dpdk-dev] [PATCH v10 4/9] mk: update library order in static build

2018-04-03 Thread Erik Gabriel Carrillo
The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a9b4b05..01d0b4e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)+= 
-lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)  += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)  += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)+= -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)  += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)   += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)   += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)  += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)+= -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)   += -lrte_ring
-- 
2.6.4



[dpdk-dev] [PATCH v10 5/9] eventtimer: add default software driver

2018-04-03 Thread Erik Gabriel Carrillo
If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 lib/Makefile  |   2 +-
 lib/librte_eventdev/Makefile  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 909 ++
 lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
 4 files changed, 966 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool 
librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash 
librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool 
-lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..968c18b 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
}
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
return NULL;
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,875 @@ rte_event_timer_adapter_stats_reset(struct 
rte_event_timer_adapter *adapter)
return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+   uint16_t head;
+   uint16_t tail;
+   struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+   return (bufp-&

[dpdk-dev] [PATCH v10 3/9] eventtimer: add common code

2018-04-03 Thread Erik Gabriel Carrillo
This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo 
---
 config/common_base|   1 +
 drivers/event/sw/sw_evdev.c   |  18 +
 lib/librte_eventdev/Makefile  |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c | 387 ++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++
 lib/librte_eventdev/rte_eventdev.c|  22 ++
 lib/librte_eventdev/rte_eventdev.h|  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h|  35 ++
 lib/librte_eventdev/rte_eventdev_version.map  |  20 +-
 9 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index 7abf7c6..9354c66 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 0e89f11..dcb6551 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+ uint64_t flags,
+ uint32_t *caps,
+ const struct rte_event_timer_adapter_ops **ops)
+{
+   RTE_SET_USED(dev);
+   RTE_SET_USED(flags);
+   *caps = 0;
+
+   /* Use default SW ops */
+   *ops = NULL;
+
+   return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+   .timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
.xstats_get = sw_xstats_get,
.xstats_get_names = sw_xstats_get_names,
.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+   rte_log(RTE_LOG_ ## level, logtype, \
+   RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+   "\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+void *conf_arg)
+{
+   struct rte_event_timer_adapter *adapter;
+   struct rte_eventdev *dev;
+   struct rte_event_dev_config dev_conf;
+   struct rte_event_port_conf *port_conf, def_port_conf = {0};
+   int started;
+   uint8_t port_id;
+   uint8_t dev_id;
+   int ret;

[dpdk-dev] [PATCH v10 6/9] eventtimer: add support for meson build system

2018-04-03 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 config/rte_config.h | 1 +
 lib/librte_eventdev/meson.build | 9 ++---
 lib/meson.build | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
'rte_event_ring.c',
-   'rte_event_eth_rx_adapter.c')
+   'rte_event_eth_rx_adapter.c',
+   'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
'rte_eventdev_pmd.h',
'rte_eventdev_pmd_pci.h',
'rte_eventdev_pmd_vdev.h',
'rte_event_ring.h',
-   'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+   'rte_event_eth_rx_adapter.h',
+   'rte_event_timer_adapter.h',
+   'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
'metrics', # bitrate/latency stats depends on this
'hash',# efd depends on this
'kvargs',  # cryptodev depends on this
+   'timer',   # eventdev depends on this
'acl', 'bbdev', 'bitratestats', 'cfgfile',
'cmdline', 'cryptodev',
'distributor', 'efd', 'eventdev',
'gro', 'gso', 'ip_frag', 'jobstats',
'kni', 'latencystats', 'lpm', 'member',
'meter', 'power', 'pdump',
-   'reorder', 'sched', 'security', 'timer', 'vhost',
+   'reorder', 'sched', 'security', 'vhost',
# add pkt framework libs which use other libs from above
'port', 'table', 'pipeline',
# flow_classify lib depends on pkt framework table lib
-- 
2.6.4



[dpdk-dev] [PATCH v10 8/9] doc: add event timer adapter section to programmer's guide

2018-04-03 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Signed-off-by: Jerin Jacob 
Signed-off-by: Pavan Nikhilesh 
Acked-by: Jerin Jacob 
---
 doc/guides/prog_guide/event_timer_adapter.rst | 296 ++
 doc/guides/prog_guide/index.rst   |   1 +
 2 files changed, 297 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst 
b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 000..7e5fe18
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,296 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event ` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers ` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+--
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+   #define NSECPERSEC 1E9 // No of ns in 1 sec
+   const struct rte_event_timer_adapter_conf adapter_config = {
+.event_dev_id = event_dev_id,
+.timer_adapter_id = 0,
+   

[dpdk-dev] [PATCH v10 7/9] test: add event timer adapter auto-test

2018-04-03 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 test/test/Makefile   |1 +
 test/test/test_event_timer_adapter.c | 1831 ++
 2 files changed, 1832 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
new file mode 100644
index 000..9afe031
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1831 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)   RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+   struct rte_event_dev_info *info)
+{
+   memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+   dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+   dev_conf->nb_event_ports = 1;
+   dev_conf->nb_event_queues = 1;
+   dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+   dev_conf->nb_event_port_dequeue_depth =
+   info->max_event_port_dequeue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_events_limit =
+   info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+   int ret;
+   struct rte_event_dev_config dev_conf;
+   struct rte_event_dev_info info;
+   uint32_t service_id;
+
+   ret = rte_event_dev_info_get(evdev, &info);
+   TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+   TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+   "ERROR max_num_events=%d < max_events=%d",
+   info.max_num_events, MAX_TIMERS);
+
+   devconf_set_default_sane_values(&dev_conf, &info);
+   ret = rte_event_dev_configure(evdev, &dev_conf);
+   TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+   ret = rte_event_queue_setup(evdev, 0, NULL);
+   TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+   /* Configure event port */
+   ret = rte_event_port_setup(evdev, 0, NULL);
+   TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+   ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+   TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+   /* If this is a software event device, map and start its service */
+   if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+   TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+   "Failed to add service core");
+   TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+   sw_evdev_slcore),
+   "Failed to start service core");
+   TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+   service_id, sw_evdev_slcore, 1),
+   "Failed to map evdev service");
+   TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+   service_id, 1),
+   "Failed to start evdev service");
+ 

[dpdk-dev] [PATCH v10 9/9] doc: add event timer adapter documentation

2018-04-03 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 MAINTAINERS|  7 +++
 doc/api/doxy-api-index.md  | 32 +++-
 doc/guides/rel_notes/release_18_05.rst |  6 ++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4c0cc1..d72f012 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo 
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain 
 M: Hemant Agrawal 
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]   (@ref rte_security.h),
   [eventdev]   (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter](@ref rte_event_timer_adapter.h),
   [rawdev] (@ref rte_rawdev.h),
   [metrics](@ref rte_metrics.h),
   [bitrate](@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst 
b/doc/guides/rel_notes/release_18_05.rst
index 9cc77f8..d2a4192 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -58,6 +58,12 @@ New Features
   * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
   * Added support for DROP action in flow API.
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 ---
-- 
2.6.4



[dpdk-dev] [PATCH v11 0/9] eventtimer: introduce event timer adapter

2018-04-04 Thread Erik Gabriel Carrillo
This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v11
- fix build error (Jerin)
- fix whitespace issue (Pavan)

v10
- remove stale references to rte_event_timer_init API and update docs (Jerin)
- rebase to latest dpdk-next-eventdev tree (Jerin)
- make sw_event_adapter_timer_ops var static (Pavan)

v9
- Addressed comments on previous series from Pavan:
  - Don't assume services exist in HW cases
  - Adjust retry logic in a couple of tests
- Addressed comments on previous series from Jerin:
  - Fix build warning
- Addressed comments on previous series from Hemant:
  - Adjust copyright text

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS   |7 +
 config/common_base|1 +
 config/rte_config.h

[dpdk-dev] [PATCH v11 1/9] eventtimer: introduce event timer adapter

2018-04-04 Thread Erik Gabriel Carrillo
Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob 
Signed-off-by: Pavan Nikhilesh 
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 lib/librte_eventdev/Makefile  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++
 lib/librte_eventdev/rte_eventdev.h|   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *   timer_tick_ns
+ *   +
+ *  +---+|
+ *  |   ||
+ *  +---+ bkt 0 +v---+
+ *  |   |   ||
+ *  |   +---+|
+ *  +---+---++---+---+  +---+---+---+---+
+ *  |   ||   |  |   |   |   |   |
+ *  | bkt n || bkt 1 |<-> t0| t1| t2| tn|
+ *  |   ||   |  |   |   |   |   |
+ *  +---+---++---+---+  +---+---+---+---+
+ *  | Timer adapter  |
+ *  +---+---++---+---+
+ *  |   ||   |
+ *  | bkt 4 || bkt 2 |<--- Current bucket
+ *  |   ||   |
+ *  +---+---++---+---+
+ *   |  +---+   |
+ *   |  |   |   |
+ *   +--+ bkt 3 +---+
+ *  |   |
+ *  +---+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in 
ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will 
be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may als

[dpdk-dev] [PATCH v11 2/9] eventdev: convert to SPDX license tag in header

2018-04-04 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Hemant Agrawal 
Acked-by: Jerin Jacob 
---
 lib/librte_eventdev/rte_eventdev.h | 37 +
 1 file changed, 5 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_eventdev.h 
b/lib/librte_eventdev/rte_eventdev.h
index a1f0749..86df4be 100644
--- a/lib/librte_eventdev/rte_eventdev.h
+++ b/lib/librte_eventdev/rte_eventdev.h
@@ -1,35 +1,8 @@
-/*
- *   BSD LICENSE
- *
- *   Copyright 2016 Cavium, Inc.
- *   Copyright 2016 Intel Corporation.
- *   Copyright 2016 NXP.
- *
- *   Redistribution and use in source and binary forms, with or without
- *   modification, are permitted provided that the following conditions
- *   are met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in
- *   the documentation and/or other materials provided with the
- *   distribution.
- * * Neither the name of Cavium, Inc nor the names of its
- *   contributors may be used to endorse or promote products derived
- *   from this software without specific prior written permission.
- *
- *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2016 Cavium, Inc.
+ * Copyright(c) 2016-2018 Intel Corporation.
+ * Copyright 2016 NXP
+ * All rights reserved.
  */
 
 #ifndef _RTE_EVENTDEV_H_
-- 
2.6.4



[dpdk-dev] [PATCH v11 6/9] eventtimer: add support for meson build system

2018-04-04 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 config/rte_config.h | 1 +
 lib/librte_eventdev/meson.build | 9 ++---
 lib/meson.build | 3 ++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/config/rte_config.h b/config/rte_config.h
index 72c0aa2..117c19f 100644
--- a/config/rte_config.h
+++ b/config/rte_config.h
@@ -55,6 +55,7 @@
 /* eventdev defines */
 #define RTE_EVENT_MAX_DEVS 16
 #define RTE_EVENT_MAX_QUEUES_PER_DEV 64
+#define RTE_EVENT_TIMER_ADAPTER_NUM_MAX 32
 
 /* ip_fragmentation defines */
 #define RTE_LIBRTE_IP_FRAG_MAX_FRAG 4
diff --git a/lib/librte_eventdev/meson.build b/lib/librte_eventdev/meson.build
index e1e22a5..232b870 100644
--- a/lib/librte_eventdev/meson.build
+++ b/lib/librte_eventdev/meson.build
@@ -5,11 +5,14 @@ version = 3
 allow_experimental_apis = true
 sources = files('rte_eventdev.c',
'rte_event_ring.c',
-   'rte_event_eth_rx_adapter.c')
+   'rte_event_eth_rx_adapter.c',
+   'rte_event_timer_adapter.c')
 headers = files('rte_eventdev.h',
'rte_eventdev_pmd.h',
'rte_eventdev_pmd_pci.h',
'rte_eventdev_pmd_vdev.h',
'rte_event_ring.h',
-   'rte_event_eth_rx_adapter.h')
-deps += ['ring', 'ethdev', 'hash']
+   'rte_event_eth_rx_adapter.h',
+   'rte_event_timer_adapter.h',
+   'rte_event_timer_adapter_pmd.h')
+deps += ['ring', 'ethdev', 'hash', 'mempool', 'timer']
diff --git a/lib/meson.build b/lib/meson.build
index ef61591..b1ad35f 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -13,13 +13,14 @@ libraries = [ 'compat', # just a header, used for versioning
'metrics', # bitrate/latency stats depends on this
'hash',# efd depends on this
'kvargs',  # cryptodev depends on this
+   'timer',   # eventdev depends on this
'acl', 'bbdev', 'bitratestats', 'cfgfile',
'cmdline', 'cryptodev',
'distributor', 'efd', 'eventdev',
'gro', 'gso', 'ip_frag', 'jobstats',
'kni', 'latencystats', 'lpm', 'member',
'meter', 'power', 'pdump',
-   'reorder', 'sched', 'security', 'timer', 'vhost',
+   'reorder', 'sched', 'security', 'vhost',
# add pkt framework libs which use other libs from above
'port', 'table', 'pipeline',
# flow_classify lib depends on pkt framework table lib
-- 
2.6.4



[dpdk-dev] [PATCH v11 5/9] eventtimer: add default software driver

2018-04-04 Thread Erik Gabriel Carrillo
If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 lib/Makefile  |   2 +-
 lib/librte_eventdev/Makefile  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 912 ++
 lib/librte_eventdev/rte_event_timer_adapter.h |  57 +-
 4 files changed, 969 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a6..965be6c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -31,7 +31,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool 
librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash 
librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
 DEPDIRS-librte_rawdev := librte_eal librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8b16e3f..297df4a 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -14,7 +14,7 @@ LIBABIVER := 3
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool 
-lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 75a14ac..6eba6b4 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -5,11 +5,20 @@
 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -20,9 +29,13 @@
 #define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
 
 static int evtim_logtype;
+static int evtim_svc_logtype;
+static int evtim_buffer_logtype;
 
 static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 
+static const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 #define EVTIM_LOG(level, logtype, ...) \
rte_log(RTE_LOG_ ## level, logtype, \
RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
@@ -33,8 +46,14 @@ static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
 #ifdef RTE_LIBRTE_EVENTDEV_DEBUG
 #define EVTIM_LOG_DBG(...) \
EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#define EVTIM_BUF_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_buffer_logtype, __VA_ARGS__)
+#define EVTIM_SVC_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_svc_logtype, __VA_ARGS__)
 #else
 #define EVTIM_LOG_DBG(...) (void)0
+#define EVTIM_BUF_LOG_DBG(...) (void)0
+#define EVTIM_SVC_LOG_DBG(...) (void)0
 #endif
 
 static int
@@ -188,6 +207,12 @@ rte_event_timer_adapter_create_ext(
}
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
ret = adapter->ops->init(adapter);
@@ -305,6 +330,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
return NULL;
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -377,6 +408,878 @@ rte_event_timer_adapter_stats_reset(struct 
rte_event_timer_adapter *adapter)
return adapter->ops->stats_reset(adapter);
 }
 
+/*
+ * Software event timer adapter buffer helper functions
+ */
+
+#define NSECPERSEC 1E9
+
+/* Optimizations used to index into the buffer require that the buffer size
+ * be a power of 2.
+ */
+#define EVENT_BUFFER_SZ 4096
+#define EVENT_BUFFER_BATCHSZ 32
+#define EVENT_BUFFER_MASK (EVENT_BUFFER_SZ - 1)
+
+struct event_buffer {
+   uint16_t head;
+   uint16_t tail;
+   struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+   return (bufp-&

[dpdk-dev] [PATCH v11 7/9] test: add event timer adapter auto-test

2018-04-04 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 test/test/Makefile   |1 +
 test/test/test_event_timer_adapter.c | 1830 ++
 2 files changed, 1831 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index a88cc38..c9c007c9 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -185,6 +185,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 endif
 
 ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y)
diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
new file mode 100644
index 000..93471db
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,1830 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc
+ * Copyright(c) 2017-2018 Intel Corporation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "test.h"
+
+/* 4K timers corresponds to sw evdev max inflight events */
+#define MAX_TIMERS  (4 * 1024)
+#define BKT_TCK_NSEC
+
+#define NSECPERSEC 1E9
+#define BATCH_SIZE 16
+/* Both the app lcore and adapter ports are linked to this queue */
+#define TEST_QUEUE_ID 0
+/* Port the application dequeues from */
+#define TEST_PORT_ID 0
+#define TEST_ADAPTER_ID 0
+
+/* Handle log statements in same manner as test macros */
+#define LOG_DBG(...)   RTE_LOG(DEBUG, EAL, __VA_ARGS__)
+
+static int evdev;
+static struct rte_event_timer_adapter *timdev;
+static struct rte_mempool *eventdev_test_mempool;
+static struct rte_ring *timer_producer_ring;
+static uint64_t global_bkt_tck_ns;
+static volatile uint8_t arm_done;
+
+static bool using_services;
+static uint32_t test_lcore1;
+static uint32_t test_lcore2;
+static uint32_t test_lcore3;
+static uint32_t sw_evdev_slcore;
+static uint32_t sw_adptr_slcore;
+
+static inline void
+devconf_set_default_sane_values(struct rte_event_dev_config *dev_conf,
+   struct rte_event_dev_info *info)
+{
+   memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+   dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+   dev_conf->nb_event_ports = 1;
+   dev_conf->nb_event_queues = 1;
+   dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+   dev_conf->nb_event_port_dequeue_depth =
+   info->max_event_port_dequeue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_events_limit =
+   info->max_num_events;
+}
+
+static inline int
+eventdev_setup(void)
+{
+   int ret;
+   struct rte_event_dev_config dev_conf;
+   struct rte_event_dev_info info;
+   uint32_t service_id;
+
+   ret = rte_event_dev_info_get(evdev, &info);
+   TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+   TEST_ASSERT(info.max_num_events >= (int32_t)MAX_TIMERS,
+   "ERROR max_num_events=%d < max_events=%d",
+   info.max_num_events, MAX_TIMERS);
+
+   devconf_set_default_sane_values(&dev_conf, &info);
+   ret = rte_event_dev_configure(evdev, &dev_conf);
+   TEST_ASSERT_SUCCESS(ret, "Failed to configure eventdev");
+
+   ret = rte_event_queue_setup(evdev, 0, NULL);
+   TEST_ASSERT_SUCCESS(ret, "Failed to setup queue=%d", 0);
+
+   /* Configure event port */
+   ret = rte_event_port_setup(evdev, 0, NULL);
+   TEST_ASSERT_SUCCESS(ret, "Failed to setup port=%d", 0);
+   ret = rte_event_port_link(evdev, 0, NULL, NULL, 0);
+   TEST_ASSERT(ret >= 0, "Failed to link all queues port=%d", 0);
+
+   /* If this is a software event device, map and start its service */
+   if (rte_event_dev_service_id_get(evdev, &service_id) == 0) {
+   TEST_ASSERT_SUCCESS(rte_service_lcore_add(sw_evdev_slcore),
+   "Failed to add service core");
+   TEST_ASSERT_SUCCESS(rte_service_lcore_start(
+   sw_evdev_slcore),
+   "Failed to start service core");
+   TEST_ASSERT_SUCCESS(rte_service_map_lcore_set(
+   service_id, sw_evdev_slcore, 1),
+   "Failed to map evdev service");
+   TEST_ASSERT_SUCCESS(rte_service_runstate_set(
+   service_id, 1),
+   "Failed to start evdev service");
+ 

[dpdk-dev] [PATCH v11 4/9] mk: update library order in static build

2018-04-04 Thread Erik Gabriel Carrillo
The introduction of the event timer adapter library adds a dependency
on the rte_timer library from the rte_eventdev library.  Update the
order so that the timer library comes after the eventdev library in the
linker command when statically linking applications.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 mk/rte.app.mk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index a9b4b05..01d0b4e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -80,7 +80,6 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_BITRATE)+= 
-lrte_bitratestats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LATENCY_STATS)  += -lrte_latencystats
 _LDLIBS-$(CONFIG_RTE_LIBRTE_POWER)  += -lrte_power
 
-_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)  += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EFD)+= -lrte_efd
 
 _LDLIBS-y += --whole-archive
@@ -98,6 +97,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_CRYPTODEV)  += -lrte_cryptodev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY)   += -lrte_security
 _LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV)   += -lrte_eventdev
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER)  += -lrte_timer
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL)+= -lrte_mempool
 _LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING)   += -lrte_mempool_ring
 _LDLIBS-$(CONFIG_RTE_LIBRTE_RING)   += -lrte_ring
-- 
2.6.4



[dpdk-dev] [PATCH v11 3/9] eventtimer: add common code

2018-04-04 Thread Erik Gabriel Carrillo
This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Pavan Nikhilesh 
---
 config/common_base|   1 +
 drivers/event/sw/sw_evdev.c   |  18 +
 lib/librte_eventdev/Makefile  |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c | 387 ++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 114 +++
 lib/librte_eventdev/rte_eventdev.c|  22 ++
 lib/librte_eventdev/rte_eventdev.h|  20 ++
 lib/librte_eventdev/rte_eventdev_pmd.h|  35 ++
 lib/librte_eventdev/rte_eventdev_version.map  |  20 +-
 9 files changed, 618 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/config/common_base b/config/common_base
index 7abf7c6..9354c66 100644
--- a/config/common_base
+++ b/config/common_base
@@ -550,6 +550,7 @@ CONFIG_RTE_LIBRTE_EVENTDEV=y
 CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG=n
 CONFIG_RTE_EVENT_MAX_DEVS=16
 CONFIG_RTE_EVENT_MAX_QUEUES_PER_DEV=64
+CONFIG_RTE_EVENT_TIMER_ADAPTER_NUM_MAX=32
 
 #
 # Compile PMD for skeleton event device
diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 0e89f11..dcb6551 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -464,6 +464,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+ uint64_t flags,
+ uint32_t *caps,
+ const struct rte_event_timer_adapter_ops **ops)
+{
+   RTE_SET_USED(dev);
+   RTE_SET_USED(flags);
+   *caps = 0;
+
+   /* Use default SW ops */
+   *ops = NULL;
+
+   return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -791,6 +807,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+   .timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
.xstats_get = sw_xstats_get,
.xstats_get_names = sw_xstats_get_names,
.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 549b182..8b16e3f 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -20,6 +20,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -29,6 +30,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 000..75a14ac
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,387 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DATA_MZ_NAME_FORMAT "rte_event_timer_adapter_data_%d"
+
+static int evtim_logtype;
+
+static struct rte_event_timer_adapter 
adapters[RTE_EVENT_TIMER_ADAPTER_NUM_MAX];
+
+#define EVTIM_LOG(level, logtype, ...) \
+   rte_log(RTE_LOG_ ## level, logtype, \
+   RTE_FMT("EVTIMER: %s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) \
+   "\n", __func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#define EVTIM_LOG_ERR(...) EVTIM_LOG(ERR, evtim_logtype, __VA_ARGS__)
+
+#ifdef RTE_LIBRTE_EVENTDEV_DEBUG
+#define EVTIM_LOG_DBG(...) \
+   EVTIM_LOG(DEBUG, evtim_logtype, __VA_ARGS__)
+#else
+#define EVTIM_LOG_DBG(...) (void)0
+#endif
+
+static int
+default_port_conf_cb(uint16_t id, uint8_t event_dev_id, uint8_t *event_port_id,
+void *conf_arg)
+{
+   struct rte_event_timer_adapter *adapter;
+   struct rte_eventdev *dev;
+   struct rte_event_dev_config dev_conf;
+   struct rte_event_port_conf *port_conf, def_port_conf = {0};
+   int started;
+   uint8_t port_id;
+   uint8_t dev_id;
+ 

[dpdk-dev] [PATCH v11 8/9] doc: add event timer adapter section to programmer's guide

2018-04-04 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Signed-off-by: Jerin Jacob 
Signed-off-by: Pavan Nikhilesh 
Acked-by: Jerin Jacob 
---
 doc/guides/prog_guide/event_timer_adapter.rst | 296 ++
 doc/guides/prog_guide/index.rst   |   1 +
 2 files changed, 297 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst 
b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 000..7e5fe18
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,296 @@
+..  SPDX-License-Identifier: BSD-3-Clause
+Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Event Timer Adapter Library
+=
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event ` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers ` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+--
+Event timers are timers that enqueue a timer expiration event to an event
+device upon timer expiration.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configuration.
+
+State
+~
+
+Before arming an event timer, the application should initialize its state to
+RTE_EVENT_TIMER_NOT_ARMED. The event timer's state will be updated when a
+request to arm or cancel it takes effect.
+
+If the application wishes to rearm the timer after it has expired, it should
+reset the state back to RTE_EVENT_TIMER_NOT_ARMED before doing so.
+
+User Metadata
+~
+
+Memory to store user specific metadata.  The event timer adapter implementation
+will not modify this area.
+
+API Overview
+
+
+This section will introduce the reader to the event timer adapter API, showing
+how to create and configure an event timer adapter and use it to manage event
+timers.
+
+From a high level, the setup steps are:
+
+* rte_event_timer_adapter_create()
+* rte_event_timer_adapter_start()
+
+And to start and stop timers:
+
+* rte_event_timer_arm_burst()
+* rte_event_timer_cancel_burst()
+
+Create and Configure an Adapter Instance
+
+
+To create an event timer adapter instance, initialize an
+``rte_event_timer_adapter_conf`` struct with the desired values, and pass it
+to ``rte_event_timer_adapter_create()``.
+
+.. code-block:: c
+
+   #define NSECPERSEC 1E9 // No of ns in 1 sec
+   const struct rte_event_timer_adapter_conf adapter_config = {
+.event_dev_id = event_dev_id,
+.timer_adapter_id = 0,
+   

[dpdk-dev] [PATCH v11 9/9] doc: add event timer adapter documentation

2018-04-04 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
Acked-by: Jerin Jacob 
---
 MAINTAINERS|  7 +++
 doc/api/doxy-api-index.md  | 32 +++-
 doc/guides/rel_notes/release_18_05.rst |  6 ++
 3 files changed, 16 insertions(+), 29 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index d4c0cc1..d72f012 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -317,6 +317,13 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo 
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
+
 Raw device API - EXPERIMENTAL
 M: Shreyansh Jain 
 M: Hemant Agrawal 
diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index d77f205..5c6cd51 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -2,35 +2,8 @@ API {#index}
 ===
 
 
 
 The public API headers are grouped by topics:
@@ -47,6 +20,7 @@ The public API headers are grouped by topics:
   [security]   (@ref rte_security.h),
   [eventdev]   (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter](@ref rte_event_timer_adapter.h),
   [rawdev] (@ref rte_rawdev.h),
   [metrics](@ref rte_metrics.h),
   [bitrate](@ref rte_bitrate.h),
diff --git a/doc/guides/rel_notes/release_18_05.rst 
b/doc/guides/rel_notes/release_18_05.rst
index 9cc77f8..d2a4192 100644
--- a/doc/guides/rel_notes/release_18_05.rst
+++ b/doc/guides/rel_notes/release_18_05.rst
@@ -58,6 +58,12 @@ New Features
   * Added support for NVGRE, VXLAN and GENEVE filters in flow API.
   * Added support for DROP action in flow API.
 
+* **Added the Event Timer Adapter Library.**
+
+  The Event Timer Adapter Library extends the event-based model by introducing
+  APIs that allow applications to arm/cancel event timers that generate
+  timer expiry events. This new type of event is scheduled by an event device
+  along with existing types of events.
 
 API Changes
 ---
-- 
2.6.4



[dpdk-dev] [PATCH v6 00/23] eventtimer: introduce event timer adapter

2018-01-10 Thread Erik Gabriel Carrillo
This patch set adds an initial implementation of the software driver
for the event timer adapter library, adds some unit tests, and adds
documentation.  More testing is needed, but I'd like to get feedback on the
current state.

This patch set produces the following checkpatch warning: 
"macro with flow control". I have left the macros in since such usage seems
common in DPDK.

The tests also depend on the following patch to pass:
http://dpdk.org/ml/archives/dev/2018-January/085209.html

v6
- Addressed comments on previous versin from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (23):
  eventtimer: add event timer adapter API
  eventtimer: add common code
  eventtimer: add default software driver stub
  test: add event timer adapter auto-test
  eventtimer: add adapter allocation definitions
  test: exercise event timer adapter allocation functions
  eventtimer: add adapter get info function definition
  eventtimer: add adapter start/stop definitions
  eventtimer: add API to get service id
  eventtimer: remove service id entry from info structure
  test: exercise event timer adapter start/stop functions
  eventtimer: add event timer arm/cancel function definitions
  eventtimer: add adapter service definition
  eventtimer: add event timer initializer function
  eventtimer: add buffering of timer expiry events
  eventtimer: add stats to API
  eventtimer: add support for single-producer put mode
  eventtimer: add non-blocking mode for event timer operations
  test: exercise event timer arm and expiry
  maintainers: add event timer adapter section
  doc: add event timer adapter to API index
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter to release notes

 MAINTAINERS   |6 +
 doc/api/doxy-api-index.md |1 +
 doc/guides/prog_guide/event_timer_adapter.rst |  301 ++
 doc/guides/prog_guide/index.rst   |1 +
 doc/guides/rel_notes/release_18_02.rst|6 +
 drivers/event/sw/sw_evdev.c   |   18 +
 lib/Makefile  |2 +-
 lib/librte_eventdev/Makefile  |5 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 1147 +
 lib/librte_eventdev/rte_event_timer_adapter.h |  651 
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  174 
 lib/librte_eventdev/rte_eventdev.h|7 +-
 lib/librte_eventdev/rte_eventdev_pmd.h|   35 +
 lib/librte_eventdev/rte_eventdev_version.map  |   19 +-
 mk/rte.app.mk |2 +-
 test/test/Makefile|1 +
 test/test/test_event_timer_adapter.c  |  446 
 17 files changed, 2816 insertions(+), 6 deletions(-)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst
 create mode 100644 lib/librte_ev

[dpdk-dev] [PATCH v6 02/23] eventtimer: add common code

2018-01-10 Thread Erik Gabriel Carrillo
This commit adds the logic that is shared by all event timer adapter
drivers; the common code handles instance allocation and some
initialization.

Signed-off-by: Erik Gabriel Carrillo 
---
 drivers/event/sw/sw_evdev.c   |  18 +
 lib/librte_eventdev/Makefile  |   2 +
 lib/librte_eventdev/rte_event_timer_adapter.c | 395 ++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 159 +
 lib/librte_eventdev/rte_eventdev.h|   3 +
 lib/librte_eventdev/rte_eventdev_pmd.h|  35 ++
 lib/librte_eventdev/rte_eventdev_version.map  |  15 +-
 7 files changed, 626 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.c
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter_pmd.h

diff --git a/drivers/event/sw/sw_evdev.c b/drivers/event/sw/sw_evdev.c
index 74976c0..c3291c8 100644
--- a/drivers/event/sw/sw_evdev.c
+++ b/drivers/event/sw/sw_evdev.c
@@ -407,6 +407,22 @@ sw_eth_rx_adapter_caps_get(const struct rte_eventdev *dev,
return 0;
 }
 
+static int
+sw_timer_adapter_caps_get(const struct rte_eventdev *dev,
+ uint64_t flags,
+ uint32_t *caps,
+ const struct rte_event_timer_adapter_ops **ops)
+{
+   RTE_SET_USED(dev);
+   RTE_SET_USED(flags);
+   *caps = 0;
+
+   /* Use default SW ops */
+   *ops = NULL;
+
+   return 0;
+}
+
 static void
 sw_info_get(struct rte_eventdev *dev, struct rte_event_dev_info *info)
 {
@@ -727,6 +743,8 @@ sw_probe(struct rte_vdev_device *vdev)
 
.eth_rx_adapter_caps_get = sw_eth_rx_adapter_caps_get,
 
+   .timer_adapter_caps_get = sw_timer_adapter_caps_get,
+
.xstats_get = sw_xstats_get,
.xstats_get_names = sw_xstats_get_names,
.xstats_get_by_name = sw_xstats_get_by_name,
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 685b474..8f11a79 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -19,6 +19,7 @@ LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
 SRCS-y += rte_eventdev.c
 SRCS-y += rte_event_ring.c
 SRCS-y += rte_event_eth_rx_adapter.c
+SRCS-y += rte_event_timer_adapter.c
 
 # export include files
 SYMLINK-y-include += rte_eventdev.h
@@ -28,6 +29,7 @@ SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
 SYMLINK-y-include += rte_event_timer_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter_pmd.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
new file mode 100644
index 000..3e58db4
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -0,0 +1,395 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "rte_eventdev.h"
+#include "rte_eventdev_pmd.h"
+#include "rte_event_timer_adapter.h"
+#include "rte_event_timer_adapter_pmd.h"
+
+#define MAX_EVENT_TIMER_ADAPTERS 64
+#define DATA_MZ_NAME_MAX_LEN 64
+#define DA

[dpdk-dev] [PATCH v6 03/23] eventtimer: add default software driver stub

2018-01-10 Thread Erik Gabriel Carrillo
If an eventdev PMD does not wish to provide event timer adapter ops
definitions, the library will fall back to a default software
implementation whose entry points are added by this commit.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 107 ++
 1 file changed, 107 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 3e58db4..540be95 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -48,6 +48,8 @@
 
 static struct rte_event_timer_adapter adapters[MAX_EVENT_TIMER_ADAPTERS];
 
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops;
+
 static inline int
 adapter_valid(const struct rte_event_timer_adapter *adapter)
 {
@@ -211,6 +213,12 @@ rte_event_timer_adapter_create_ext(
}
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Allow driver to do some setup */
FUNC_PTR_OR_NULL_RET_WITH_ERRNO(adapter->ops->init, -ENOTSUP);
ret = adapter->ops->init(adapter);
@@ -318,6 +326,12 @@ rte_event_timer_adapter_lookup(uint16_t adapter_id)
return NULL;
}
 
+   /* If eventdev PMD did not provide ops, use default software
+* implementation.
+*/
+   if (adapter->ops == NULL)
+   adapter->ops = &sw_event_adapter_timer_ops;
+
/* Set fast-path function pointers */
adapter->arm_burst = adapter->ops->arm_burst;
adapter->arm_tmo_tick_burst = adapter->ops->arm_tmo_tick_burst;
@@ -393,3 +407,96 @@ rte_event_timer_cancel_burst(const struct 
rte_event_timer_adapter *adapter,
 
return adapter->cancel_burst(adapter, evtims, nb_evtims);
 }
+
+/*
+ * Software event timer adapter ops definitions
+ */
+
+static int
+sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
+{
+   RTE_SET_USED(adapter);
+
+   return 0;
+}
+
+static int
+sw_event_timer_adapter_uninit(struct rte_event_timer_adapter *adapter)
+{
+   RTE_SET_USED(adapter);
+
+   return 0;
+}
+
+static int
+sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
+{
+   RTE_SET_USED(adapter);
+
+   return 0;
+}
+
+static int
+sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
+{
+   RTE_SET_USED(adapter);
+
+   return 0;
+}
+
+static void
+sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
+   struct rte_event_timer_adapter_info *adapter_info)
+{
+   RTE_SET_USED(adapter);
+   RTE_SET_USED(adapter_info);
+}
+
+static int
+sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+struct rte_event_timer **evtims,
+uint16_t nb_evtims)
+{
+   RTE_SET_USED(adapter);
+   RTE_SET_USED(evtims);
+   RTE_SET_USED(nb_evtims);
+
+   return 0;
+}
+
+static int
+sw_event_timer_cancel_burst(const struct rte_event_timer_adapter *adapter,
+   struct rte_event_timer **evtims,
+   uint16_t nb_evtims)
+{
+   RTE_SET_USED(adapter);
+   RTE_SET_USED(evtims);
+   RTE_SET_USED(nb_evtims);
+
+   return 0;
+}
+
+static int
+sw_event_timer_arm_tmo_tick_burst(const struct rte_event_timer_adapter 
*adapter,
+ struct rte_event_timer **tims,
+ uint64_t timeout_tick,
+ uint16_t nb_tims)
+{
+   RTE_SET_USED(adapter);
+   RTE_SET_USED(tims);
+   RTE_SET_USED(timeout_tick);
+   RTE_SET_USED(nb_tims);
+
+   return 0;
+}
+
+const struct rte_event_timer_adapter_ops sw_event_adapter_timer_ops = {
+   .init = sw_event_timer_adapter_init,
+   .uninit = sw_event_timer_adapter_uninit,
+   .start = sw_event_timer_adapter_start,
+   .stop = sw_event_timer_adapter_stop,
+   .get_info = sw_event_timer_adapter_get_info,
+   .arm_burst = sw_event_timer_arm_burst,
+   .arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
+   .cancel_burst = sw_event_timer_cancel_burst,
+};
-- 
2.6.4



[dpdk-dev] [PATCH v6 01/23] eventtimer: add event timer adapter API

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/Makefile  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 566 ++
 lib/librte_eventdev/rte_eventdev.h|   4 +-
 3 files changed, 569 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 7fd78c7..685b474 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -27,6 +27,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 000..7d967e6
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,566 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 Cavium, Inc.
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *   timer_tick_ns
+ *   +
+ *  +---+|
+ *  |   ||
+ *  +---+ bkt 0 +v---+
+ *  |   |   ||
+ *  |   +---+|
+ *  +---+---++---+---+  +---+---+---+---+
+ *  |   ||   |  |   |   |   |   |
+ *  | bkt n || bkt 1 |<-> t0| t1| t2| tn|
+ *  |   ||   |  |   |   |   |   |
+ *  +---+---++---+---+  +---+---+---+---+
+ *  | Timer adapter  |
+ *  +---+---++---+---+
+ *  |   ||   |
+ *  | bkt 4 || bkt 2 |<--- Current bucket
+ *  |   ||   |
+ *  +---+---++---+---+
+ *   |  +---+   |
+ *   |  |   |   |
+ *   +--+ bkt 3 +---+
+ *  |   |
+ *  +---+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform depended external clock.
+ *
+ * - Application creates a timer adapter instance with given clock source,
+ *   the total number of event timers, resolution(expressed in ns) to traverse
+ *   between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). On timer adapter
+ *   start, the timer starts ticking at *timer_tick_ns* resolution.
+ *
+ * - Application arms an event timer to be expired at the number of
+ *   *timer_tick_ns* from now.
+ *
+ * - Application can cancel the existing armed timer if required.
+ *
+ * - If 

[dpdk-dev] [PATCH v6 04/23] test: add event timer adapter auto-test

2018-01-10 Thread Erik Gabriel Carrillo
Add initial infrastructure for event timer adapter auto-test.

Signed-off-by: Erik Gabriel Carrillo 
---
 test/test/Makefile   |   1 +
 test/test/test_event_timer_adapter.c | 177 +++
 2 files changed, 178 insertions(+)
 create mode 100644 test/test/test_event_timer_adapter.c

diff --git a/test/test/Makefile b/test/test/Makefile
index e7818dc..573e394 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -182,6 +182,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_EVENTDEV),y)
 SRCS-y += test_eventdev.c
 SRCS-y += test_event_ring.c
 SRCS-y += test_event_eth_rx_adapter.c
+SRCS-y += test_event_timer_adapter.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_SW_EVENTDEV) += test_eventdev_sw.c
 SRCS-$(CONFIG_RTE_LIBRTE_PMD_OCTEONTX_SSOVF) += test_eventdev_octeontx.c
 endif
diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
new file mode 100644
index 000..cbd206a
--- /dev/null
+++ b/test/test/test_event_timer_adapter.c
@@ -0,0 +1,177 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in
+ *   the documentation and/or other materials provided with the
+ *   distribution.
+ * * Neither the name of Intel Corporation nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "test.h"
+
+#define NB_TEST_EVENT_TIMERS   4
+#define NB_TEST_PORTS  1
+#define NB_TEST_QUEUES 1
+#define TEST_PORT_ID   0
+#define TEST_QUEUE_ID  0
+
+static int evdev;
+struct rte_mempool *g_event_timer_pool;
+
+static inline void
+devconf_set_test_values(struct rte_event_dev_config *dev_conf,
+ struct rte_event_dev_info *info)
+{
+   memset(dev_conf, 0, sizeof(struct rte_event_dev_config));
+   dev_conf->dequeue_timeout_ns = info->min_dequeue_timeout_ns;
+   dev_conf->nb_event_ports = NB_TEST_PORTS;
+   dev_conf->nb_event_queues = NB_TEST_QUEUES;
+   dev_conf->nb_event_queue_flows = info->max_event_queue_flows;
+   dev_conf->nb_event_port_dequeue_depth =
+   info->max_event_port_dequeue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_event_port_enqueue_depth =
+   info->max_event_port_enqueue_depth;
+   dev_conf->nb_events_limit =
+   info->max_num_events;
+}
+
+static int
+configure_event_dev(void)
+{
+   const char *eventdev_name = "event_sw0";
+   int ret;
+   struct rte_event_dev_config devconf;
+   struct rte_event_dev_info info;
+
+   evdev = rte_event_dev_get_dev_id(eventdev_name);
+   if (evdev < 0) {
+   if (rte_vdev_init(eventdev_name, NULL) < 0) {
+   printf("Error creating eventdev\n");
+   return TEST_FAILED;
+   }
+   evdev = rte_event_dev_get_dev_id(eventdev_name);
+   if (evdev < 0) {
+   printf("Error finding newly created eventdev\n");
+   return TEST_FAILED;
+   }
+   }
+
+   ret = rte_event_dev_info_get(evdev, &info);
+   TEST_ASSERT_SUCCESS(ret, "Failed to get event dev info");
+
+   devconf_set_test_values(&devconf, &info);
+
+   ret = rte_event_dev_configure(evdev, &

[dpdk-dev] [PATCH v6 08/23] eventtimer: add adapter start/stop definitions

2018-01-10 Thread Erik Gabriel Carrillo
Add definitions to the default software implementation for the functions
that start and stop adapter instances.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 19 +++
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 38f4dcf..27e6226 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -565,7 +565,18 @@ sw_event_timer_adapter_uninit(struct 
rte_event_timer_adapter *adapter)
 static int
 sw_event_timer_adapter_start(const struct rte_event_timer_adapter *adapter)
 {
-   RTE_SET_USED(adapter);
+   int ret;
+   struct rte_event_timer_adapter_sw_data *sw_data;
+
+   sw_data = adapter->data->adapter_priv;
+
+   ret = rte_service_component_runstate_set(sw_data->service_id, 1);
+   if (ret < 0)
+   return ret;
+
+   /* If no service core is mapped to the service, fail */
+   if (!rte_service_runstate_get(sw_data->service_id))
+   return -ENOENT;
 
return 0;
 }
@@ -573,9 +584,9 @@ sw_event_timer_adapter_start(const struct 
rte_event_timer_adapter *adapter)
 static int
 sw_event_timer_adapter_stop(const struct rte_event_timer_adapter *adapter)
 {
-   RTE_SET_USED(adapter);
-
-   return 0;
+   struct rte_event_timer_adapter_sw_data *sw_data;
+   sw_data = adapter->data->adapter_priv;
+   return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
 static void
-- 
2.6.4



[dpdk-dev] [PATCH v6 05/23] eventtimer: add adapter allocation definitions

2018-01-10 Thread Erik Gabriel Carrillo
Add definitions for the functions that allocate and deallocate adapter
instances in the default software implementation.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/Makefile  |   2 +-
 lib/librte_eventdev/Makefile  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 138 +-
 lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
 4 files changed, 139 insertions(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index 4202702..4c53f8c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool 
librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash 
librte_mempool
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index 8f11a79..e68f888 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -13,7 +13,7 @@ LIBABIVER := 3
 # build flags
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 540be95..9c4ba1c 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -31,11 +31,17 @@
  */
 
 #include 
+#include 
 
 #include 
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -163,6 +169,11 @@ rte_event_timer_adapter_create_ext(
 
adapter_id = conf->timer_adapter_id;
 
+   if (adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) {
+   rte_errno = -EINVAL;
+   return NULL;
+   }
+
/* Check adapter ID not already allocated */
adapter = &adapters[adapter_id];
if (adapter->allocated) {
@@ -412,18 +423,141 @@ rte_event_timer_cancel_burst(const struct 
rte_event_timer_adapter *adapter,
  * Software event timer adapter ops definitions
  */
 
+struct rte_event_timer_adapter_sw_data {
+   /* Number of outstanding timers managed by event adapter. */
+   int nb_armed_evtims;
+   /* Identifier of service executing timer management logic. */
+   uint32_t service_id;
+   /* Ring containing messages to arm or cancel event timers */
+   struct rte_ring *msg_ring;
+   /* Mempool containing msg objects */
+   struct rte_mempool *msg_pool;
+   /* Mempool containing timer objects */
+   struct rte_mempool *tim_pool;
+};
+
+enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
+
+struct msg {
+   enum msg_type type;
+   struct rte_event_timer *evtim;
+};
+
+static int
+sw_event_timer_adapter_service_func(void *arg)
+{
+   RTE_SET_USED(arg);
+   return 0;
+}
+
 static int
 sw_event_timer_adapter_init(struct rte_event_timer_adapter *adapter)
 {
-   RTE_SET_USED(adapter);
+   int ret;
+   struct rte_event_timer_adapter_sw_data *sw_data;
+   uint64_t nb_timers;
+   struct rte_service_spec service;
+
+   /* Allocate storage for SW implementation data */
+   char priv_data_name[RTE_RING_NAMESIZE];
+   snprintf(priv_data_name, RTE_RING_NAMESIZE, "sw_evtim_adap_priv_%"PRIu8,
+adapter->data->id);
+   adapter->data->adapter_priv = rte_zmalloc_socket(
+   priv_data_name,
+   sizeof(struct rte_event_timer_adapter_sw_data),
+   RTE_CACHE_LINE_SIZE,
+   adapter->data->socket_id);
+   if (adapter->data->adapter_priv == NULL) {
+   rte_errno = ENOMEM;
+   return -1;
+   }
+
+   sw_data = adapter->data->adapter_priv;
+
+   /* Rings require power of 2, so round up to next such value */
+   nb_timers = rte_align64pow2(adapter->data->conf.nb_timers);
+
+   char msg_ring_name[RTE_RING_NAMESIZE];
+   snprintf(msg_ring_name, RTE_RING_NAMESIZE,
+"sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+   sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
+   adapter->data->socket_id, 0);
+   if (sw_data->msg_ring == NULL) {
+   rte_errno = ENOMEM;
+   return -1;
+   }
+
+   char p

[dpdk-dev] [PATCH v6 07/23] eventtimer: add adapter get info function definition

2018-01-10 Thread Erik Gabriel Carrillo
Add a definition to the default software implementation for the entry
point that can fill out driver-specific information in the info struct.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 9c4ba1c..38f4dcf 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -582,8 +582,9 @@ static void
 sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
struct rte_event_timer_adapter_info *adapter_info)
 {
-   RTE_SET_USED(adapter);
-   RTE_SET_USED(adapter_info);
+   struct rte_event_timer_adapter_sw_data *sw_data;
+   sw_data = adapter->data->adapter_priv;
+   adapter_info->service_id = sw_data->service_id;
 }
 
 static int
-- 
2.6.4



[dpdk-dev] [PATCH v6 06/23] test: exercise event timer adapter allocation functions

2018-01-10 Thread Erik Gabriel Carrillo
Exercise the create and free functions in the event timer adapter
auto-test.

Signed-off-by: Erik Gabriel Carrillo 
---
 test/test/test_event_timer_adapter.c | 88 
 1 file changed, 88 insertions(+)

diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
index cbd206a..c8623aa 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -158,11 +158,99 @@ testsuite_teardown(void)
rte_mempool_free(g_event_timer_pool);
 }
 
+#define NSECPERSEC 1E9
+static int
+adapter_create_free(void)
+{
+   int adapter_id = 0;
+   uint32_t svc_start_count, svc_end_count;
+   struct rte_event_timer_adapter *adapters[
+   RTE_EVENT_TIMER_ADAPTER_NUM_MAX + 1];
+
+   struct rte_event_timer_adapter_conf conf = {
+   .event_dev_id = evdev + 1,  // invalid event dev id
+   .timer_adapter_id = adapter_id,
+   .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+   .timer_tick_ns = NSECPERSEC / 10,
+   .max_tmo_ns = 180 * NSECPERSEC,
+   .nb_timers = NB_TEST_EVENT_TIMERS,
+   .flags = 0,
+   };
+
+   svc_start_count = rte_service_get_count();
+
+   /* Test create */
+
+   /* Test invalid conf */
+   adapters[0] = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(adapters[0] == NULL, "Erroneously created adapter with "
+   "invalid event device id");
+   /* TODO: Should errno values be negative? */
+   TEST_ASSERT(rte_errno == -EINVAL, "Incorrect errno value for invalid "
+   "event device id");
+
+   /* Test valid conf */
+   conf.event_dev_id = evdev;
+   adapters[0] = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(adapters[0] != NULL, "Failed to create adapter with valid "
+   "configuration");
+
+   /* Test existing id */
+   adapters[1] = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(adapters[1] == NULL, "Erroneusly created adapter with "
+   "existing id");
+   TEST_ASSERT(rte_errno == -EEXIST, "Incorrect errno value for existing "
+   "id");
+
+   /* Test instance limit */
+   int i;
+   for (i = adapter_id + 1; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+   conf.timer_adapter_id = i;
+   adapters[i] = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(adapters[i] != NULL, "Failed to create adapter "
+   "with valid configuration");
+   }
+   conf.timer_adapter_id = i;
+   adapters[i] = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(adapters[i] == NULL, "Erroneously created excess adapters");
+
+   /* Check that at least RTE_EVENT_TIMER_ADAPTER_NUM_MAX services
+* have been created
+*/
+   svc_end_count = rte_service_get_count();
+   TEST_ASSERT(svc_end_count - svc_start_count ==
+   RTE_EVENT_TIMER_ADAPTER_NUM_MAX,
+   "Failed to create expected number of services");
+
+   /* Test free */
+
+   int ret;
+   for (i = 0; i < RTE_EVENT_TIMER_ADAPTER_NUM_MAX; i++) {
+   ret = rte_event_timer_adapter_free(adapters[i]);
+   TEST_ASSERT(ret == 0, "Failed to free adapter %d, ret = %d", i,
+   ret);
+   }
+
+   /* Test free of already freed adapter */
+   ret = rte_event_timer_adapter_free(adapters[0]);
+   TEST_ASSERT(ret < 0, "Erroneously freed adapter that was previously "
+   "freed");
+
+   /* Test free of null adapter */
+   adapters[0] = NULL;
+   ret = rte_event_timer_adapter_free(adapters[0]);
+   TEST_ASSERT(ret < 0, "Erroneously freed adapter that was previously "
+   "freed");
+
+   return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
.suite_name = "event timer adapter test suite",
.setup = testsuite_setup,
.teardown = testsuite_teardown,
.unit_test_cases = {
+   TEST_CASE(adapter_create_free),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
-- 
2.6.4



[dpdk-dev] [PATCH v6 11/23] test: exercise event timer adapter start/stop functions

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 test/test/test_event_timer_adapter.c | 77 +++-
 1 file changed, 76 insertions(+), 1 deletion(-)

diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
index c8623aa..58cbaba 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -49,8 +49,11 @@
 #define TEST_PORT_ID   0
 #define TEST_QUEUE_ID  0
 
+#define NSECPERSEC 1E9
+
 static int evdev;
 struct rte_mempool *g_event_timer_pool;
+struct rte_event_timer_adapter *g_adapter;
 
 static inline void
 devconf_set_test_values(struct rte_event_dev_config *dev_conf,
@@ -158,7 +161,33 @@ testsuite_teardown(void)
rte_mempool_free(g_event_timer_pool);
 }
 
-#define NSECPERSEC 1E9
+static int
+adapter_create(void)
+{
+   int adapter_id = 0;
+
+   struct rte_event_timer_adapter_conf conf = {
+   .event_dev_id = 0,
+   .timer_adapter_id = adapter_id,
+   .clk_src = RTE_EVENT_TIMER_ADAPTER_CPU_CLK,
+   .timer_tick_ns = NSECPERSEC / 10,
+   .max_tmo_ns = 180 * NSECPERSEC,
+   .nb_timers = NB_TEST_EVENT_TIMERS,
+   .flags = 0,
+   };
+
+   g_adapter = rte_event_timer_adapter_create(&conf);
+   TEST_ASSERT(g_adapter != NULL, "Failed to create event timer adapter");
+
+   return TEST_SUCCESS;
+}
+
+static void
+adapter_free(void)
+{
+   (void) rte_event_timer_adapter_free(g_adapter);
+}
+
 static int
 adapter_create_free(void)
 {
@@ -245,12 +274,58 @@ adapter_create_free(void)
return TEST_SUCCESS;
 }
 
+/* TODO: test multiple starts */
+static int
+adapter_start_stop(void)
+{
+   int ret;
+   uint32_t service_id;
+   struct rte_event_timer_adapter *l_adapter = NULL;
+
+   ret = rte_event_timer_adapter_start(l_adapter);
+   TEST_ASSERT(ret < 0, "Erroneously started null adapter, ret = %d", ret);
+
+   /* Check that we fail when no service core is mapped */
+   ret = rte_event_timer_adapter_start(g_adapter);
+   TEST_ASSERT(ret == -ENOENT, "Erroneously started adapter with no "
+   "service core mapped");
+
+   TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+  &service_id),
+   "Failed to get event timer adapter service id");
+
+   TEST_ASSERT(rte_service_lcore_count() > 0, "Need one or more service "
+   "cores to perform this test");
+
+   /* Could map using service_id, but just do default mapping */
+   ret = rte_service_start_with_defaults();
+   TEST_ASSERT(ret == 0, "Failed to start services");
+
+   ret = rte_event_timer_adapter_start(g_adapter);
+   TEST_ASSERT(ret == 0, "Failed to start adapter");
+
+   ret = rte_event_timer_adapter_start(g_adapter);
+   TEST_ASSERT(ret == 0, "Failed to repeatedly start adapter");
+
+   ret = rte_event_timer_adapter_stop(g_adapter);
+   TEST_ASSERT(ret == 0, "Failed to stop event adapter, ret = %d", ret);
+
+   ret = rte_event_timer_adapter_stop(l_adapter);
+   TEST_ASSERT(ret < 0, "Erroneously stopped event adapter, ret = %d",
+   ret);
+
+   rte_service_lcore_reset_all();
+
+   return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
.suite_name = "event timer adapter test suite",
.setup = testsuite_setup,
.teardown = testsuite_teardown,
.unit_test_cases = {
TEST_CASE(adapter_create_free),
+   TEST_CASE_ST(adapter_create, adapter_free, adapter_start_stop),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
-- 
2.6.4



[dpdk-dev] [PATCH v6 09/23] eventtimer: add API to get service id

2018-01-10 Thread Erik Gabriel Carrillo
When the event timer adapter uses a software implementation, timer
management is performed on a service core using a service registered at
the time of adapter creation.  This commit adds a helper function to get
the service id that can be used by an application to assign an lcore for
the service to run on.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 20 
 lib/librte_eventdev/rte_event_timer_adapter.h | 19 +++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h |  4 
 lib/librte_eventdev/rte_eventdev_version.map  |  1 +
 4 files changed, 44 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 27e6226..68748be 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -378,6 +378,23 @@ rte_event_timer_adapter_free(struct 
rte_event_timer_adapter *adapter)
 }
 
 int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+  uint32_t *service_id)
+{
+   ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+
+   if (service_id == NULL)
+   return -EINVAL;
+
+   if (adapter->data->service_inited) {
+   *service_id = adapter->data->service_id;
+   return 0;
+   }
+
+   return -ESRCH;
+}
+
+int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
  struct rte_event_timer **evtims,
  uint16_t nb_evtims)
@@ -521,6 +538,9 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter 
*adapter)
if (ret < 0)
return ret;
 
+   adapter->data->service_id = sw_data->service_id;
+   adapter->data->service_inited = 1;
+
return 0;
 }
 
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
index d1e4d18..84d3c39 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -402,6 +402,25 @@ struct rte_event_timer_adapter 
*rte_event_timer_adapter_lookup(
 int rte_event_timer_adapter_free(struct rte_event_timer_adapter *adapter);
 
 /**
+ * Retrieve the service ID of the event timer adapter. If the adapter doesn't
+ * use an rte_service function, this function returns -ESRCH.
+ *
+ * @param adapter
+ *   A pointer to an event timer adapter.
+ *
+ * @param [out] service_id
+ *   A pointer to a uint32_t, to be filled in with the service id.
+ *
+ * @return
+ *   - 0: Success
+ *   - <0: Error code on failure, if the event dev doesn't use a rte_service
+ *   function, this function returns -ESRCH.
+ */
+int
+rte_event_timer_adapter_service_id_get(struct rte_event_timer_adapter *adapter,
+  uint32_t *service_id);
+
+/**
  * @warning
  * @b EXPERIMENTAL: this structure may change without prior notice
  *
diff --git a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h 
b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
index 485fad1..6c65c36 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter_pmd.h
@@ -125,6 +125,10 @@ struct rte_event_timer_adapter_data {
/**< Adapter capabilities */
void *adapter_priv;
/**< Timer adapter private data*/
+   uint8_t service_inited;
+   /**< Service initialization state */
+   uint32_t service_id;
+   /**< Service ID*/
 
RTE_STD_C11
uint8_t started : 1;
diff --git a/lib/librte_eventdev/rte_eventdev_version.map 
b/lib/librte_eventdev/rte_eventdev_version.map
index f56ca0f..a35a668 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -75,6 +75,7 @@ DPDK_18.02 {
rte_event_timer_adapter_create_ext;
rte_event_timer_adapter_free;
rte_event_timer_adapter_get_info;
+   rte_event_timer_adapter_service_id_get;
rte_event_timer_adapter_start;
rte_event_timer_adapter_stop;
rte_event_timer_arm_burst;
-- 
2.6.4



[dpdk-dev] [PATCH v6 12/23] eventtimer: add event timer arm/cancel function definitions

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 lib/Makefile  |   2 +-
 lib/librte_eventdev/Makefile  |   2 +-
 lib/librte_eventdev/rte_event_timer_adapter.c | 155 +++---
 mk/rte.app.mk |   2 +-
 4 files changed, 141 insertions(+), 20 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index 4c53f8c..c2bee80 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -29,7 +29,7 @@ DEPDIRS-librte_security := librte_eal librte_mempool 
librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
 DEPDIRS-librte_security += librte_cryptodev
 DIRS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += librte_eventdev
-DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash 
librte_mempool
+DEPDIRS-librte_eventdev := librte_eal librte_ring librte_ether librte_hash 
librte_mempool librte_timer
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += librte_vhost
 DEPDIRS-librte_vhost := librte_eal librte_mempool librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash
diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index e68f888..6e95528 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -13,7 +13,7 @@ LIBABIVER := 3
 # build flags
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
-LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool
+LDLIBS += -lrte_eal -lrte_ring -lrte_ethdev -lrte_hash -lrte_mempool 
-lrte_timer
 
 # library source files
 SRCS-y += rte_eventdev.c
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index a4c8012..38e52cb 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -609,16 +609,91 @@ sw_event_timer_adapter_stop(const struct 
rte_event_timer_adapter *adapter)
return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
+static __rte_always_inline void
+swap(struct rte_event_timer **evtims, int i, int j)
+{
+   struct rte_event_timer *tmp;
+
+   tmp = evtims[i];
+   evtims[i] = evtims[j];
+   evtims[j] = tmp;
+}
+
+static __rte_always_inline int
+__sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
+  struct rte_event_timer **evtims,
+  uint16_t nb_evtims)
+{
+   int i, n, mark, nb_fails = 0;
+   int fails[nb_evtims];
+   struct rte_event_timer_adapter_sw_data *sw_data;
+   struct msg *msgs[nb_evtims];
+   struct rte_timer *tims[nb_evtims];
+
+   sw_data = adapter->data->adapter_priv;
+
+   n = rte_mempool_get_bulk(sw_data->msg_pool, (void **)msgs, nb_evtims);
+   if (n < 0) {
+   rte_errno = ENOMEM;
+   return 0;
+   }
+
+   n = rte_mempool_get_bulk(sw_data->tim_pool, (void **)tims, nb_evtims);
+   if (n < 0) {
+   rte_errno = ENOMEM;
+   return 0;
+   }
+
+   for (i = 0; i < nb_evtims; i++) {
+   rte_timer_init(tims[i]);
+   evtims[i]->impl_opaque[0] = (uintptr_t)tims[i];
+   evtims[i]->impl_opaque[1] = (uintptr_t)adapter;
+
+   msgs[i]->evtim = evtims[i];
+   msgs[i]->type = MSG_TYPE_ARM;
+   }
+
+   n = rte_ring_enqueue_burst(sw_data->msg_ring, (void **)msgs, nb_evtims,
+  NULL);
+   if (n < nb_evtims) {
+   rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
+nb_evtims - n);
+   rte_mempool_put_bulk(sw_data->tim_pool, (void **)&tims[n],
+nb_evtims - n);
+   }
+
+   for (i = 0; i < n; i++) {
+   /* Wait until state is updated */
+   while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+  evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
+   ;
+
+   /* Note any failures */
+   if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+   fails[nb_fails++] = i;
+   rte_errno = EINVAL;
+   }
+
+   /* TODO: handle the case of consecutive arm requests;  the
+* second request can erroneously see success from the first
+*/
+   }
+
+   /* Move the failures to the end of the array */
+   for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+   swap(evtims, fails[i], mark);
+
+   n = mark + 1;
+
+   return n;
+}
+
 static int
 sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 struct rte_event_timer **evtims,
 uint16_t nb_evtims)
 {
-   RTE_SET_USED(adapter);
-   RTE_SET_USED(evtims);
-   RTE_SET_USED(nb_evtims);
-
-   return 0;
+   return __sw_event_timer_arm

[dpdk-dev] [PATCH v6 10/23] eventtimer: remove service id entry from info structure

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 11 +--
 lib/librte_eventdev/rte_event_timer_adapter.h |  2 --
 2 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 68748be..a4c8012 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -609,15 +609,6 @@ sw_event_timer_adapter_stop(const struct 
rte_event_timer_adapter *adapter)
return rte_service_component_runstate_set(sw_data->service_id, 0);
 }
 
-static void
-sw_event_timer_adapter_get_info(const struct rte_event_timer_adapter *adapter,
-   struct rte_event_timer_adapter_info *adapter_info)
-{
-   struct rte_event_timer_adapter_sw_data *sw_data;
-   sw_data = adapter->data->adapter_priv;
-   adapter_info->service_id = sw_data->service_id;
-}
-
 static int
 sw_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
 struct rte_event_timer **evtims,
@@ -661,7 +652,7 @@ const struct rte_event_timer_adapter_ops 
sw_event_adapter_timer_ops = {
.uninit = sw_event_timer_adapter_uninit,
.start = sw_event_timer_adapter_start,
.stop = sw_event_timer_adapter_stop,
-   .get_info = sw_event_timer_adapter_get_info,
+   .get_info = NULL,
.arm_burst = sw_event_timer_arm_burst,
.arm_tmo_tick_burst = sw_event_timer_arm_tmo_tick_burst,
.cancel_burst = sw_event_timer_cancel_burst,
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
index 84d3c39..8d29cfc 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -283,8 +283,6 @@ struct rte_event_timer_adapter_info {
/**< Event timer adapter capabilities */
int16_t event_dev_port_id;
/**< Event device port ID, if applicable */
-   int32_t service_id;
-   /**< Service ID, if applicable */
 };
 
 /**
-- 
2.6.4



[dpdk-dev] [PATCH v6 13/23] eventtimer: add adapter service definition

2018-01-10 Thread Erik Gabriel Carrillo
Define the callback function for the service that corresponds to an
adapter instance, as well as the callback for expired timers that the
service manages.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 198 +-
 lib/librte_eventdev/rte_event_timer_adapter.h |   2 +-
 2 files changed, 198 insertions(+), 2 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 38e52cb..0266ad5 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -40,8 +40,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 
 #include "rte_eventdev.h"
 #include "rte_eventdev_pmd.h"
@@ -460,10 +462,198 @@ struct msg {
struct rte_event_timer *evtim;
 };
 
+static void
+sw_event_timer_cb(struct rte_timer *tim, void *arg)
+{
+   uint16_t n;
+   struct rte_event_timer *evtim;
+   struct rte_event_timer_adapter *adapter;
+   struct rte_event_timer_adapter_sw_data *sw_data;
+
+   evtim = arg;
+   adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
+   sw_data = adapter->data->adapter_priv;
+
+   n = rte_event_enqueue_burst(adapter->data->event_dev_id,
+   adapter->data->event_port_id,
+   &evtim->ev,
+   1);
+   if (n != 1 && rte_errno == -ENOSPC) {
+   /* If we couldn't enqueue because the event port was
+* backpressured, put the timer back in the skiplist with an
+* immediate expiry value so we can process it again on the
+* next iteration.
+*/
+   rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
+sw_event_timer_cb, evtim);
+   } else {
+   sw_data->nb_armed_evtims--;
+   rte_wmb();
+   evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+   rte_mempool_put(sw_data->tim_pool, (void **)&tim);
+   }
+}
+
+static __rte_always_inline uint64_t
+get_timeout_cycles(struct rte_event_timer *evtim,
+  struct rte_event_timer_adapter *adapter)
+{
+   uint64_t timeout_ns;
+
+   timeout_ns = evtim->timeout_ticks * adapter->data->conf.timer_tick_ns;
+#define NSECPERSEC 1E9
+   return timeout_ns * rte_get_timer_hz() / NSECPERSEC;
+
+}
+
+/* Check that event timer timeout value is in range */
+static __rte_always_inline int
+check_timeout(struct rte_event_timer *evtim,
+ const struct rte_event_timer_adapter *adapter)
+{
+   uint64_t tmo_nsec = evtim->timeout_ticks *
+   adapter->data->conf.timer_tick_ns;
+
+   return  (tmo_nsec > adapter->data->conf.max_tmo_ns) ? -1
+   : (tmo_nsec < adapter->data->conf.timer_tick_ns) ? -2
+   : 0;
+}
+
+/* Check that event timer event queue sched type matches destination event 
queue
+ * sched type
+ */
+static __rte_always_inline int
+check_destination_event_queue(struct rte_event_timer *evtim,
+ const struct rte_event_timer_adapter *adapter)
+{
+   int ret;
+   uint32_t sched_type;
+
+   ret = rte_event_queue_attr_get(adapter->data->event_dev_id,
+  evtim->ev.queue_id,
+  RTE_EVENT_QUEUE_ATTR_SCHEDULE_TYPE,
+  &sched_type);
+
+   if (ret < 0 || evtim->ev.sched_type != sched_type)
+   return -1;
+
+   return 0;
+}
+
+/* We can't correctly block on the state of a timer that is currently armed,
+ * so disallow it.
+ */
+static __rte_always_inline int
+check_state_for_arm(struct rte_event_timer *evtim)
+{
+   return evtim->state != RTE_EVENT_TIMER_ARMED ? 0 : -1;
+}
+
+static inline int
+validate_event_timer(struct rte_event_timer *evtim,
+struct rte_event_timer_adapter *adapter)
+{
+   int ret;
+
+   if (check_state_for_arm(evtim) < 0) {
+   evtim->state = RTE_EVENT_TIMER_ERROR;
+   return -1;
+   }
+
+   ret = check_timeout(evtim, adapter);
+   switch (ret) {
+   case -1:
+   evtim->state = RTE_EVENT_TIMER_ERROR_TOOLATE;
+   return -1;
+   case -2:
+   evtim->state = RTE_EVENT_TIMER_ERROR_TOOEARLY;
+   return -1;
+   }
+
+   if (check_destination_event_queue(evtim, adapter) < 0) {
+   evtim->state = RTE_EVENT_TIMER_ERROR;
+   return -1;
+   }
+
+   return 0;
+}
+
+
+#define NB_OBJS 32
 static int
 sw_event_timer_adapter_service_func(void *arg)
 {
-   RTE_SET_USED(arg);
+   int i, num_msgs, ret;
+ 

[dpdk-dev] [PATCH v6 14/23] eventtimer: add event timer initializer function

2018-01-10 Thread Erik Gabriel Carrillo
Add a function that can be used to initialize event timers so that they
are in a known state before being used for arm or cancel operations.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c |  8 
 lib/librte_eventdev/rte_event_timer_adapter.h | 11 +++
 lib/librte_eventdev/rte_eventdev_version.map  |  1 +
 3 files changed, 20 insertions(+)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 0266ad5..8bd9ebc 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -396,6 +396,14 @@ rte_event_timer_adapter_service_id_get(struct 
rte_event_timer_adapter *adapter,
return -ESRCH;
 }
 
+void
+rte_event_timer_init(struct rte_event_timer *evtim)
+{
+   evtim->ev.op = RTE_EVENT_OP_NEW;
+   evtim->ev.event_type = RTE_EVENT_TYPE_TIMER;
+   evtim->state = RTE_EVENT_TIMER_NOT_ARMED;
+}
+
 int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
  struct rte_event_timer **evtims,
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
index bbbe7b9..3488488 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -484,6 +484,17 @@ struct rte_event_timer {
  * @warning
  * @b EXPERIMENTAL: this API may change without prior notice
  *
+ * Set an event timer's initial state and initialize the event it carries.
+ *
+ * @param evtim
+ *   A pointer to an event timer structure.
+ */
+void rte_event_timer_init(struct rte_event_timer *evtim);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
  * Arm a burst of event timers with separate expiration timeout tick for each
  * event timer.
  *
diff --git a/lib/librte_eventdev/rte_eventdev_version.map 
b/lib/librte_eventdev/rte_eventdev_version.map
index a35a668..c4bc946 100644
--- a/lib/librte_eventdev/rte_eventdev_version.map
+++ b/lib/librte_eventdev/rte_eventdev_version.map
@@ -78,6 +78,7 @@ DPDK_18.02 {
rte_event_timer_adapter_service_id_get;
rte_event_timer_adapter_start;
rte_event_timer_adapter_stop;
+   rte_event_timer_init;
rte_event_timer_arm_burst;
rte_event_timer_arm_tmo_tick_burst;
rte_event_timer_cancel_burst;
-- 
2.6.4



[dpdk-dev] [PATCH v6 16/23] eventtimer: add stats to API

2018-01-10 Thread Erik Gabriel Carrillo
Add interfaces to support the collection, retrieval and resetting of
per-adapter statistics.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 79 +++
 lib/librte_eventdev/rte_event_timer_adapter.h | 51 +++
 lib/librte_eventdev/rte_event_timer_adapter_pmd.h | 11 
 lib/librte_eventdev/rte_eventdev_version.map  |  2 +
 4 files changed, 130 insertions(+), 13 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 176cc5b..ebc6124 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -405,6 +405,26 @@ rte_event_timer_init(struct rte_event_timer *evtim)
 }
 
 int
+rte_event_timer_adapter_stats_get(struct rte_event_timer_adapter *adapter,
+ struct rte_event_timer_adapter_stats *stats)
+{
+   ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+   FUNC_PTR_OR_ERR_RET(adapter->ops->stats_get, -EINVAL);
+   if (stats == NULL)
+   return -EINVAL;
+
+   return adapter->ops->stats_get(adapter, stats);
+}
+
+int
+rte_event_timer_adapter_stats_reset(struct rte_event_timer_adapter *adapter)
+{
+   ADAPTER_VALID_OR_ERR_RET(adapter, -EINVAL);
+   FUNC_PTR_OR_ERR_RET(adapter->ops->stats_reset, -EINVAL);
+   return adapter->ops->stats_reset(adapter);
+}
+
+int
 rte_event_timer_arm_burst(const struct rte_event_timer_adapter *adapter,
  struct rte_event_timer **evtims,
  uint16_t nb_evtims)
@@ -503,7 +523,8 @@ event_buffer_add(struct event_buffer *bufp, struct 
rte_event *eventp)
 
 static void
 event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
-  uint16_t *nb_events_flushed)
+  uint16_t *nb_events_flushed,
+  uint16_t *nb_events_inv)
 {
uint16_t n = 0;
uint16_t *headp = &bufp->head;
@@ -519,17 +540,19 @@ event_buffer_flush(struct event_buffer *bufp, uint8_t 
dev_id, uint8_t port_id,
return;
}
 
+   *nb_events_inv = 0;
*nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
 &events[*headp], n);
if (*nb_events_flushed != n && rte_errno == -EINVAL) {
/* We must have hit a bad event...skip it to ensure we don't
 * hang on it.
 */
-   (*nb_events_flushed)++;
+   nb_events_inv++;
}
 
-   *headp = (*headp + *nb_events_flushed) % EVENT_BUFFER_SZ;
-   bufp->count -= *nb_events_flushed;
+   *headp = (*headp + *nb_events_flushed + *nb_events_inv) %
+   EVENT_BUFFER_SZ;
+   bufp->count -= (*nb_events_flushed + *nb_events_inv);
 }
 
 /*
@@ -549,6 +572,8 @@ struct rte_event_timer_adapter_sw_data {
struct rte_mempool *tim_pool;
/* Buffered timer expiry events to be enqueued to an event device. */
struct event_buffer buffer;
+   /* Statistics */
+   struct rte_event_timer_adapter_stats stats;
 };
 
 enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
@@ -561,7 +586,7 @@ struct msg {
 static void
 sw_event_timer_cb(struct rte_timer *tim, void *arg)
 {
-   uint16_t nb_evs_flushed;
+   uint16_t nb_evs_flushed, nb_evs_invalid;
int ret;
struct rte_event_timer *evtim;
struct rte_event_timer_adapter *adapter;
@@ -579,6 +604,8 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
 */
rte_timer_reset_sync(tim, SINGLE, 0, rte_lcore_id(),
 sw_event_timer_cb, evtim);
+
+   sw_data->stats.evtim_retry_count++;
} else {
sw_data->nb_armed_evtims--;
rte_wmb();
@@ -590,7 +617,11 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
event_buffer_flush(&sw_data->buffer,
   adapter->data->event_dev_id,
   adapter->data->event_port_id,
-  &nb_evs_flushed);
+  &nb_evs_flushed,
+  &nb_evs_invalid);
+
+   sw_data->stats.ev_enq_count += nb_evs_flushed;
+   sw_data->stats.ev_inv_count += nb_evs_invalid;
}
 }
 
@@ -683,9 +714,9 @@ validate_event_timer(struct rte_event_timer *evtim,
 static int
 sw_event_timer_adapter_service_func(void *arg)
 {
-   int i, num_msgs, ret;
+   int i, num_msgs;
uint64_t cycles;
-   uint16_t nb_events;
+   uint16_t nb_evs_flushed, nb_evs_invalid;
struct rte_event_timer_adapter *adapter;
struct rte_event_timer_adapter_sw_data *sw_data;
struct rte_event_timer *evtim = NU

[dpdk-dev] [PATCH v6 17/23] eventtimer: add support for single-producer put mode

2018-01-10 Thread Erik Gabriel Carrillo
Add support for the RTE_EVENT_TIMER_ADAPTER_F_SP_PUT flag, which indicates
that the API should be used in single-producer put mode.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 13 ++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index ebc6124..0af68b2 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -798,6 +798,7 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter 
*adapter)
int ret;
struct rte_event_timer_adapter_sw_data *sw_data;
uint64_t nb_timers;
+   unsigned int flags;
struct rte_service_spec service;
static bool timer_subsystem_inited; // static initialized to false
 
@@ -823,8 +824,11 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter 
*adapter)
char msg_ring_name[RTE_RING_NAMESIZE];
snprintf(msg_ring_name, RTE_RING_NAMESIZE,
 "sw_evtim_adap_msg_ring_%"PRIu8, adapter->data->id);
+   flags = adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT ?
+   RING_F_SP_ENQ | RING_F_SC_DEQ :
+   RING_F_SC_DEQ;
sw_data->msg_ring = rte_ring_create(msg_ring_name, nb_timers,
-   adapter->data->socket_id, 0);
+   adapter->data->socket_id, flags);
if (sw_data->msg_ring == NULL) {
rte_errno = ENOMEM;
return -1;
@@ -833,10 +837,13 @@ sw_event_timer_adapter_init(struct 
rte_event_timer_adapter *adapter)
char pool_name[RTE_RING_NAMESIZE];
snprintf(pool_name, RTE_RING_NAMESIZE, "sw_evtim_adap_msg_pool_%"PRIu8,
 adapter->data->id);
+   flags = (adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_SP_PUT) ?
+MEMPOOL_F_SP_PUT | MEMPOOL_F_SC_GET :
+MEMPOOL_F_SC_GET;
sw_data->msg_pool = rte_mempool_create(pool_name, nb_timers,
   sizeof(struct msg), 32, 0, NULL,
   NULL, NULL, NULL,
-  adapter->data->socket_id, 0);
+  adapter->data->socket_id, flags);
if (sw_data->msg_pool == NULL) {
rte_errno = ENOMEM;
return -1;
@@ -847,7 +854,7 @@ sw_event_timer_adapter_init(struct rte_event_timer_adapter 
*adapter)
sw_data->tim_pool = rte_mempool_create(pool_name, nb_timers,
   sizeof(struct rte_timer), 32, 0,
   NULL, NULL, NULL, NULL,
-  adapter->data->socket_id, 0);
+  adapter->data->socket_id, flags);
if (sw_data->tim_pool == NULL) {
printf("Could not allocate tim mempool\n");
return -1;
-- 
2.6.4



[dpdk-dev] [PATCH v6 18/23] eventtimer: add non-blocking mode for event timer operations

2018-01-10 Thread Erik Gabriel Carrillo
Add a mode to the event timer adapter that allows the event timer arm
and cancel APIs to return immediately, rather than waiting for the service
to update the state of each timer.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 69 ++-
 lib/librte_eventdev/rte_event_timer_adapter.h |  6 +++
 2 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 0af68b2..624cc36 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -1022,28 +1022,31 @@ __sw_event_timer_arm_burst(const struct 
rte_event_timer_adapter *adapter,
 nb_evtims - n);
}
 
-   for (i = 0; i < n; i++) {
-   /* Wait until state is updated */
-   while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
-  evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
-   ;
-
-   /* Note any failures */
-   if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
-   fails[nb_fails++] = i;
-   rte_errno = EINVAL;
-   }
+   if (!(adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_NB_ARM)) {
+   for (i = 0; i < n; i++) {
+   /* Wait until state is updated */
+   while (evtims[i]->state == RTE_EVENT_TIMER_NOT_ARMED ||
+  evtims[i]->state == RTE_EVENT_TIMER_CANCELED)
+   ;
+
+   /* Note any failures */
+   if (evtims[i]->state != RTE_EVENT_TIMER_ARMED) {
+   fails[nb_fails++] = i;
+   rte_errno = EINVAL;
+   }
 
-   /* TODO: handle the case of consecutive arm requests;  the
-* second request can erroneously see success from the first
-*/
-   }
+   /* TODO: handle the case of consecutive arm requests;
+* the second request can erroneously see success from
+* the first
+*/
+   }
 
-   /* Move the failures to the end of the array */
-   for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
-   swap(evtims, fails[i], mark);
+   /* Move the failures to the end of the array */
+   for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+   swap(evtims, fails[i], mark);
 
-   n = mark + 1;
+   n = mark + 1;
+   }
 
return n;
 }
@@ -1093,23 +1096,25 @@ sw_event_timer_cancel_burst(const struct 
rte_event_timer_adapter *adapter,
rte_mempool_put_bulk(sw_data->msg_pool, (void **)&msgs[n],
 nb_evtims - n);
 
-   for (i = 0; i < n; i++) {
-   /* Wait until state is updated */
-   while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
-   ;
+   if (!(adapter->data->conf.flags & RTE_EVENT_TIMER_ADAPTER_F_NB_ARM)) {
+   for (i = 0; i < n; i++) {
+   /* Wait until state is updated */
+   while (evtims[i]->state == RTE_EVENT_TIMER_ARMED)
+   ;
 
-   /* Note any failures */
-   if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
-   fails[nb_fails++] = i;
-   rte_errno = EINVAL;
+   /* Note any failures */
+   if (evtims[i]->state != RTE_EVENT_TIMER_CANCELED) {
+   fails[nb_fails++] = i;
+   rte_errno = EINVAL;
+   }
}
-   }
 
-   /* Move the failures to the end of the array */
-   for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
-   swap(evtims, fails[i], mark);
+   /* Move the failures to the end of the array */
+   for (i = 0, mark = n - 1; i < nb_fails; i++, mark--)
+   swap(evtims, fails[i], mark);
 
-   n = mark + 1;
+   n = mark + 1;
+   }
 
return n;
 }
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
index a4b16a7..2a69455 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.h
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -175,6 +175,12 @@ enum rte_event_timer_adapter_clk_src {
  *
  * @see struct rte_event_timer_adapter_conf::flags
  */
+#define RTE_EVENT_TIMER_ADAPTER_F_NB_ARM   (1ULL << 2)
+/**< ``rte_event_timer_arm_burst()`` API to be used in non-blocking/
+ * asynchronous mode
+ *
+ * @see struct rte_event_timer_adapter_conf::flags
+ */
 
 /**
  * @warning
-- 
2.6.4



[dpdk-dev] [PATCH v6 20/23] maintainers: add event timer adapter section

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 MAINTAINERS | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b51c2d0..55581c8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -291,6 +291,12 @@ F: lib/librte_eventdev/*eth_rx_adapter*
 F: test/test/test_event_eth_rx_adapter.c
 F: doc/guides/prog_guide/event_ethernet_rx_adapter.rst
 
+Eventdev Timer Adapter API - EXPERIMENTAL
+M: Erik Gabriel Carrillo 
+T: git://dpdk.org/next/dpdk-next-eventdev
+F: lib/librte_eventdev/*timer_adapter*
+F: test/test/test_event_timer_adapter.c
+F: doc/guides/prog_guide/event_timer_adapter.rst
 
 Bus Drivers
 ---
-- 
2.6.4



[dpdk-dev] [PATCH v6 19/23] test: exercise event timer arm and expiry

2018-01-10 Thread Erik Gabriel Carrillo
Add a test that creates an event timer and detects the generation of a
timer expiry event being scheduled through the software event device.

Signed-off-by: Erik Gabriel Carrillo 
---
 test/test/test_event_timer_adapter.c | 106 +++
 1 file changed, 106 insertions(+)

diff --git a/test/test/test_event_timer_adapter.c 
b/test/test/test_event_timer_adapter.c
index 58cbaba..3a16cce 100644
--- a/test/test/test_event_timer_adapter.c
+++ b/test/test/test_event_timer_adapter.c
@@ -319,6 +319,111 @@ adapter_start_stop(void)
return TEST_SUCCESS;
 }
 
+#define BATCH_SIZE 16
+static int
+event_timer_expiry(void)
+{
+   uint16_t n;
+   uint32_t evdev_service_id, adapter_service_id;
+   int ret;
+   struct rte_event_timer_adapter *adapter = g_adapter;
+   struct rte_event_timer *evtim = NULL;
+   struct rte_event_timer *evtim2 = NULL;
+   struct rte_event evs[BATCH_SIZE];
+
+   TEST_ASSERT_SUCCESS(rte_event_dev_service_id_get(evdev,
+   &evdev_service_id), "Failed to get "
+   "event device service id");
+
+   TEST_ASSERT(rte_service_lcore_count() > 0, "Need one or more service "
+   "cores to perform this test");
+
+   TEST_ASSERT_SUCCESS(rte_event_timer_adapter_service_id_get(g_adapter,
+   &adapter_service_id), "Failed to get "
+   "event timer adapter service id");
+
+   /* Could map using service_id, but just do default mapping */
+   ret = rte_service_start_with_defaults();
+   TEST_ASSERT_SUCCESS(ret, "Failed to start services");
+
+   if (rte_event_dev_start(evdev) < 0) {
+   printf("Failed to start event device\n");
+   return TEST_FAILED;
+   }
+
+   ret = rte_event_timer_adapter_start(adapter);
+   if (ret < 0) {
+   printf("Failed to start adapter\n");
+   return TEST_FAILED;
+   }
+
+   /* Set up an event timer */
+   rte_mempool_get(g_event_timer_pool, (void **)&evtim);
+   if (evtim == NULL) {
+   /* Failed to get an event timer object */
+   return TEST_FAILED;
+   }
+
+   rte_event_timer_init(evtim);
+
+   evtim->ev.event_ptr = evtim;
+   evtim->ev.queue_id = TEST_QUEUE_ID;
+   evtim->ev.sched_type = RTE_SCHED_TYPE_ATOMIC;
+   evtim->timeout_ticks = 30;  // expire in 3 sec
+
+   ret = rte_event_timer_arm_burst(adapter, &evtim, 1);
+   if (ret != 1) {
+   printf("Failed to arm event timer: %s\n",
+  rte_strerror(rte_errno));
+   return TEST_FAILED;
+   }
+
+   rte_delay_ms(2999);
+
+   n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+   TEST_ASSERT_EQUAL(n, 0, "Dequeued unexpected timer expiry event");
+
+   /* Delay 1 more millisecond and run the services again - should let us
+* dequeue one event
+*/
+   rte_delay_ms(1);
+
+   n = rte_event_dequeue_burst(evdev, TEST_PORT_ID, evs, RTE_DIM(evs), 0);
+   if (n == 0) {
+   printf("Failed to dequeue timer expiry event\n");
+   return TEST_FAILED;
+   }
+
+   if (n > 1) {
+   printf("Dequeued incorrect number (%d) of timer expiry "
+  "events\n", n);
+   return TEST_FAILED;
+   }
+
+   if (evs[0].event_type != RTE_EVENT_TYPE_TIMER) {
+   printf("Dequeued unexpected type of event\n");
+   return TEST_FAILED;
+   }
+
+   /* Check that we recover the original event timer and then free it */
+   evtim2 = evs[0].event_ptr;
+   TEST_ASSERT_EQUAL(evtim, evtim2,
+ "Failed to recover pointer to original event timer");
+   rte_mempool_put(g_event_timer_pool, evtim2);
+
+   ret = rte_event_timer_adapter_stop(adapter);
+   if (ret < 0) {
+   printf("Failed to stop event adapter\n");
+   return TEST_FAILED;
+   }
+
+   rte_event_dev_stop(evdev);
+
+   rte_service_lcore_reset_all();
+
+   return TEST_SUCCESS;
+}
+
 static struct unit_test_suite adapter_tests  = {
.suite_name = "event timer adapter test suite",
.setup = testsuite_setup,
@@ -326,6 +431,7 @@ static struct unit_test_suite adapter_tests  = {
.unit_test_cases = {
TEST_CASE(adapter_create_free),
TEST_CASE_ST(adapter_create, adapter_free, adapter_start_stop),
+   TEST_CASE_ST(adapter_create, adapter_free, event_timer_expiry),
TEST_CASES_END() /**< NULL terminate unit test array */
}
 };
-- 
2.6.4



[dpdk-dev] [PATCH v6 15/23] eventtimer: add buffering of timer expiry events

2018-01-10 Thread Erik Gabriel Carrillo
Buffer timer expiry events generated while walking a "run list"
in rte_timer_manage, and burst enqueue them to an event device
to the extent possible.

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/rte_event_timer_adapter.c | 118 +++---
 1 file changed, 108 insertions(+), 10 deletions(-)

diff --git a/lib/librte_eventdev/rte_event_timer_adapter.c 
b/lib/librte_eventdev/rte_event_timer_adapter.c
index 8bd9ebc..176cc5b 100644
--- a/lib/librte_eventdev/rte_event_timer_adapter.c
+++ b/lib/librte_eventdev/rte_event_timer_adapter.c
@@ -447,7 +447,93 @@ rte_event_timer_cancel_burst(const struct 
rte_event_timer_adapter *adapter,
 }
 
 /*
- * Software event timer adapter ops definitions
+ * Software event timer adapter buffer helper functions
+ */
+
+#define EVENT_BUFFER_SZ 1024
+#if EVENT_BUFFER_SZ < 1 || EVENT_BUFFER_SZ > 65536
+#error "EVENT_BUFFER_SZ must be between 1 and 65536"
+#endif
+
+#define EVENT_BUFFER_BATCHSZ 32
+
+struct event_buffer {
+   uint16_t head;
+   uint16_t tail;
+   uint16_t count;
+   struct rte_event events[EVENT_BUFFER_SZ];
+} __rte_cache_aligned;
+
+static inline bool
+event_buffer_full(struct event_buffer *bufp)
+{
+   return (bufp->tail + 1) % EVENT_BUFFER_SZ == bufp->head;
+}
+
+static inline bool
+event_buffer_batch_ready(struct event_buffer *bufp)
+{
+   return bufp->count >= EVENT_BUFFER_BATCHSZ;
+}
+
+static void
+event_buffer_init(struct event_buffer *bufp)
+{
+   bufp->head = bufp->tail = bufp->count = 0;
+   memset(&bufp->events, 0, sizeof(struct rte_event) * EVENT_BUFFER_SZ);
+}
+
+static int
+event_buffer_add(struct event_buffer *bufp, struct rte_event *eventp)
+{
+   uint16_t *tailp = &bufp->tail;
+   struct rte_event *buf_eventp;
+
+   if (event_buffer_full(bufp))
+   return -1;
+
+   buf_eventp = &bufp->events[*tailp];
+   rte_memcpy(buf_eventp, eventp, sizeof(struct rte_event));
+
+   *tailp = (*tailp + 1) % EVENT_BUFFER_SZ;
+   bufp->count++;
+
+   return 0;
+}
+
+static void
+event_buffer_flush(struct event_buffer *bufp, uint8_t dev_id, uint8_t port_id,
+  uint16_t *nb_events_flushed)
+{
+   uint16_t n = 0;
+   uint16_t *headp = &bufp->head;
+   uint16_t *tailp = &bufp->tail;
+   struct rte_event *events = bufp->events;
+
+   if (*tailp > *headp)
+   n = *tailp - *headp;
+   else if (*tailp < *headp)
+   n = EVENT_BUFFER_SZ - *headp;
+   else {  /* buffer empty */
+   *nb_events_flushed = 0;
+   return;
+   }
+
+   *nb_events_flushed = rte_event_enqueue_burst(dev_id, port_id,
+&events[*headp], n);
+   if (*nb_events_flushed != n && rte_errno == -EINVAL) {
+   /* We must have hit a bad event...skip it to ensure we don't
+* hang on it.
+*/
+   (*nb_events_flushed)++;
+   }
+
+   *headp = (*headp + *nb_events_flushed) % EVENT_BUFFER_SZ;
+   bufp->count -= *nb_events_flushed;
+}
+
+/*
+ * Software event timer adapter implementation
  */
 
 struct rte_event_timer_adapter_sw_data {
@@ -461,6 +547,8 @@ struct rte_event_timer_adapter_sw_data {
struct rte_mempool *msg_pool;
/* Mempool containing timer objects */
struct rte_mempool *tim_pool;
+   /* Buffered timer expiry events to be enqueued to an event device. */
+   struct event_buffer buffer;
 };
 
 enum msg_type {MSG_TYPE_ARM, MSG_TYPE_CANCEL};
@@ -473,7 +561,8 @@ struct msg {
 static void
 sw_event_timer_cb(struct rte_timer *tim, void *arg)
 {
-   uint16_t n;
+   uint16_t nb_evs_flushed;
+   int ret;
struct rte_event_timer *evtim;
struct rte_event_timer_adapter *adapter;
struct rte_event_timer_adapter_sw_data *sw_data;
@@ -482,14 +571,10 @@ sw_event_timer_cb(struct rte_timer *tim, void *arg)
adapter = (struct rte_event_timer_adapter *)evtim->impl_opaque[1];
sw_data = adapter->data->adapter_priv;
 
-   n = rte_event_enqueue_burst(adapter->data->event_dev_id,
-   adapter->data->event_port_id,
-   &evtim->ev,
-   1);
-   if (n != 1 && rte_errno == -ENOSPC) {
-   /* If we couldn't enqueue because the event port was
-* backpressured, put the timer back in the skiplist with an
-* immediate expiry value so we can process it again on the
+   ret = event_buffer_add(&sw_data->buffer, &evtim->ev);
+   if (ret < 0) {
+   /* If event buffer is full, put timer back in list with
+* immediate expiry value, so that we process it again on the
 * next

[dpdk-dev] [PATCH v6 22/23] doc: add event timer adapter section to programmer's guide

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 doc/guides/prog_guide/event_timer_adapter.rst | 301 ++
 doc/guides/prog_guide/index.rst   |   1 +
 2 files changed, 302 insertions(+)
 create mode 100644 doc/guides/prog_guide/event_timer_adapter.rst

diff --git a/doc/guides/prog_guide/event_timer_adapter.rst 
b/doc/guides/prog_guide/event_timer_adapter.rst
new file mode 100644
index 000..47418a2
--- /dev/null
+++ b/doc/guides/prog_guide/event_timer_adapter.rst
@@ -0,0 +1,301 @@
+..  BSD LICENSE
+Copyright(c) 2017 Intel Corporation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in
+the documentation and/or other materials provided with the
+distribution.
+* Neither the name of Intel Corporation nor the names of its
+contributors may be used to endorse or promote products derived
+from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Event Timer Adapter Library
+=
+
+The DPDK
+`Event Device library <http://dpdk.org/doc/guides/prog_guide/eventdev.html>`_
+introduces an event driven programming model which presents applications with
+an alternative to the polling model traditionally used in DPDK
+applications. Event devices can be coupled with arbitrary components to provide
+new event sources by using **event adapters**. The Event Timer Adapter is one
+such adapter; it bridges event devices and timer mechanisms.
+
+The Event Timer Adapter library extends the event driven model
+by introducing a :ref:`new type of event ` that represents
+a timer expiration, and providing an API with which adapters can be created or
+destroyed, and :ref:`event timers ` can be armed and canceled.
+
+The Event Timer Adapter library is designed to interface with hardware or
+software implementations of the timer mechanism; it will query an eventdev PMD
+to determine which implementation should be used.  The default software
+implementation manages timers using the DPDK
+`Timer library <http://dpdk.org/doc/guides/prog_guide/timer_lib.html>`_.
+
+Examples of using the API are presented in the `API Overview`_ and
+`Processing Timer Expiry Events`_ sections.  Code samples are abstracted and
+are based on the example of handling a TCP retransmission.
+
+.. _event_timer:
+
+Event Timer struct
+--
+Event timers are timers that enqueue a timer expiration event to an event
+device upon firing.
+
+The Event Timer Adapter API represents each event timer with a generic struct,
+which contains an event and user metadata.  The ``rte_event_timer`` struct is
+defined in ``lib/librte_event/librte_event_timer_adapter.h``.
+
+.. _timer_expiry_event:
+
+Timer Expiry Event
+~~
+
+The event contained by an event timer is enqueued in the event device when the
+timer expires, and the event device uses the attributes below when scheduling
+it:
+
+* ``event_queue_id`` - Application should set this to specify an event queue to
+  which the timer expiry event should be enqueued
+* ``event_priority`` - Application can set this to indicate the priority of the
+  timer expiry event in the event queue relative to other events
+* ``sched_type`` - Application can set this to specify the scheduling type of
+  the timer expiry event
+* ``flow_id`` - Application can set this to indicate which flow this timer
+  expiry event corresponds to
+* ``op`` - Will be set to ``RTE_EVENT_OP_NEW`` by the event timer adapter
+* ``event_type`` - Will be set to ``RTE_EVENT_TYPE_TIMER`` by the event timer
+  adapter
+
+Timeout Ticks
+~
+
+The number of ticks from now in which the timer will expire. The ticks value
+has a resolution (``timer_tick_ns``) that is specified in the event timer
+adapter configura

[dpdk-dev] [PATCH v6 21/23] doc: add event timer adapter to API index

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 doc/api/doxy-api-index.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/api/doxy-api-index.md b/doc/api/doxy-api-index.md
index 3492702..3110658 100644
--- a/doc/api/doxy-api-index.md
+++ b/doc/api/doxy-api-index.md
@@ -46,6 +46,7 @@ The public API headers are grouped by topics:
   [security]   (@ref rte_security.h),
   [eventdev]   (@ref rte_eventdev.h),
   [event_eth_rx_adapter]   (@ref rte_event_eth_rx_adapter.h),
+  [event_timer_adapter](@ref rte_event_timer_adapter.h),
   [metrics](@ref rte_metrics.h),
   [bitrate](@ref rte_bitrate.h),
   [latency](@ref rte_latencystats.h),
-- 
2.6.4



[dpdk-dev] [PATCH v6 23/23] doc: add event timer adapter to release notes

2018-01-10 Thread Erik Gabriel Carrillo
Signed-off-by: Erik Gabriel Carrillo 
---
 doc/guides/rel_notes/release_18_02.rst | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/doc/guides/rel_notes/release_18_02.rst 
b/doc/guides/rel_notes/release_18_02.rst
index 24b67bb..8eafcd3 100644
--- a/doc/guides/rel_notes/release_18_02.rst
+++ b/doc/guides/rel_notes/release_18_02.rst
@@ -41,6 +41,12 @@ New Features
  Also, make sure to start the actual text at the margin.
  =
 
+* **Added the Event Timer Adapter Library.**
+
+  Added the Event Timer Adapter Library.  This library extends the
+  event-based model by introducing APIs that allow applications to
+  generate timer expiry events that are scheduled by an event device
+  along with existing types of events.
 
 API Changes
 ---
-- 
2.6.4



[dpdk-dev] [PATCH 1/1] doc: announce API change to lcore role function

2018-01-12 Thread Erik Gabriel Carrillo
This an API/ABI change notice for DPDK 18.05 announcing a change in
the meaning of the return values of the rte_lcore_has_role() function.

Signed-off-by: Erik Gabriel Carrillo 
---
 doc/guides/rel_notes/deprecation.rst | 5 +
 1 file changed, 5 insertions(+)

diff --git a/doc/guides/rel_notes/deprecation.rst 
b/doc/guides/rel_notes/deprecation.rst
index 13e8543..15a94cf 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -21,6 +21,11 @@ Deprecation Notices
   - ``rte_eal_devargs_type_count``
   - ``rte_eal_parse_devargs_str``, replaced by ``rte_eal_devargs_parse``
 
+* eal: The semantics of the return value for the ``rte_lcore_has_role`` 
function
+  are planned to change in v18.05. The function currently returns 0 and <0 for
+  success and failure, respectively.  This will change to 1 and 0 for true and
+  false, respectively, to make use of the function more intuitive.
+
 * pci: Several exposed functions are misnamed.
   The following functions are deprecated starting from v17.11 and are replaced:
 
-- 
2.6.4



[dpdk-dev] [PATCH 1/1] timer: fix reset on service cores

2018-01-12 Thread Erik Gabriel Carrillo
The return value of rte_lcore_has_role is misinterpreted in the timer
reset function.  The return values of rte_lcore_has_role will be changed
in a future DPDK release, but this commit fixes this call site until
that happens.

Fixes: 351f463456f8 ("timer: allow reset on service cores")
Cc: sta...@dpdk.org

Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_timer/rte_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/librte_timer/rte_timer.c b/lib/librte_timer/rte_timer.c
index 604ecab..4bbcd06 100644
--- a/lib/librte_timer/rte_timer.c
+++ b/lib/librte_timer/rte_timer.c
@@ -403,7 +403,7 @@ rte_timer_reset(struct rte_timer *tim, uint64_t ticks,
 
if (unlikely((tim_lcore != (unsigned)LCORE_ID_ANY) &&
!(rte_lcore_is_enabled(tim_lcore) ||
-   rte_lcore_has_role(tim_lcore, ROLE_SERVICE
+ rte_lcore_has_role(tim_lcore, ROLE_SERVICE) == 0)))
return -1;
 
if (type == PERIODICAL)
-- 
2.6.4



[dpdk-dev] [PATCH v8 0/9] eventtimer: introduce event timer adapter

2018-03-29 Thread Erik Gabriel Carrillo
This patch series contains the next iteration of the Event Timer Adapter
library, which abstracts timer mechanisms that are tightly coupled with event
devices, and extends the event based programming model so that timer
expirations are represented as an event.

v8
- Addressed comments on previous series from Jerin:
  - Add better git comment to initial patch
  - Return uint16_t for fastpath functions
  - Move updates to existing licenses to separate patch for individual review
  - Fix clang build error
  - Move fastpath functions into header as static inline functions
  - Remove duplicate map file entry
  - Fix flag value
  - Move update to rte.app.mk file into separate commit
- Addressed comments on previous series from Pavan:
  - Make tests generic so that they work for software or hardware event devices
and timer mechanisms
  - Don't access eventdev internals from tests
- Integrated unit tests from Pavan

v7
- Addressed comments on previous patch series from Pavan:
  - Use SPDX license tags
  - Squash various commits to make series easier to review
  - Tag experimental functions as such
  - Use one mempool for messages and timers in sw driver 
  - Limit service cores mapped to sw driver's service to one
  - Use smp memory barriers
  - In service function, invoke rte_timer_manage() with frequency matching the
resolution the adapter was configured with
- Reworked synchronization in sw driver between threads producing messages
  and service thread that consumes them.  The new approach avoids a situation
  where event timers couldn't be armed/canceled from the same lcore the service
  was running on.
- Updated logging facility
- Added more unit tests
- Added support for meson build

v6
- Addressed comments on previous version from Jerin:
  - Added RTE_EVENT_TIMER_CANCELED event timer state back in
  - remove check for started adapter in timer arm/cancel functions 
  - reuse CONFIG_RTE_LIBRTE_EVENTDEV_DEBUG instead of adding new config option
- Added initial version of software driver implementation
- Added stats APIs
- Added API to retrieve adapter service ID
- Added API to initialize event timer
- Added entry to Programmer's Guide in documentation
- Added new unit tests to auto-test

v5
- Addressed comments on previous version from Pavan:
  - renamed rte_event_timer_adapter_driver.h to rte_event_timer_adapter_pmd.h
  - moved contents of sw_event_timer_adapter.c into rte_event_timer_adapter.c
  - added flags parameter to timer_adapter_caps_get() call
  - added DEBUG config variable to conditionally compile run-time checks on
datapath
  - fixed license text and file description
- Also added a config variable to enable/disable compilation of event timer
  adapter - feedback on whether this is desirable is appreciated

v4
- Split changes into multiple patches for easier review

v3
- Reworked allocation and ops organization in common code based on feedback
  received from Jerin and Pavan. This will allow fast-path function pointers to 
  be dereferenced with one level of indirection with pointers valid in primary
  and secondary processes.
- Moved default software implementation from sw_evdev directory to eventdev
  library directory, which will allow it to be used by any eventdev PMD as an
  alternative to providing its own definitions.
- Reverted occurrences of id back to pointer to adapter struct in library API
- Added rte_event_timer_adapter_lookup() function back in

v2
- Added ops structure and stubbed out plugin for SW impl
- Added unit test stubs
- Replaced occurrences of "wheel" in API with "adapter"
- Replaced occurrences of pointer to struct rte_event_timer_adapter with ids
- Removed rte_event_timer_adapter_lookup() function
- Replaced RTE_EVENT_TIMER_SUCCESS_{ARM,CANCEL} states with
  RTE_EVENT_TIMER_ARMED

Erik Gabriel Carrillo (9):
  eventtimer: introduce event timer adapter
  eventdev: convert to SPDX license tag in header
  eventtimer: add common code
  mk: update library order in static build
  eventtimer: add default software driver
  eventtimer: add support for meson build system
  test: add event timer adapter auto-test
  doc: add event timer adapter section to programmer's guide
  doc: add event timer adapter documentation

 MAINTAINERS   |7 +
 config/common_base|1 +
 config/rte_config.h   |1 +
 doc/api/doxy-api-index.md |   32 +-
 doc/guides/prog_guide/event_timer_adapter.rst |  297 
 doc/guides/prog_guide/index.rst   |1 +
 doc/guides/rel_notes/release_18_05.rst|6 +
 drivers/event/sw/sw_evdev.c   |   18 +
 lib/Makefile  |2 +-
 lib/librte_eventdev/Makefile  |5 +-
 lib/librte_eventdev/meson.build   |9 +-
 lib/librte_eventdev/rte_event_timer_adapter.c   

[dpdk-dev] [PATCH v8 1/9] eventtimer: introduce event timer adapter

2018-03-29 Thread Erik Gabriel Carrillo
Event devices can be coupled with various components to provide
new event sources by using event adapters.  The event timer adapter
is one such adapter; it bridges event devices and timer mechanisms.
This library extends the event-driven programming model by
introducing a new type of event that represents a timer expiration,
and it provides APIs with which adapters can be created or destroyed
and event timers can be armed and canceled.

Signed-off-by: Jerin Jacob 
Signed-off-by: Pavan Nikhilesh 
Signed-off-by: Erik Gabriel Carrillo 
---
 lib/librte_eventdev/Makefile  |   1 +
 lib/librte_eventdev/rte_event_timer_adapter.h | 715 ++
 lib/librte_eventdev/rte_eventdev.h|   4 +-
 3 files changed, 718 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_eventdev/rte_event_timer_adapter.h

diff --git a/lib/librte_eventdev/Makefile b/lib/librte_eventdev/Makefile
index d27dd07..549b182 100644
--- a/lib/librte_eventdev/Makefile
+++ b/lib/librte_eventdev/Makefile
@@ -28,6 +28,7 @@ SYMLINK-y-include += rte_eventdev_pmd_pci.h
 SYMLINK-y-include += rte_eventdev_pmd_vdev.h
 SYMLINK-y-include += rte_event_ring.h
 SYMLINK-y-include += rte_event_eth_rx_adapter.h
+SYMLINK-y-include += rte_event_timer_adapter.h
 
 # versioning export map
 EXPORT_MAP := rte_eventdev_version.map
diff --git a/lib/librte_eventdev/rte_event_timer_adapter.h 
b/lib/librte_eventdev/rte_event_timer_adapter.h
new file mode 100644
index 000..6a76791
--- /dev/null
+++ b/lib/librte_eventdev/rte_event_timer_adapter.h
@@ -0,0 +1,715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2017 Cavium, Inc.
+ * Copyright(c) 2017-2018 Intel Corporation.
+ * All rights reserved.
+ */
+
+#ifndef __RTE_EVENT_TIMER_ADAPTER_H__
+#define __RTE_EVENT_TIMER_ADAPTER_H__
+
+/**
+ * @file
+ *
+ * RTE Event Timer Adapter
+ *
+ * An event timer adapter has the following abstract working model:
+ *
+ *   timer_tick_ns
+ *   +
+ *  +---+|
+ *  |   ||
+ *  +---+ bkt 0 +v---+
+ *  |   |   ||
+ *  |   +---+|
+ *  +---+---++---+---+  +---+---+---+---+
+ *  |   ||   |  |   |   |   |   |
+ *  | bkt n || bkt 1 |<-> t0| t1| t2| tn|
+ *  |   ||   |  |   |   |   |   |
+ *  +---+---++---+---+  +---+---+---+---+
+ *  | Timer adapter  |
+ *  +---+---++---+---+
+ *  |   ||   |
+ *  | bkt 4 || bkt 2 |<--- Current bucket
+ *  |   ||   |
+ *  +---+---++---+---+
+ *   |  +---+   |
+ *   |  |   |   |
+ *   +--+ bkt 3 +---+
+ *  |   |
+ *  +---+
+ *
+ * - It has a virtual monotonically increasing 64-bit timer adapter clock based
+ *   on *enum rte_event_timer_adapter_clk_src* clock source. The clock source
+ *   could be a CPU clock, or a platform dependent external clock.
+ *
+ * - The application creates a timer adapter instance with given the clock
+ *   source, the total number of event timers, and a resolution(expressed in 
ns)
+ *   to traverse between the buckets.
+ *
+ * - Each timer adapter may have 0 to n buckets based on the configured
+ *   max timeout(max_tmo_ns) and resolution(timer_tick_ns). Upon starting the
+ *   timer adapter, the adapter starts ticking at *timer_tick_ns* resolution.
+ *
+ * - The application arms an event timer that will expire *timer_tick_ns*
+ *   from now.
+ *
+ * - The application can cancel an armed timer and no timer expiry event will 
be
+ *   generated.
+ *
+ * - If a timer expires then the library injects the timer expiry event in
+ *   the designated event queue.
+ *
+ * - The timer expiry event will be received through *rte_event_dequeue_burst*.
+ *
+ * - The application frees the timer adapter instance.
+ *
+ * Multiple timer adapters can be created with a varying level of resolution
+ * for various expiry use cases that run in parallel.
+ *
+ * Before using the timer adapter, the application has to create and configure
+ * an event device along with the event port. Based on the event device
+ * capability it might require creating an additional event port to be used
+ * by the timer adapter.
+ *
+ * The application creates the event timer adapter using the
+ * ``rte_event_timer_adapter_create()``. The event device id is passed to this
+ * function, inside this function the event device capability is checked,
+ * and if an in-built port is absent the application uses the default
+ * function to create a new producer port.
+ *
+ * The application may also use the

  1   2   >