[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