X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=ofproto%2Fofproto-dpif-governor.c;h=459f8715edb1cc1e8b433292a6d52e3e841afb9f;hb=6b4b2f598246e87237342a9179a0d29e202ebe65;hp=7e3ecfae16a33d70b46dded3cbefca03f61aad7d;hpb=e0edde6fee279cdbbf3c179f5f50adaf0c7c7f1e;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif-governor.c b/ofproto/ofproto-dpif-governor.c index 7e3ecfae1..459f8715e 100644 --- a/ofproto/ofproto-dpif-governor.c +++ b/ofproto/ofproto-dpif-governor.c @@ -18,7 +18,6 @@ #include "ofproto-dpif-governor.h" -#include #include #include "coverage.h" @@ -54,13 +53,11 @@ enum { MAX_ELAPSED = 5000 }; /* In milliseconds. */ static void governor_new_generation(struct governor *, unsigned int size); -/* Creates and returns a new governor named 'name' (which is used only for log - * messages). */ +/* Creates and returns a new governor. */ struct governor * -governor_create(const char *name) +governor_create(void) { struct governor *g = xzalloc(sizeof *g); - g->name = xstrdup(name); governor_new_generation(g, MIN_SIZE); return g; } @@ -70,7 +67,7 @@ void governor_destroy(struct governor *g) { if (g) { - VLOG_INFO("%s: disengaging", g->name); + VLOG_INFO("disengaging"); free(g->table); free(g); } @@ -93,7 +90,9 @@ governor_run(struct governor *g) void governor_wait(struct governor *g) { - poll_timer_wait_until(g->start + MAX_ELAPSED); + if (g->size > MIN_SIZE) { + poll_timer_wait_until(g->start + MAX_ELAPSED); + } } /* Returns true if 'g' has been doing only a minimal amount of work and thus @@ -114,11 +113,11 @@ governor_is_idle(struct governor *g) bool governor_should_install_flow(struct governor *g, uint32_t hash, int n) { + int old_count, new_count; bool install_flow; uint8_t *e; - int count; - assert(n > 0); + ovs_assert(n > 0); /* Count these packets and begin a new generation if necessary. */ g->n_packets += n; @@ -133,19 +132,38 @@ governor_should_install_flow(struct governor *g, uint32_t hash, int n) governor_new_generation(g, new_size); } + /* If we've set up most of the flows we've seen, then we're wasting time + * handling most packets one at a time, so in this case instead set up most + * flows directly and use the remaining flows as a sample set to adjust our + * criteria later. + * + * The definition of "most" is conservative, but the sample size is tuned + * based on a few experiments with TCP_CRR mode in netperf. */ + if (g->n_setups >= g->n_flows - g->n_flows / 16 + && g->n_flows >= 64 + && hash & 0x3f) { + g->n_shortcuts++; + return true; + } + /* Do hash table processing. * * Even-numbered hash values use high-order nibbles. * Odd-numbered hash values use low-order nibbles. */ e = &g->table[(hash >> 1) & (g->size - 1)]; - count = n + (hash & 1 ? *e >> 4 : *e & 0x0f); - if (count >= FLOW_SETUP_THRESHOLD) { + old_count = (hash & 1 ? *e >> 4 : *e & 0x0f); + if (!old_count) { + g->n_flows++; + } + new_count = n + old_count; + if (new_count >= FLOW_SETUP_THRESHOLD) { + g->n_setups++; install_flow = true; - count = 0; + new_count = 0; } else { install_flow = false; } - *e = hash & 1 ? (count << 4) | (*e & 0x0f) : (*e & 0xf0) | count; + *e = hash & 1 ? (new_count << 4) | (*e & 0x0f) : (*e & 0xf0) | new_count; return install_flow; } @@ -155,34 +173,39 @@ governor_should_install_flow(struct governor *g, uint32_t hash, int n) static void governor_new_generation(struct governor *g, unsigned int size) { - assert(size >= MIN_SIZE && size <= MAX_SIZE); - assert(is_pow2(size)); + ovs_assert(size >= MIN_SIZE && size <= MAX_SIZE); + ovs_assert(is_pow2(size)); /* Allocate new table, if necessary. */ if (g->size != size) { if (!g->size) { - VLOG_INFO("%s: engaging governor with %u kB hash table", - g->name, g->size / 1024); + VLOG_INFO("engaging governor with %u kB hash table", size / 1024); } else { - VLOG_INFO("%s: processed %u packets in %.2f s, " - "%s hash table to %u kB", - g->name, g->n_packets, + VLOG_INFO("processed %u packets in %.2f s, " + "%s hash table to %u kB " + "(%u hashes, %u setups, %u shortcuts)", + g->n_packets, (time_msec() - g->start) / 1000.0, size > g->size ? "enlarging" : "shrinking", - size / 1024); + size / 1024, + g->n_flows, g->n_setups, g->n_shortcuts); } free(g->table); g->table = xmalloc(size * sizeof *g->table); g->size = size; } else { - VLOG_DBG("%s: processed %u packets in %.2f s with %u kB hash table", - g->name, g->n_packets, (time_msec() - g->start) / 1000.0, - size / 1024); + VLOG_DBG("processed %u packets in %.2f s with %u kB hash table " + "(%u hashes, %u setups, %u shortcuts)", + g->n_packets, (time_msec() - g->start) / 1000.0, + size / 1024, g->n_flows, g->n_setups, g->n_shortcuts); } /* Clear data for next generation. */ memset(g->table, 0, size * sizeof *g->table); g->start = time_msec(); g->n_packets = 0; + g->n_flows /= 2; + g->n_setups /= 2; + g->n_shortcuts = 0; }