[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH net-next] xen-netback: Grant copy the header instead of map and memcpy
On 27/03/14 11:35, Ian Campbell wrote: My manual measurements showed that if I also use the Xen patch which avoids TLB flush when the pages were not touched, I can easily get 9 - 9.3 Gbps with iperf. But I'll run some more automated tests.On Wed, 2014-03-26 at 21:18 +0000, Zoltan Kiss wrote:An old inefficiency of the TX path that we are grant mapping the first slot, and then copy the header part to the linear area. Instead, doing a grant copy for that header straight on is more reasonable. Especially because there are ongoing efforts to make Xen avoiding TLB flush after unmap when the page were not touched in Dom0. In the original way the memcpy ruined that. The key changes: - the vif has a tx_copy_ops array again - xenvif_tx_build_gops sets up the grant copy operations - we don't have to figure out whether the header and first frag are on the same grant mapped page or not Unrelated, but I've made a small refactoring in xenvif_get_extras as well.Just a few thoughts, not really based on close review of the code. Do you have any measurements for this series or workloads where it is particularly beneficial? You've added a second hypercall to tx_action, probably those can be combined into one vm exit by using a multicall. Yes, good idea! If nr_cops is zero, nr_gops should be too, but it can happen that we have only copy ops, but no grant ops (all the packets processed are < PKT_PROT_LEN). Actually there is a bug in tx_action, it shouldn't return when (nr_cops != 0) && (nr_gops == 0)Also you should omit either if their respective nr_?ops is zero (can nr_cops ever be zero?) N is already 1, we already copy only the first slot. But here we should be prepared for the unlikely situation that a guest sends 256 packets suddenly, all with one slot.Adding another MAX_PENDING_REQS sized array is unfortunate. Could we perhaps get away with only ever doing copy for the first N requests (for small N) in a frame and copying up the request, N should be chosen to be large enough to cover the more common cases (which I suppose is Windows which puts the network and transport headers in separate slots). This might allow the copy array to be smaller, at the expense of still doing the map+memcpy for some corner cases. Unfortunately the hypercalls expect an array of _one_ of them, so we can't put the 2 types into an union unless it's guaranteed that they have the same size. And they are expected to beOr (and I confess this is a skanky hack): we overlay tx_copy_ops and tx_map_ops in a union, and insert one set of ops from the front and the other from the end, taking great care around when and where they meet. static int xenvif_tx_check_gop(struct xenvif *vif, struct sk_buff *skb, - struct gnttab_map_grant_ref **gopp) + struct gnttab_map_grant_ref **gopp, + struct gnttab_copy **gopp_copy)I think a precursor patch which only does s/gopp/gopp_map/ would be beneficial. It's 5 renaming in 4 hunks, I think it's enough to do them in the same patch @@ -1164,7 +1147,9 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) return false; } -static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) +static unsigned xenvif_tx_build_gops(struct xenvif *vif, + int budget, + unsigned *copy_ops)I think you should turn the nr map ops into an explicit pointer return too, having one thing go via the formal return code and another via a pointer is a bit odd. Ok struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop; struct sk_buff *skb; @@ -1267,24 +1252,37 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) } } - xenvif_tx_create_gop(vif, pending_idx, &txreq, gop); - - gop++; - XENVIF_TX_CB(skb)->pending_idx = pending_idx; __skb_put(skb, data_len);Can't you allocate the skb with sufficient headroom? (or maybe I've forgotten again how skb payload management works and __skb_put is effectively free on an empty skb?) It effectively does: skb->tail += len; skb->len += len;So we can copy data_len between head and tail. The skb is already allocated in xenvif_alloc_skb with a buffer size NET_SKB_PAD + NET_IP_ALIGN + data_len, and and the headroom is NET_SKB_PAD + NET_IP_ALIGN. I think we should only grant copy the parts which goes to the linear part, because we would memcpy it anyway. It's expected that the stack won't touch anything else while the packet passes through. data_len is the size of the linear buffer here.+ vif->tx_copy_ops[*copy_ops].source.u.ref = txreq.gref; + vif->tx_copy_ops[*copy_ops].source.domid = vif->domid; + vif->tx_copy_ops[*copy_ops].source.offset = txreq.offset; + + vif->tx_copy_ops[*copy_ops].dest.u.gmfn = virt_to_mfn(skb->data); + vif->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF; + vif->tx_copy_ops[*copy_ops].dest.offset = offset_in_page(skb->data); + + vif->tx_copy_ops[*copy_ops].len = data_len;Do we want to copy the entire first frag even if it is e.g. a complete page? I'm not sure where the tradeoff lies between doing a grant copy of more than necessary and doing a map+memcpy when the map is already required for the page frag anyway. Then data_len will be txreq.size, we allocate the skb for that, and later on we call __pskb_pull_tail in xenvif_tx_submit to pull up for that (which is essentially map+memcpy). It's not optimal, but it's like that since the good old days. I agree it could be optimized, but let's change it in a different patch!What about the case where the first frag is less than PKT_PROT_LEN? I think you still do map+memcpy in that case? @@ -1375,6 +1374,7 @@ static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb) static int xenvif_tx_submit(struct xenvif *vif) { struct gnttab_map_grant_ref *gop = vif->tx_map_ops;Another candidate for a precursor patch renaming for clarity. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |