From: Joe Stringer Date: Fri, 1 Nov 2013 23:34:29 +0000 (-0700) Subject: netdev-linux: Skip miimon execution when disabled X-Git-Tag: sliver-openvswitch-2.0.90-1~6^2~7 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=19c8e9c11bcd441a42ababb8439bc7b24e9e435c netdev-linux: Skip miimon execution when disabled When dealing with a large number of ports, one of the performance bottlenecks is that we loop through all netdevs in the main loop. Miimon is a contributor to this, checking all devices even if it has never been enabled. This patch introduces a counter for the number of netdevs with miimon configured. If this is 0, then we skip miimon_run() and miimon_wait(). In a test environment of 5000 internal ports and 50 tunnel ports with bfd, this reduces CPU usage from about 50% to about 45%. Signed-off-by: Joe Stringer Signed-off-by: Ben Pfaff --- diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 2752623d3..7e7514420 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -61,6 +61,7 @@ #include "netlink.h" #include "ofpbuf.h" #include "openflow/openflow.h" +#include "ovs-atomic.h" #include "packets.h" #include "poll-loop.h" #include "rtnetlink-link.h" @@ -402,6 +403,11 @@ struct netdev_rx_linux { * additional log messages. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); +/* Polling miimon status for all ports causes performance degradation when + * handling a large number of ports. If there are no devices using miimon, then + * we skip netdev_linux_miimon_run() and netdev_linux_miimon_wait(). */ +static atomic_int miimon_cnt = ATOMIC_VAR_INIT(0); + static void netdev_linux_run(void); static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *, @@ -423,6 +429,7 @@ static int set_etheraddr(const char *netdev_name, const uint8_t[ETH_ADDR_LEN]); static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats); static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats); static int af_packet_sock(void); +static bool netdev_linux_miimon_enabled(void); static void netdev_linux_miimon_run(void); static void netdev_linux_miimon_wait(void); @@ -485,13 +492,24 @@ netdev_linux_notify_sock(void) return sock; } +static bool +netdev_linux_miimon_enabled(void) +{ + int miimon; + + atomic_read(&miimon_cnt, &miimon); + return miimon > 0; +} + static void netdev_linux_run(void) { struct nl_sock *sock; int error; - netdev_linux_miimon_run(); + if (netdev_linux_miimon_enabled()) { + netdev_linux_miimon_run(); + } sock = netdev_linux_notify_sock(); if (!sock) { @@ -553,7 +571,9 @@ netdev_linux_wait(void) { struct nl_sock *sock; - netdev_linux_miimon_wait(); + if (netdev_linux_miimon_enabled()) { + netdev_linux_miimon_wait(); + } sock = netdev_linux_notify_sock(); if (sock) { nl_sock_wait(sock, POLLIN); @@ -711,6 +731,11 @@ netdev_linux_destruct(struct netdev *netdev_) close(netdev->tap_fd); } + if (netdev->miimon_interval > 0) { + int junk; + atomic_sub(&miimon_cnt, 1, &junk); + } + ovs_mutex_destroy(&netdev->mutex); } @@ -1222,6 +1247,14 @@ netdev_linux_set_miimon_interval(struct netdev *netdev_, ovs_mutex_lock(&netdev->mutex); interval = interval > 0 ? MAX(interval, 100) : 0; if (netdev->miimon_interval != interval) { + int junk; + + if (interval && !netdev->miimon_interval) { + atomic_add(&miimon_cnt, 1, &junk); + } else if (!interval && netdev->miimon_interval) { + atomic_sub(&miimon_cnt, 1, &junk); + } + netdev->miimon_interval = interval; timer_set_expired(&netdev->miimon_timer); }