diff mbox series

[ovs-dev,RFC,1/5] dpif-netdev: Convert exit latch to flag.

Message ID 1556626682-28858-2-git-send-email-david.marchand@redhat.com
State Changes Requested
Headers show
Series Quicker pmd threads reloads | expand

Commit Message

David Marchand April 30, 2019, 12:17 p.m. UTC
No need for a latch here since we don't have to wait.
A simple boolean flag is enough.

Fixes: e4cfed38b159 ("dpif-netdev: Add poll-mode-device thread.")
Signed-off-by: David Marchand <david.marchand@redhat.com>
---
 lib/dpif-netdev.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

Comments

Ilya Maximets May 6, 2019, 3:37 p.m. UTC | #1
On 30.04.2019 15:17, David Marchand wrote:
> No need for a latch here since we don't have to wait.
> A simple boolean flag is enough.
> 
> Fixes: e4cfed38b159 ("dpif-netdev: Add poll-mode-device thread.")
> Signed-off-by: David Marchand <david.marchand@redhat.com>
> ---
>  lib/dpif-netdev.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index f1422b2..30774ed 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -681,10 +681,10 @@ struct dp_netdev_pmd_thread {
>      /* Current context of the PMD thread. */
>      struct dp_netdev_pmd_thread_ctx ctx;
>  
> -    struct latch exit_latch;        /* For terminating the pmd thread. */
>      struct seq *reload_seq;
>      uint64_t last_reload_seq;
>      atomic_bool reload;             /* Do we need to reload ports? */
> +    atomic_bool exit;               /* For terminating the pmd thread. */
>      pthread_t thread;
>      unsigned core_id;               /* CPU core id of this pmd thread. */
>      int numa_id;                    /* numa node id of this pmd thread. */
> @@ -5479,7 +5479,7 @@ reload:
>      ovs_mutex_unlock(&pmd->perf_stats.stats_mutex);
>  
>      poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
> -    exiting = latch_is_set(&pmd->exit_latch);
> +    atomic_read_relaxed(&pmd->exit, &exiting);

I'm afraid that relaxed memory model is not suitable here.
You need to change memory models for both 'reload' and 'exit'
or put ack_rel thread fence between them. Otherwise reads/writes
could be reordered resulting in missed exit and main thread
hang on join.

>      /* Signal here to make sure the pmd finishes
>       * reloading the updated configuration. */
>      dp_netdev_pmd_reload_done(pmd);
> @@ -5898,7 +5898,7 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct dp_netdev *dp,
>      pmd->n_output_batches = 0;
>  
>      ovs_refcount_init(&pmd->ref_cnt);
> -    latch_init(&pmd->exit_latch);
> +    atomic_init(&pmd->exit, false);
>      pmd->reload_seq = seq_create();
>      pmd->last_reload_seq = seq_read(pmd->reload_seq);
>      atomic_init(&pmd->reload, false);
> @@ -5945,7 +5945,6 @@ dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd)
>      cmap_destroy(&pmd->classifiers);
>      cmap_destroy(&pmd->flow_table);
>      ovs_mutex_destroy(&pmd->flow_mutex);
> -    latch_destroy(&pmd->exit_latch);
>      seq_destroy(pmd->reload_seq);
>      xpthread_cond_destroy(&pmd->cond);
>      ovs_mutex_destroy(&pmd->cond_mutex);
> @@ -5967,7 +5966,7 @@ dp_netdev_del_pmd(struct dp_netdev *dp, struct dp_netdev_pmd_thread *pmd)
>          pmd_free_static_tx_qid(pmd);
>          ovs_mutex_unlock(&dp->non_pmd_mutex);
>      } else {
> -        latch_set(&pmd->exit_latch);
> +        atomic_store_relaxed(&pmd->exit, true);
>          dp_netdev_reload_pmd__(pmd);
>          xpthread_join(pmd->thread, NULL);
>      }
>
David Marchand May 14, 2019, 7:38 a.m. UTC | #2
Hello Ilya,


On Mon, May 6, 2019 at 5:37 PM Ilya Maximets <i.maximets@samsung.com> wrote:

> On 30.04.2019 15:17, David Marchand wrote:
> > No need for a latch here since we don't have to wait.
> > A simple boolean flag is enough.
> >
> > Fixes: e4cfed38b159 ("dpif-netdev: Add poll-mode-device thread.")
> > Signed-off-by: David Marchand <david.marchand@redhat.com>
> > ---
> >  lib/dpif-netdev.c | 9 ++++-----
> >  1 file changed, 4 insertions(+), 5 deletions(-)
> >
> > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> > index f1422b2..30774ed 100644
> > --- a/lib/dpif-netdev.c
> > +++ b/lib/dpif-netdev.c
> > @@ -681,10 +681,10 @@ struct dp_netdev_pmd_thread {
> >      /* Current context of the PMD thread. */
> >      struct dp_netdev_pmd_thread_ctx ctx;
> >
> > -    struct latch exit_latch;        /* For terminating the pmd thread.
> */
> >      struct seq *reload_seq;
> >      uint64_t last_reload_seq;
> >      atomic_bool reload;             /* Do we need to reload ports? */
> > +    atomic_bool exit;               /* For terminating the pmd thread.
> */
> >      pthread_t thread;
> >      unsigned core_id;               /* CPU core id of this pmd thread.
> */
> >      int numa_id;                    /* numa node id of this pmd thread.
> */
> > @@ -5479,7 +5479,7 @@ reload:
> >      ovs_mutex_unlock(&pmd->perf_stats.stats_mutex);
> >
> >      poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
> > -    exiting = latch_is_set(&pmd->exit_latch);
> > +    atomic_read_relaxed(&pmd->exit, &exiting);
>
> I'm afraid that relaxed memory model is not suitable here.
> You need to change memory models for both 'reload' and 'exit'
> or put ack_rel thread fence between them. Otherwise reads/writes
> could be reordered resulting in missed exit and main thread
> hang on join.
>

Indeed, I can not use relaxed memory model on both atomics.

I have been reading some articles and I am a bit puzzled :-).
I don't understand why I would need to update both atomics memory model.

On the pmd thread side:
atomic_read_explicit(&pmd->reload, &reload, memory_model_acquire);
atomic_read_relaxed(&pmd->exit, &exiting);

On the control side:
atomic_store_relaxed(&pmd->exit, true);
atomic_store_explicit(&pmd->reload, true, memory_order_release);

Would not it be enough to have those threads share the same view by
synchronising on reload ?
Ilya Maximets May 14, 2019, 9:53 a.m. UTC | #3
On 14.05.2019 10:38, David Marchand wrote:
> Hello Ilya,
> On Mon, May 6, 2019 at 5:37 PM Ilya Maximets <i.maximets@samsung.com <mailto:i.maximets@samsung.com>> wrote:
> 
>     On 30.04.2019 15:17, David Marchand wrote:
>     > No need for a latch here since we don't have to wait.
>     > A simple boolean flag is enough.
>     >
>     > Fixes: e4cfed38b159 ("dpif-netdev: Add poll-mode-device thread.")
>     > Signed-off-by: David Marchand <david.marchand@redhat.com <mailto:david.marchand@redhat.com>>
>     > ---
>     >  lib/dpif-netdev.c | 9 ++++-----
>     >  1 file changed, 4 insertions(+), 5 deletions(-)
>     >
>     > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>     > index f1422b2..30774ed 100644
>     > --- a/lib/dpif-netdev.c
>     > +++ b/lib/dpif-netdev.c
>     > @@ -681,10 +681,10 @@ struct dp_netdev_pmd_thread {
>     >      /* Current context of the PMD thread. */
>     >      struct dp_netdev_pmd_thread_ctx ctx;
>     > 
>     > -    struct latch exit_latch;        /* For terminating the pmd thread. */
>     >      struct seq *reload_seq;
>     >      uint64_t last_reload_seq;
>     >      atomic_bool reload;             /* Do we need to reload ports? */
>     > +    atomic_bool exit;               /* For terminating the pmd thread. */
>     >      pthread_t thread;
>     >      unsigned core_id;               /* CPU core id of this pmd thread. */
>     >      int numa_id;                    /* numa node id of this pmd thread. */
>     > @@ -5479,7 +5479,7 @@ reload:
>     >      ovs_mutex_unlock(&pmd->perf_stats.stats_mutex);
>     > 
>     >      poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
>     > -    exiting = latch_is_set(&pmd->exit_latch);
>     > +    atomic_read_relaxed(&pmd->exit, &exiting);
> 
>     I'm afraid that relaxed memory model is not suitable here.
>     You need to change memory models for both 'reload' and 'exit'
>     or put ack_rel thread fence between them. Otherwise reads/writes
>     could be reordered resulting in missed exit and main thread
>     hang on join.
> 
> 
> Indeed, I can not use relaxed memory model on both atomics.
> 
> I have been reading some articles and I am a bit puzzled :-).
> I don't understand why I would need to update both atomics memory model.
> 
> On the pmd thread side:
> atomic_read_explicit(&pmd->reload, &reload, memory_model_acquire);
> atomic_read_relaxed(&pmd->exit, &exiting);
> 
> On the control side:
> atomic_store_relaxed(&pmd->exit, true);
> atomic_store_explicit(&pmd->reload, true, memory_order_release);
> 
> Would not it be enough to have those threads share the same view by synchronising on reload ?

Yes. You're right. Above example is valid.
I re-checked the spec for release-acquire ordering and it seems that
we could use 'reload' with rel-acq ordering as a synchronization point
because it will force all memory writes (non-atomic and relaxed atomic)
that happened-before the rel atomic store in main thread become visible
side-effects in PMD thread after the acq atomic read.

Probably, I was confused because of thinking that we need a backward
synchronization (PMD --> main). But we don't.

https://en.cppreference.com/w/c/atomic/memory_order#Release-Acquire_ordering

Best regards, Ilya Maximets.
David Marchand May 14, 2019, 10:04 a.m. UTC | #4
On Tue, May 14, 2019 at 11:53 AM Ilya Maximets <i.maximets@samsung.com>
wrote:

>
> On 14.05.2019 10:38, David Marchand wrote:
> > Hello Ilya,
> > On Mon, May 6, 2019 at 5:37 PM Ilya Maximets <i.maximets@samsung.com
> <mailto:i.maximets@samsung.com>> wrote:
> >
> >     On 30.04.2019 15:17, David Marchand wrote:
> >     > No need for a latch here since we don't have to wait.
> >     > A simple boolean flag is enough.
> >     >
> >     > Fixes: e4cfed38b159 ("dpif-netdev: Add poll-mode-device thread.")
> >     > Signed-off-by: David Marchand <david.marchand@redhat.com <mailto:
> david.marchand@redhat.com>>
> >     > ---
> >     >  lib/dpif-netdev.c | 9 ++++-----
> >     >  1 file changed, 4 insertions(+), 5 deletions(-)
> >     >
> >     > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> >     > index f1422b2..30774ed 100644
> >     > --- a/lib/dpif-netdev.c
> >     > +++ b/lib/dpif-netdev.c
> >     > @@ -681,10 +681,10 @@ struct dp_netdev_pmd_thread {
> >     >      /* Current context of the PMD thread. */
> >     >      struct dp_netdev_pmd_thread_ctx ctx;
> >     >
> >     > -    struct latch exit_latch;        /* For terminating the pmd
> thread. */
> >     >      struct seq *reload_seq;
> >     >      uint64_t last_reload_seq;
> >     >      atomic_bool reload;             /* Do we need to reload
> ports? */
> >     > +    atomic_bool exit;               /* For terminating the pmd
> thread. */
> >     >      pthread_t thread;
> >     >      unsigned core_id;               /* CPU core id of this pmd
> thread. */
> >     >      int numa_id;                    /* numa node id of this pmd
> thread. */
> >     > @@ -5479,7 +5479,7 @@ reload:
> >     >      ovs_mutex_unlock(&pmd->perf_stats.stats_mutex);
> >     >
> >     >      poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
> >     > -    exiting = latch_is_set(&pmd->exit_latch);
> >     > +    atomic_read_relaxed(&pmd->exit, &exiting);
> >
> >     I'm afraid that relaxed memory model is not suitable here.
> >     You need to change memory models for both 'reload' and 'exit'
> >     or put ack_rel thread fence between them. Otherwise reads/writes
> >     could be reordered resulting in missed exit and main thread
> >     hang on join.
> >
> >
> > Indeed, I can not use relaxed memory model on both atomics.
> >
> > I have been reading some articles and I am a bit puzzled :-).
> > I don't understand why I would need to update both atomics memory model.
> >
> > On the pmd thread side:
> > atomic_read_explicit(&pmd->reload, &reload, memory_model_acquire);
> > atomic_read_relaxed(&pmd->exit, &exiting);
> >
> > On the control side:
> > atomic_store_relaxed(&pmd->exit, true);
> > atomic_store_explicit(&pmd->reload, true, memory_order_release);
> >
> > Would not it be enough to have those threads share the same view by
> synchronising on reload ?
>
> Yes. You're right. Above example is valid.
> I re-checked the spec for release-acquire ordering and it seems that
> we could use 'reload' with rel-acq ordering as a synchronization point
> because it will force all memory writes (non-atomic and relaxed atomic)
> that happened-before the rel atomic store in main thread become visible
> side-effects in PMD thread after the acq atomic read.
>
> Probably, I was confused because of thinking that we need a backward
> synchronization (PMD --> main). But we don't.
>
>
> https://en.cppreference.com/w/c/atomic/memory_order#Release-Acquire_ordering



Thanks a lot.
Then I will revisit my series with that in mind.
diff mbox series

Patch

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f1422b2..30774ed 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -681,10 +681,10 @@  struct dp_netdev_pmd_thread {
     /* Current context of the PMD thread. */
     struct dp_netdev_pmd_thread_ctx ctx;
 
-    struct latch exit_latch;        /* For terminating the pmd thread. */
     struct seq *reload_seq;
     uint64_t last_reload_seq;
     atomic_bool reload;             /* Do we need to reload ports? */
+    atomic_bool exit;               /* For terminating the pmd thread. */
     pthread_t thread;
     unsigned core_id;               /* CPU core id of this pmd thread. */
     int numa_id;                    /* numa node id of this pmd thread. */
@@ -5479,7 +5479,7 @@  reload:
     ovs_mutex_unlock(&pmd->perf_stats.stats_mutex);
 
     poll_cnt = pmd_load_queues_and_ports(pmd, &poll_list);
-    exiting = latch_is_set(&pmd->exit_latch);
+    atomic_read_relaxed(&pmd->exit, &exiting);
     /* Signal here to make sure the pmd finishes
      * reloading the updated configuration. */
     dp_netdev_pmd_reload_done(pmd);
@@ -5898,7 +5898,7 @@  dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct dp_netdev *dp,
     pmd->n_output_batches = 0;
 
     ovs_refcount_init(&pmd->ref_cnt);
-    latch_init(&pmd->exit_latch);
+    atomic_init(&pmd->exit, false);
     pmd->reload_seq = seq_create();
     pmd->last_reload_seq = seq_read(pmd->reload_seq);
     atomic_init(&pmd->reload, false);
@@ -5945,7 +5945,6 @@  dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd)
     cmap_destroy(&pmd->classifiers);
     cmap_destroy(&pmd->flow_table);
     ovs_mutex_destroy(&pmd->flow_mutex);
-    latch_destroy(&pmd->exit_latch);
     seq_destroy(pmd->reload_seq);
     xpthread_cond_destroy(&pmd->cond);
     ovs_mutex_destroy(&pmd->cond_mutex);
@@ -5967,7 +5966,7 @@  dp_netdev_del_pmd(struct dp_netdev *dp, struct dp_netdev_pmd_thread *pmd)
         pmd_free_static_tx_qid(pmd);
         ovs_mutex_unlock(&dp->non_pmd_mutex);
     } else {
-        latch_set(&pmd->exit_latch);
+        atomic_store_relaxed(&pmd->exit, true);
         dp_netdev_reload_pmd__(pmd);
         xpthread_join(pmd->thread, NULL);
     }