[ovs-dev] [RFCv3 12/13] revalidator: Reduce ukey contention.

Joe Stringer joestringer at nicira.com
Tue Sep 2 10:48:50 UTC 2014


When handler threads are installing ukeys, they hold the ukey mutex for
the duration of flow setup. If a revalidator thread dumps this flow
while the handler holds the lock, it will attempt to lock it using
ovs_mutex_trylock(), then if it cannot grab the lock, skip the flow.

Attempting to lock on a ukey that is currently locked is a common
occurrence when:
 - There are many handler threads running, and
 - Large numbers of small flows are passing through OVS.

In these cases, the act of attempting to lock the ukey is quite
expensive. This patch adds a flag 'installed' to the ukey, which is
raised when flow setup is complete. By checking this flag before
attempting to perform a trylock(), we can reduce lock contention between
handler and revalidator threads.

Signed-off-by: Joe Stringer <joestringer at nicira.com>
---
v3: No change.
v2: No change.
---
 ofproto/ofproto-dpif-upcall.c |   29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 81ea1c0..93c13ab 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -208,14 +208,17 @@ struct udpif_key {
     struct ofpbuf *actions;        /* Datapath flow actions as nlattrs. */
     ovs_u128 uid;                  /* Unique flow identifier. */
     uint32_t hash;                 /* Pre-computed hash for 'key'. */
+    atomic_bool installed;         /* True if the datapath flow has been
+                                      installed and handlers are finished with
+                                      this ukey. Used to reduce contention. */
 
     struct ovs_mutex mutex;                   /* Guards the following. */
     struct dpif_flow_stats stats OVS_GUARDED; /* Last known stats.*/
     long long int created OVS_GUARDED;        /* Estimate of creation time. */
     uint64_t dump_seq OVS_GUARDED;            /* Tracks udpif->dump_seq. */
     uint64_t reval_seq OVS_GUARDED;           /* Tracks udpif->reval_seq. */
-    bool flow_exists OVS_GUARDED;             /* Ensures flows are only deleted
-                                                 once. */
+    bool flow_exists OVS_GUARDED;             /* The flow is currently in the
+                                                 datapath. */
 
     struct xlate_cache *xcache OVS_GUARDED;   /* Cache for xlate entries that
                                                * are affected by this ukey.
@@ -1312,6 +1315,7 @@ ukey_new(struct udpif *udpif, struct upcall *upcall)
     ukey->hash = get_uid_hash(&ukey->uid);
     ukey->actions = ofpbuf_clone(&upcall->put_actions);
 
+    atomic_init(&ukey->installed, false);
     ovs_mutex_init(&ukey->mutex);
     ukey->dump_seq = upcall->dump_seq;
     ukey->reval_seq = upcall->reval_seq;
@@ -1355,6 +1359,7 @@ ukey_install_finish(struct udpif_key *ukey, int error)
 {
     if (!error) {
         ukey->flow_exists = true;
+        atomic_store(&ukey->installed, true);
     }
     ovs_mutex_unlock(&ukey->mutex);
 }
@@ -1370,6 +1375,22 @@ ukey_install(struct udpif *udpif, struct udpif_key *ukey)
     return true;
 }
 
+/* Wrapper for ovs_mutex_trylock() which reduces contention between handler
+ * threads and revalidator threads by not bothering to try locking if the
+ * flow is still being processed. */
+static int
+ukey_trylock(struct udpif_key *ukey)
+    OVS_TRY_LOCK(0, ukey->mutex)
+{
+    bool installed;
+
+    atomic_read(&ukey->installed, &installed);
+    if (!installed) {
+        return EBUSY;
+    }
+    return ovs_mutex_trylock(&ukey->mutex);
+}
+
 /* Searches for a ukey in 'udpif->ukeys' that matches 'flow' and attempts to
  * lock the ukey.
  *
@@ -1391,7 +1412,7 @@ ukey_acquire(struct udpif *udpif, const struct dpif_flow *flow,
     ukey = ukey_lookup(udpif, flow->uid, flow->uid_len,
                        flow->key, flow->key_len);
     if (ukey) {
-        retval = ovs_mutex_trylock(&ukey->mutex);
+        retval = ukey_trylock(ukey);
     } else {
         struct ds ds = DS_EMPTY_INITIALIZER;
         ovs_u128 uid;
@@ -1848,7 +1869,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge)
 
             /* Handler threads could be holding a ukey lock while it installs a
              * new flow, so don't hang around waiting for access to it. */
-            if (ovs_mutex_trylock(&ukey->mutex)) {
+            if (ukey_trylock(ukey)) {
                 continue;
             }
             flow_exists = ukey->flow_exists;
-- 
1.7.10.4




More information about the dev mailing list