Given the current implementation it is not clear to me that the result
calculated by ofproto_enumerate_types() can ever change.

By caching the lookup made by ofproto_enumerate_types() calls to
shash_add() and shash_destroy() destroy are avoided reducing the use of
malloc(), free() and hash_bytes().

In my test environment this increased the rate at which packets could be
received from ~25.6kpps to ~27.0kpps.

Signed-off-by: Simon Horman <ho...@verge.net.au>
---
 ofproto/ofproto.c |   17 ++++++++++++++---
 ofproto/ofproto.h |    3 ++-
 vswitchd/bridge.c |   32 ++++++++++++--------------------
 3 files changed, 28 insertions(+), 24 deletions(-)

diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index acf3b9a..1ec688e 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -329,19 +329,30 @@ ofproto_class_unregister(const struct ofproto_class 
*class)
 
 /* Clears 'types' and enumerates all registered ofproto types into it.  The
  * caller must first initialize the sset. */
-void
-ofproto_enumerate_types(struct sset *types)
+const struct sset *
+ofproto_enumerate_types(void)
 {
     size_t i;
+    static struct sset types = SSET_INITIALIZER(&types);
+
+    if (!sset_is_empty(&types)) {
+        return &types;
+    }
 
+    /* Here it is assumed that both the contents of ofproto_classes[]
+     * and the output of ofproto_classes[]->enumerate_types() never
+     * changes. This is a performance optimisation, avoiding recalculating
+     * types each time this function is called. */
     for (i = 0; i < n_ofproto_classes; i++) {
         const struct sset *types_ = ofproto_classes[i]->enumerate_types();
         const char *name;
 
         SSET_FOR_EACH(name, types_) {
-            sset_add(types, name);
+            sset_add(&types, name);
         }
     }
+
+    return &types;
 }
 
 /* Returns the fully spelled out name for the given ofproto 'type'.
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 413472a..eb58c94 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -132,7 +132,8 @@ struct ofproto_controller {
     uint8_t dscp;               /* DSCP value for controller connection. */
 };
 
-void ofproto_enumerate_types(struct sset *types);
+const struct sset *
+ofproto_enumerate_types(void);
 const char *ofproto_normalize_type(const char *);
 
 int ofproto_enumerate_names(const char *type, struct sset *names);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 82c3bff..ac08590 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -620,14 +620,13 @@ bridge_update_ofprotos(void)
 {
     struct bridge *br, *next;
     struct sset names;
-    struct sset types;
+    const struct sset *types;
     const char *type;
 
     /* Delete ofprotos with no bridge or with the wrong type. */
     sset_init(&names);
-    sset_init(&types);
-    ofproto_enumerate_types(&types);
-    SSET_FOR_EACH (type, &types) {
+    types = ofproto_enumerate_types();
+    SSET_FOR_EACH (type, types) {
         const char *name;
 
         ofproto_enumerate_names(type, &names);
@@ -639,7 +638,6 @@ bridge_update_ofprotos(void)
         }
     }
     sset_destroy(&names);
-    sset_destroy(&types);
 
     /* Add ofprotos for bridges which don't have one yet. */
     HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) {
@@ -2096,16 +2094,14 @@ refresh_instant_stats(void)
 void
 bridge_run_fast(void)
 {
-    struct sset types;
+    const struct sset *types;
     const char *type;
     struct bridge *br;
 
-    sset_init(&types);
-    ofproto_enumerate_types(&types);
-    SSET_FOR_EACH (type, &types) {
+    types = ofproto_enumerate_types();
+    SSET_FOR_EACH (type, types) {
         ofproto_type_run_fast(type);
     }
-    sset_destroy(&types);
 
     HMAP_FOR_EACH (br, node, &all_bridges) {
         ofproto_run_fast(br->ofproto);
@@ -2118,7 +2114,7 @@ bridge_run(void)
     static struct ovsrec_open_vswitch null_cfg;
     const struct ovsrec_open_vswitch *cfg;
     struct ovsdb_idl_txn *reconf_txn = NULL;
-    struct sset types;
+    const struct sset *types;
     const char *type;
 
     bool vlan_splinters_changed;
@@ -2154,12 +2150,10 @@ bridge_run(void)
     bridge_init_ofproto(cfg);
 
     /* Let each datapath type do the work that it needs to do. */
-    sset_init(&types);
-    ofproto_enumerate_types(&types);
-    SSET_FOR_EACH (type, &types) {
+    types = ofproto_enumerate_types();
+    SSET_FOR_EACH (type, types) {
         ofproto_type_run(type);
     }
-    sset_destroy(&types);
 
     /* Let each bridge do the work that it needs to do. */
     HMAP_FOR_EACH (br, node, &all_bridges) {
@@ -2263,7 +2257,7 @@ bridge_run(void)
 void
 bridge_wait(void)
 {
-    struct sset types;
+    const struct sset *types;
     const char *type;
 
     ovsdb_idl_wait(idl);
@@ -2272,12 +2266,10 @@ bridge_wait(void)
         poll_immediate_wake();
     }
 
-    sset_init(&types);
-    ofproto_enumerate_types(&types);
-    SSET_FOR_EACH (type, &types) {
+    types = ofproto_enumerate_types();
+    SSET_FOR_EACH (type, types) {
         ofproto_type_wait(type);
     }
-    sset_destroy(&types);
 
     if (!hmap_is_empty(&all_bridges)) {
         struct bridge *br;
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to