[ovs-dev] [PATCH 1/3] netdev-linux: Cache result in netdev_linux_miimon_run()

Simon Horman horms at verge.net.au
Mon Jan 21 06:10:00 UTC 2013


In general the network devices don't change very often.
By caching the lookup made by netdev_linux_miimon_run()
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 ~23.3kpps to ~24.4kpps.

Signed-off-by: Simon Horman <horms at verge.net.au>
---
 lib/netdev-linux.c    |   25 +++++++++----------------
 lib/netdev-provider.h |    3 +--
 lib/netdev.c          |   22 ++++++++++++++++++----
 3 files changed, 28 insertions(+), 22 deletions(-)

diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 433d168..004b5eb 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -561,12 +561,11 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change,
             }
         }
     } else {
-        struct shash device_shash;
+        const struct shash *device_shash;
         struct shash_node *node;
 
-        shash_init(&device_shash);
-        netdev_dev_get_devices(&netdev_linux_class, &device_shash);
-        SHASH_FOR_EACH (node, &device_shash) {
+        device_shash = netdev_dev_get_devices(&netdev_linux_class);
+        SHASH_FOR_EACH (node, device_shash) {
             unsigned int flags;
 
             dev = node->data;
@@ -574,7 +573,6 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change,
             get_flags(&dev->netdev_dev, &flags);
             netdev_dev_linux_changed(dev, flags, 0);
         }
-        shash_destroy(&device_shash);
     }
 }
 
@@ -1230,12 +1228,11 @@ netdev_linux_set_miimon_interval(struct netdev *netdev_,
 static void
 netdev_linux_miimon_run(void)
 {
-    struct shash device_shash;
+    const struct shash *device_shash;
     struct shash_node *node;
 
-    shash_init(&device_shash);
-    netdev_dev_get_devices(&netdev_linux_class, &device_shash);
-    SHASH_FOR_EACH (node, &device_shash) {
+    device_shash = netdev_dev_get_devices(&netdev_linux_class);
+    SHASH_FOR_EACH (node, device_shash) {
         struct netdev_dev_linux *dev = node->data;
         bool miimon;
 
@@ -1251,26 +1248,22 @@ netdev_linux_miimon_run(void)
 
         timer_set_duration(&dev->miimon_timer, dev->miimon_interval);
     }
-
-    shash_destroy(&device_shash);
 }
 
 static void
 netdev_linux_miimon_wait(void)
 {
-    struct shash device_shash;
+    const struct shash *device_shash;
     struct shash_node *node;
 
-    shash_init(&device_shash);
-    netdev_dev_get_devices(&netdev_linux_class, &device_shash);
-    SHASH_FOR_EACH (node, &device_shash) {
+    device_shash = netdev_dev_get_devices(&netdev_linux_class);
+    SHASH_FOR_EACH (node, device_shash) {
         struct netdev_dev_linux *dev = node->data;
 
         if (dev->miimon_interval > 0) {
             timer_wait(&dev->miimon_timer);
         }
     }
-    shash_destroy(&device_shash);
 }
 
 /* Check whether we can we use RTM_GETLINK to get network device statistics.
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 9db950c..ff388b7 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -47,8 +47,7 @@ const char *netdev_dev_get_type(const struct netdev_dev *);
 const struct netdev_class *netdev_dev_get_class(const struct netdev_dev *);
 const char *netdev_dev_get_name(const struct netdev_dev *);
 struct netdev_dev *netdev_dev_from_name(const char *name);
-void netdev_dev_get_devices(const struct netdev_class *,
-                            struct shash *device_list);
+const struct shash *netdev_dev_get_devices(const struct netdev_class *);
 
 static inline void netdev_dev_assert_class(const struct netdev_dev *netdev_dev,
                                            const struct netdev_class *class_)
diff --git a/lib/netdev.c b/lib/netdev.c
index 0a2e7c5..df2c52d 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -52,6 +52,7 @@ static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes);
 
 /* All created network devices. */
 static struct shash netdev_dev_shash = SHASH_INITIALIZER(&netdev_dev_shash);
+bool netdev_dev_shash_changed;
 
 /* All open network devices. */
 static struct list netdev_list = LIST_INITIALIZER(&netdev_list);
@@ -1321,6 +1322,7 @@ netdev_dev_init(struct netdev_dev *netdev_dev, const char *name,
     netdev_dev->netdev_class = netdev_class;
     netdev_dev->name = xstrdup(name);
     netdev_dev->node = shash_add(&netdev_dev_shash, name, netdev_dev);
+    netdev_dev_shash_changed = true;
 }
 
 /* Undoes the results of initialization.
@@ -1338,6 +1340,7 @@ netdev_dev_uninit(struct netdev_dev *netdev_dev, bool destroy)
     ovs_assert(!netdev_dev->ref_cnt);
 
     shash_delete(&netdev_dev_shash, netdev_dev->node);
+    netdev_dev_shash_changed = true;
 
     if (destroy) {
         netdev_dev->netdev_class->destroy(netdev_dev);
@@ -1383,18 +1386,29 @@ netdev_dev_from_name(const char *name)
  *
  * The caller is responsible for initializing and destroying 'device_list'
  * but the contained netdev_devs must not be freed. */
-void
-netdev_dev_get_devices(const struct netdev_class *netdev_class,
-                       struct shash *device_list)
+const struct shash *
+netdev_dev_get_devices(const struct netdev_class *netdev_class)
 {
     struct shash_node *node;
+    static struct shash device_list = SHASH_INITIALIZER(&device_list);
+
+    if (!netdev_dev_shash_changed) {
+        return &device_list;
+    }
+
+    shash_destroy(&device_list);
+    shash_init(&device_list);
+
     SHASH_FOR_EACH (node, &netdev_dev_shash) {
         struct netdev_dev *dev = node->data;
 
         if (dev->netdev_class == netdev_class) {
-            shash_add(device_list, node->name, node->data);
+            shash_add(&device_list, node->name, node->data);
         }
     }
+
+    netdev_dev_shash_changed = false;
+    return &device_list;
 }
 
 /* Initializes 'netdev' as a instance of the netdev_dev.
-- 
1.7.10.4




More information about the dev mailing list