aboutsummaryrefslogtreecommitdiff
path: root/ofproto
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2013-03-25 19:49:13 -0700
committerBen Pfaff <blp@nicira.com>2013-04-01 13:30:58 -0700
commit7d0b0ed7bf174312a1c1bdb05a29101d400b0fa4 (patch)
tree57bcb462809e5dc254604bb005cdf21aca58cd7c /ofproto
parentc2c5cca2aff3d4324a3d84b24107675b9be6301d (diff)
ofproto-dpif: Keep track of exact-match flow info
This patch adds more flow related stats to the output of "ovs-appctl dpif/show". Specifically, the follow information are added per ofproto: - Max flow table size - Average flow table size - Average flow table add rate - Average flow table delete rate - Average flow entry life in milliseconds Feature #15366 Signed-off-by: Andy Zhou <azhou@nicira.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
Diffstat (limited to 'ofproto')
-rw-r--r--ofproto/ofproto-dpif.c178
1 files changed, 176 insertions, 2 deletions
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index df18244f..7fa44e83 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -367,6 +367,7 @@ struct subfacet {
int key_len;
long long int used; /* Time last used; time created if not used. */
+ long long int created; /* Time created. */
uint64_t dp_packet_count; /* Last known packet count in the datapath. */
uint64_t dp_byte_count; /* Last known byte count in the datapath. */
@@ -663,6 +664,13 @@ odp_port_to_ofport(const struct dpif_backer *, uint32_t odp_port);
static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
uint64_t delta);
+struct avg_subfacet_rates {
+ double add_rate; /* Moving average of new flows created per minute. */
+ double del_rate; /* Moving average of flows deleted per minute. */
+};
+static void show_dp_rates(struct ds *ds, const char *heading,
+ const struct avg_subfacet_rates *rates);
+static void exp_mavg(double *avg, int base, double new);
struct ofproto_dpif {
struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */
@@ -718,7 +726,48 @@ struct ofproto_dpif {
/* Per ofproto's dpif stats. */
uint64_t n_hit;
uint64_t n_missed;
+
+ /* Subfacet statistics.
+ *
+ * These keep track of the total number of subfacets added and deleted and
+ * flow life span. They are useful for computing the flow rates stats
+ * exposed via "ovs-appctl dpif/show". The goal is to learn about
+ * traffic patterns in ways that we can use later to improve Open vSwitch
+ * performance in new situations. */
+ long long int created; /* Time when it is created. */
+ unsigned int max_n_subfacet; /* Maximum number of flows */
+
+ /* The average number of subfacets... */
+ struct avg_subfacet_rates hourly; /* ...over the last hour. */
+ struct avg_subfacet_rates daily; /* ...over the last day. */
+ long long int last_minute; /* Last time 'hourly' was updated. */
+
+ /* Number of subfacets added or deleted since 'last_minute'. */
+ unsigned int subfacet_add_count;
+ unsigned int subfacet_del_count;
+
+ /* Number of subfacets added or deleted from 'created' to 'last_minute.' */
+ unsigned long long int total_subfacet_add_count;
+ unsigned long long int total_subfacet_del_count;
+
+ /* Sum of the number of milliseconds that each subfacet existed,
+ * over the subfacets that have been added and then later deleted. */
+ unsigned long long int total_subfacet_life_span;
+
+ /* Incremented by the number of currently existing subfacets, each
+ * time we pull statistics from the kernel. */
+ unsigned long long int total_subfacet_count;
+
+ /* Number of times we pull statistics from the kernel. */
+ unsigned long long int n_update_stats;
};
+static unsigned long long int avg_subfacet_life_span(
+ const struct ofproto_dpif *);
+static double avg_subfacet_count(const struct ofproto_dpif *ofproto);
+static void update_moving_averages(struct ofproto_dpif *ofproto);
+static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
+ uint64_t delta);
+static void update_max_subfacet_count(struct ofproto_dpif *ofproto);
/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only
* for debugging the asynchronous flow_mod implementation.) */
@@ -1299,6 +1348,19 @@ construct(struct ofproto *ofproto_)
ofproto->n_hit = 0;
ofproto->n_missed = 0;
+ ofproto->max_n_subfacet = 0;
+ ofproto->created = time_msec();
+ ofproto->last_minute = ofproto->created;
+ memset(&ofproto->hourly, 0, sizeof ofproto->hourly);
+ memset(&ofproto->daily, 0, sizeof ofproto->daily);
+ ofproto->subfacet_add_count = 0;
+ ofproto->subfacet_del_count = 0;
+ ofproto->total_subfacet_add_count = 0;
+ ofproto->total_subfacet_del_count = 0;
+ ofproto->total_subfacet_life_span = 0;
+ ofproto->total_subfacet_count = 0;
+ ofproto->n_update_stats = 0;
+
return error;
}
@@ -4043,6 +4105,9 @@ expire(struct dpif_backer *backer)
continue;
}
+ /* Keep track of the max number of flows per ofproto_dpif. */
+ update_max_subfacet_count(ofproto);
+
/* Expire subfacets that have been idle too long. */
dp_max_idle = subfacet_max_idle(ofproto);
expire_subfacets(ofproto, dp_max_idle);
@@ -4163,6 +4228,10 @@ update_stats(struct dpif_backer *backer)
continue;
}
+ ofproto->total_subfacet_count += hmap_count(&ofproto->subfacets);
+ ofproto->n_update_stats++;
+ update_moving_averages(ofproto);
+
ofport = get_ofp_port(ofproto, flow.in_port);
if (ofport && ofport->tnl_port) {
netdev_vport_inc_rx(ofport->up.netdev, stats);
@@ -5064,6 +5133,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
subfacet->key = xmemdup(key, key_len);
subfacet->key_len = key_len;
subfacet->used = now;
+ subfacet->created = now;
subfacet->dp_packet_count = 0;
subfacet->dp_byte_count = 0;
subfacet->actions_len = 0;
@@ -5075,6 +5145,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
subfacet->initial_vals = miss->initial_vals;
subfacet->odp_in_port = miss->odp_in_port;
+ ofproto->subfacet_add_count++;
return subfacet;
}
@@ -5086,6 +5157,10 @@ subfacet_destroy__(struct subfacet *subfacet)
struct facet *facet = subfacet->facet;
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+ /* Update ofproto stats before uninstall the subfacet. */
+ ofproto->subfacet_del_count++;
+ ofproto->total_subfacet_life_span += (time_msec() - subfacet->created);
+
subfacet_uninstall(subfacet);
hmap_remove(&ofproto->subfacets, &subfacet->hmap_node);
list_remove(&subfacet->list_node);
@@ -7967,14 +8042,40 @@ show_dp_format(const struct ofproto_dpif *ofproto, struct ds *ds)
{
const struct shash_node **ports;
int i;
+ struct avg_subfacet_rates lifetime;
+ unsigned long long int minutes;
+ const int min_ms = 60 * 1000; /* milliseconds in one minute. */
+
+ minutes = (time_msec() - ofproto->created) / min_ms;
+
+ if (minutes > 0) {
+ lifetime.add_rate = (double)ofproto->total_subfacet_add_count
+ / minutes;
+ lifetime.del_rate = (double)ofproto->total_subfacet_del_count
+ / minutes;
+ }else {
+ lifetime.add_rate = 0.0;
+ lifetime.del_rate = 0.0;
+ }
ds_put_format(ds, "%s (%s):\n", ofproto->up.name,
dpif_name(ofproto->backer->dpif));
ds_put_format(ds,
"\tlookups: hit:%"PRIu64" missed:%"PRIu64"\n",
ofproto->n_hit, ofproto->n_missed);
- ds_put_format(ds, "\tflows: %zu\n",
- hmap_count(&ofproto->subfacets));
+ ds_put_format(ds, "\tflows: cur: %zu, avg: %5.3f, max: %d,"
+ " life span: %llu(ms)\n",
+ hmap_count(&ofproto->subfacets),
+ avg_subfacet_count(ofproto),
+ ofproto->max_n_subfacet,
+ avg_subfacet_life_span(ofproto));
+ if (minutes >= 60) {
+ show_dp_rates(ds, "\t\thourly avg:", &ofproto->hourly);
+ }
+ if (minutes >= 60 * 24) {
+ show_dp_rates(ds, "\t\tdaily avg:", &ofproto->daily);
+ }
+ show_dp_rates(ds, "\t\toverall avg:", &lifetime);
ports = shash_sort(&ofproto->up.port_by_name);
for (i = 0; i < shash_count(&ofproto->up.port_by_name); i++) {
@@ -8391,6 +8492,79 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
return OFPP_NONE;
}
}
+static unsigned long long int
+avg_subfacet_life_span(const struct ofproto_dpif *ofproto)
+{
+ unsigned long long int dc;
+ unsigned long long int avg;
+
+ dc = ofproto->total_subfacet_del_count + ofproto->subfacet_del_count;
+ avg = dc ? ofproto->total_subfacet_life_span / dc : 0;
+
+ return avg;
+}
+
+static double
+avg_subfacet_count(const struct ofproto_dpif *ofproto)
+{
+ double avg_c = 0.0;
+
+ if (ofproto->n_update_stats) {
+ avg_c = (double)ofproto->total_subfacet_count
+ / ofproto->n_update_stats;
+ }
+
+ return avg_c;
+}
+
+static void
+show_dp_rates(struct ds *ds, const char *heading,
+ const struct avg_subfacet_rates *rates)
+{
+ ds_put_format(ds, "%s add rate: %5.3f/min, del rate: %5.3f/min\n",
+ heading, rates->add_rate, rates->del_rate);
+}
+
+static void
+update_max_subfacet_count(struct ofproto_dpif *ofproto)
+{
+ ofproto->max_n_subfacet = MAX(ofproto->max_n_subfacet,
+ hmap_count(&ofproto->subfacets));
+}
+
+/* Compute exponentially weighted moving average, adding 'new' as the newest,
+ * most heavily weighted element. 'base' designates the rate of decay: after
+ * 'base' further updates, 'new''s weight in the EWMA decays to about 1/e
+ * (about .37). */
+static void
+exp_mavg(double *avg, int base, double new)
+{
+ *avg = (*avg * (base - 1) + new) / base;
+}
+
+static void
+update_moving_averages(struct ofproto_dpif *ofproto)
+{
+ const int min_ms = 60 * 1000; /* milliseconds in one minute. */
+
+ /* Update hourly averages on the minute boundaries. */
+ if (time_msec() - ofproto->last_minute >= min_ms) {
+ exp_mavg(&ofproto->hourly.add_rate, 60, ofproto->subfacet_add_count);
+ exp_mavg(&ofproto->hourly.del_rate, 60, ofproto->subfacet_del_count);
+
+ /* Update daily averages on the hour boundaries. */
+ if ((ofproto->last_minute - ofproto->created) / min_ms % 60 == 59) {
+ exp_mavg(&ofproto->daily.add_rate, 24, ofproto->hourly.add_rate);
+ exp_mavg(&ofproto->daily.del_rate, 24, ofproto->hourly.del_rate);
+ }
+
+ ofproto->total_subfacet_add_count += ofproto->subfacet_add_count;
+ ofproto->total_subfacet_del_count += ofproto->subfacet_del_count;
+ ofproto->subfacet_add_count = 0;
+ ofproto->subfacet_del_count = 0;
+ ofproto->last_minute += min_ms;
+ }
+}
static void
dpif_stats_update_hit_count(struct ofproto_dpif *ofproto, uint64_t delta)