#include "ofproto-dpif-governor.h"
-#include <assert.h>
#include <stdlib.h>
#include "coverage.h"
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;
}
governor_destroy(struct governor *g)
{
if (g) {
- VLOG_INFO("%s: disengaging", g->name);
+ VLOG_INFO("disengaging");
free(g->table);
free(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;
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;
}
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, 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;
}