On Thu, Jan 28, 2016 at 5:56 PM, Daniele Di Proietto <diproiet...@vmware.com > wrote:
> When a group of packets arrives from a port, we loop through them to > initialize metadata and them we loop through them again to extract the > flow and perform the exact match classification. > > This commit combines the two loops into one, and initializes packet->md > in emc_processing() to improve performance. > > Since emc_processing() might also be called after recirculation (in > which case the metadata is already valid), an extra parameter is added > to support both cases. > > This commits also implements simple prefetching of packet metadata, > to further improve performance. > > Signed-off-by: Daniele Di Proietto <diproiet...@vmware.com> > This patch provides significant performance boost for DPDK single core packet forwarding rate. I was able to verify line rate forwarding of 64 byte packets over a 10G NIC. Nice job! Acked-by: Andy Zhou <az...@ovn.org> In comments inline : s/and them/and then/. Unfortunately, the code reality dropped. May be it is a small price to pay for optimizing fast path code? The following incremental patch may help to regain some lost code readability. Please feel free to fold it in if you like. diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index c38ff2d..43836d2 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -478,8 +478,9 @@ static void dp_netdev_execute_actions(struct dp_netdev_pmd_thread *pmd, const struct nlattr *actions, size_t actions_len); static void dp_netdev_input(struct dp_netdev_pmd_thread *, - struct dp_packet **, int cnt, - bool mdinit, odp_port_t port_no); + struct dp_packet **, int cnt, odp_port_t port_no); +static void dp_netdev_recirculate(struct dp_netdev_pmd_thread *, + struct dp_packet **, int cnt); static void dp_netdev_disable_upcall(struct dp_netdev *); static void dp_netdev_pmd_reload_done(struct dp_netdev_pmd_thread *pmd); @@ -2559,7 +2560,7 @@ dp_netdev_process_rxq_port(struct dp_netdev_pmd_thread *pmd, *recirc_depth_get() = 0; cycles_count_start(pmd); - dp_netdev_input(pmd, packets, cnt, false, port->port_no); + dp_netdev_input(pmd, packets, cnt, port->port_no); cycles_count_end(pmd, PMD_CYCLES_PROCESSING); } else if (error != EAGAIN && error != EOPNOTSUPP) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -3286,14 +3287,14 @@ dp_netdev_queue_batches(struct dp_packet *pkt, * The function returns the number of packets that needs to be processed in the * 'packets' array (they have been moved to the beginning of the vector). * - * If 'mdinit' is false, the metadata in 'packets' is not valid and must be + * If 'md_is_valid' is false, the metadata in 'packets' is not valid and must be * initialized by this function using 'port_no'. */ static inline size_t emc_processing(struct dp_netdev_pmd_thread *pmd, struct dp_packet **packets, size_t cnt, struct netdev_flow_key *keys, struct packet_batch batches[], size_t *n_batches, - bool mdinit,odp_port_t port_no) + bool md_is_valid, odp_port_t port_no) { struct emc_cache *flow_cache = &pmd->flow_cache; struct netdev_flow_key key; @@ -3314,7 +3315,7 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, struct dp_packet **packets, pkt_metadata_prefetch_init(&packets[i+1]->md); } - if (!mdinit) { + if (!md_is_valid) { pkt_metadata_init(&packets[i]->md, port_no); } miniflow_extract(packets[i], &key.mf); @@ -3482,11 +3483,11 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, * For performance reasons a caller may choose not to initialize the metadata * in 'packets': in this case 'mdinit' is false and this function needs to * initialize it using 'port_no'. If the metadata in 'packets' is already - * valid, 'mdinit' must be true and 'port_no' will be ignored. */ + * valid, 'md_is_valid' must be true and 'port_no' will be ignored. */ static void -dp_netdev_input(struct dp_netdev_pmd_thread *pmd, - struct dp_packet **packets, int cnt, - bool mdinit, odp_port_t port_no) +dp_netdev_input__(struct dp_netdev_pmd_thread *pmd, + struct dp_packet **packets, int cnt, + bool md_is_valid, odp_port_t port_no) { #if !defined(__CHECKER__) && !defined(_WIN32) const size_t PKT_ARRAY_SIZE = cnt; @@ -3501,7 +3502,7 @@ dp_netdev_input(struct dp_netdev_pmd_thread *pmd, n_batches = 0; newcnt = emc_processing(pmd, packets, cnt, keys, batches, &n_batches, - mdinit, port_no); + md_is_valid, port_no); if (OVS_UNLIKELY(newcnt)) { fast_path_processing(pmd, packets, newcnt, keys, batches, &n_batches); } @@ -3515,6 +3516,21 @@ dp_netdev_input(struct dp_netdev_pmd_thread *pmd, } } +static void +dp_netdev_input(struct dp_netdev_pmd_thread *pmd, + struct dp_packet **packets, int cnt, + odp_port_t port_no) +{ + dp_netdev_input__(pmd, packets, cnt, false, port_no); +} + +static void +dp_netdev_recirculate(struct dp_netdev_pmd_thread *pmd, + struct dp_packet **packets, int cnt) +{ + dp_netdev_input__(pmd, packets, cnt, true, 0); +} + struct dp_netdev_execute_aux { struct dp_netdev_pmd_thread *pmd; }; @@ -3618,7 +3634,7 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, err = push_tnl_action(dp, a, packets, cnt); if (!err) { (*depth)++; - dp_netdev_input(pmd, packets, cnt, true, 0); + dp_netdev_recirculate(pmd, packets, cnt); (*depth)--; } else { dp_netdev_drop_packets(tnl_pkt, cnt, !may_steal); @@ -3649,7 +3665,7 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, } (*depth)++; - dp_netdev_input(pmd, packets, cnt, true, 0); + dp_netdev_recirculate(pmd, packets, cnt); (*depth)--; } else { dp_netdev_drop_packets(tnl_pkt, cnt, !may_steal); @@ -3707,7 +3723,7 @@ dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt, } (*depth)++; - dp_netdev_input(pmd, packets, cnt, true, 0); + dp_netdev_recirculate(pmd, packets, cnt); (*depth)--; return; _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev