On Mon, Mar 27, 2023 at 7:25 AM Eelco Chaudron <[email protected]> wrote:
>
> Make the read of the current seq->value atomic, i.e., not needing to
> acquire the global mutex when reading it. On 64-bit systems, this
> incurs no overhead, and it will avoid the mutex and potentially
> a system call.
>
> For incrementing the value followed by waking up the threads, we are
> still taking the mutex, so the current behavior is not changing. The
> seq_read() behavior is already defined as, "Returns seq's current
> sequence number (which could change immediately)". So the change
> should not impact the current behavior.
>
> Signed-off-by: Eelco Chaudron <[email protected]>
> ---
>  lib/ovs-rcu.c |    2 +-
>  lib/seq.c     |   37 ++++++++++++++++---------------------
>  lib/seq.h     |    1 -
>  3 files changed, 17 insertions(+), 23 deletions(-)
>
> diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c
> index 946aa04d1..9e07d9bab 100644
> --- a/lib/ovs-rcu.c
> +++ b/lib/ovs-rcu.c
> @@ -170,7 +170,7 @@ ovsrcu_try_quiesce(void)
>      ovs_assert(!single_threaded());
>      perthread = ovsrcu_perthread_get();
>      if (!seq_try_lock()) {
> -        perthread->seqno = seq_read_protected(global_seqno);
> +        perthread->seqno = seq_read(global_seqno);
>          if (perthread->cbset) {
>              ovsrcu_flush_cbset__(perthread, true);
>          }
> diff --git a/lib/seq.c b/lib/seq.c
> index 99e5bf8bd..22646f3f8 100644
> --- a/lib/seq.c
> +++ b/lib/seq.c
> @@ -32,7 +32,7 @@ COVERAGE_DEFINE(seq_change);
>
>  /* A sequence number object. */
>  struct seq {
> -    uint64_t value OVS_GUARDED;
> +    atomic_uint64_t value;
>      struct hmap waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
>  };
>
> @@ -72,6 +72,7 @@ static void seq_wake_waiters(struct seq *) 
> OVS_REQUIRES(seq_mutex);
>  struct seq * OVS_EXCLUDED(seq_mutex)
>  seq_create(void)
>  {
> +    uint64_t seq_value;
>      struct seq *seq;
>
>      seq_init();
> @@ -81,7 +82,8 @@ seq_create(void)
>      COVERAGE_INC(seq_change);
>
>      ovs_mutex_lock(&seq_mutex);

I think it's also possible to get rid of the mutex here. Operations
like modifying a bridge or interface can result in calling seq_create
dozens of times, which could potentially lead to contention in cases
when a lot of interfaces are constantly added or removed. I'm mainly
thinking about kubernetes here.

Other than that, I found this patch to reduce locking on seq_mutex
pretty significantly with a userspace workload:

Before: 468727.2/sec
After: 229265.8/sec

The rest of this patch looks good to me, but what do you think about:

diff --git a/lib/seq.c b/lib/seq.c
index 22646f3f8..09fdccce5 100644
--- a/lib/seq.c
+++ b/lib/seq.c
@@ -57,7 +57,7 @@ struct seq_thread {

 static struct ovs_mutex seq_mutex = OVS_MUTEX_INITIALIZER;

-static uint64_t seq_next OVS_GUARDED_BY(seq_mutex) = 1;
+static atomic_uint64_t seq_next = 1;

 static pthread_key_t seq_thread_key;

@@ -81,11 +81,9 @@ seq_create(void)

     COVERAGE_INC(seq_change);

-    ovs_mutex_lock(&seq_mutex);
-    seq_value = seq_next++;
+    seq_value = atomic_count_inc64(&seq_next);
     atomic_store_relaxed(&seq->value, seq_value);
     hmap_init(&seq->waiters);
-    ovs_mutex_unlock(&seq_mutex);

     return seq;
 }
@@ -128,7 +126,7 @@ void
 seq_change_protected(struct seq *seq)
     OVS_REQUIRES(seq_mutex)
 {
-    uint64_t seq_value = seq_next++;
+    uint64_t seq_value = atomic_count_inc64(&seq_next);

     COVERAGE_INC(seq_change);

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to