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