The key to getting good performance on the netperf CRR test seems to be to handle the first packet of each new flow as quickly as possible. Until now, we've only had one opportunity to do that on each trip through the main poll loop. One way to improve would be to make that poll loop circulate more quickly. My experiments show, however, that even just commenting out the slower parts of the poll loop yield minimal improvement.
This commit takes another approach. Instead of making the poll loop overall faster, it invokes the performance-critical parts of it more than once during each poll loop. My measurements show that this commit improves netperf CRR performance by 24% versus the previous commit, for an overall improvement of 87% versus the baseline just before the commit that removed the poll_fd_woke(). With this commit, ovs-benchmark performance has also improved by 13% overall since that baseline. --- v2: Added comments. ofproto/ofproto-dpif.c | 34 ++++++++++++++++++++-------------- ofproto/ofproto-provider.h | 8 ++++++++ ofproto/ofproto.c | 14 ++++++++++++++ ofproto/ofproto.h | 1 + vswitchd/bridge.c | 16 ++++++++++++++++ vswitchd/bridge.h | 3 ++- vswitchd/ovs-vswitchd.c | 2 ++ 7 files changed, 63 insertions(+), 15 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index ac1e44d..fdd744b 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -581,19 +581,12 @@ destruct(struct ofproto *ofproto_) dpif_close(ofproto->dpif); } -static int -run(struct ofproto *ofproto_) +static void +run_fast(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); - struct ofport_dpif *ofport; - struct ofbundle *bundle; unsigned int work; - if (!clogged) { - complete_operations(ofproto); - } - dpif_run(ofproto->dpif); - /* Handle one or more batches of upcalls, until there's nothing left to do * or until we do a fixed total amount of work. * @@ -606,14 +599,26 @@ run(struct ofproto *ofproto_) work = 0; while (work < FLOW_MISS_MAX_BATCH) { int retval = handle_upcalls(ofproto, FLOW_MISS_MAX_BATCH - work); - if (retval < 0) { - return -retval; - } else if (!retval) { + if (retval <= 0) { break; - } else { - work += retval; } + work += retval; } +} + +static int +run(struct ofproto *ofproto_) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct ofport_dpif *ofport; + struct ofbundle *bundle; + + if (!clogged) { + complete_operations(ofproto); + } + dpif_run(ofproto->dpif); + + run_fast(ofproto_); if (timer_expired(&ofproto->next_expiration)) { int delay = expire(ofproto); @@ -5366,6 +5371,7 @@ const struct ofproto_class ofproto_dpif_class = { destruct, dealloc, run, + run_fast, wait, flush, get_features, diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 8908dc0..54127d2 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -329,6 +329,14 @@ struct ofproto_class { */ int (*run)(struct ofproto *ofproto); + /* Performs periodic activity required by 'ofproto' that needs to be done + * with the least possible latency. + * + * This is run multiple times per main loop. An ofproto provider may + * implement it or not, according to whether it provides a performance + * boost for that ofproto implementation. */ + void (*run_fast)(struct ofproto *ofproto); + /* Causes the poll loop to wake up when 'ofproto''s 'run' function needs to * be called, e.g. by calling the timer or fd waiting functions in * poll-loop.h. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 60cf524..ddc9540 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -908,6 +908,20 @@ ofproto_run(struct ofproto *p) return 0; } +/* Performs periodic activity required by 'ofproto' that needs to be done + * with the least possible latency. + * + * It makes sense to call this function a couple of times per poll loop, to + * provide a significant performance boost on some benchmarks with the + * ofproto-dpif implementation. */ +void +ofproto_run_fast(struct ofproto *p) +{ + if (p->ofproto_class->run_fast) { + p->ofproto_class->run_fast(p); + } +} + void ofproto_wait(struct ofproto *p) { diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 5a99d46..45f3f36 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -139,6 +139,7 @@ void ofproto_destroy(struct ofproto *); int ofproto_delete(const char *name, const char *type); int ofproto_run(struct ofproto *); +void ofproto_run_fast(struct ofproto *); void ofproto_wait(struct ofproto *); bool ofproto_is_alive(const struct ofproto *); diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 378a08c..9db9409 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -1765,6 +1765,22 @@ refresh_cfm_stats(void) } } +/* Performs periodic activity required by bridges that needs to be done with + * the least possible latency. + * + * It makes sense to call this function a couple of times per poll loop, to + * provide a significant performance boost on some benchmarks with ofprotos + * that use the ofproto-dpif implementation. */ +void +bridge_run_fast(void) +{ + struct bridge *br; + + HMAP_FOR_EACH (br, node, &all_bridges) { + ofproto_run_fast(br->ofproto); + } +} + void bridge_run(void) { diff --git a/vswitchd/bridge.h b/vswitchd/bridge.h index 32b581e..2d38833 100644 --- a/vswitchd/bridge.h +++ b/vswitchd/bridge.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008, 2009, 2010 Nicira Networks +/* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ void bridge_init(const char *remote); void bridge_exit(void); void bridge_run(void); +void bridge_run_fast(void); void bridge_wait(void); #endif /* bridge.h */ diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index bdc3533..301d073 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -92,7 +92,9 @@ main(int argc, char *argv[]) if (signal_poll(sighup)) { vlog_reopen_log_file(); } + bridge_run_fast(); bridge_run(); + bridge_run_fast(); unixctl_server_run(unixctl); netdev_run(); -- 1.7.4.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev