From: Jason Wang <hidden> Date: 2017-01-06 02:13:14
Hi:
This series tries to implement tx batching support for vhost. This was
done by using MSG_MORE as a hint for under layer socket. The backend
(e.g tap) can then batch the packets temporarily in a list and
submit it all once the number of bacthed exceeds a limitation.
Tests shows obvious improvement on guest pktgen over over
mlx4(noqueue) on host:
Mpps -+%
rx-frames = 0 0.91 +0%
rx-frames = 4 1.00 +9.8%
rx-frames = 8 1.00 +9.8%
rx-frames = 16 1.01 +10.9%
rx-frames = 32 1.07 +17.5%
rx-frames = 48 1.07 +17.5%
rx-frames = 64 1.08 +18.6%
rx-frames = 64 (no MSG_MORE) 0.91 +0%
Changes from V3:
- use ethtool instead of module parameter to control the maximum
number of batched packets
- avoid overhead when MSG_MORE were not set and no packet queued
Changes from V2:
- remove uselss queue limitation check (and we don't drop any packet now)
Changes from V1:
- drop NAPI handler since we don't use NAPI now
- fix the issues that may exceeds max pending of zerocopy
- more improvement on available buffer detection
- move the limitation of batched pacekts from vhost to tuntap
Please review.
Thanks
Jason Wang (3):
vhost: better detection of available buffers
vhost_net: tx batching
tun: rx batching
drivers/net/tun.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++----
drivers/vhost/net.c | 23 ++++++++++++++--
drivers/vhost/vhost.c | 8 ++++--
3 files changed, 96 insertions(+), 11 deletions(-)
--
2.7.4
From: Jason Wang <hidden> Date: 2017-01-06 02:13:15
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
From: Jason Wang <hidden> Date: 2017-01-06 02:13:16
This patch tries to utilize tuntap rx batching by peeking the tx
virtqueue during transmission, if there's more available buffers in
the virtqueue, set MSG_MORE flag for a hint for backend (e.g tuntap)
to batch the packets.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/net.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
@@ -351,6 +351,15 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net,returnr;}+staticboolvhost_exceeds_maxpend(structvhost_net*net)+{+structvhost_net_virtqueue*nvq=&net->vqs[VHOST_NET_VQ_TX];+structvhost_virtqueue*vq=&nvq->vq;++return(nvq->upend_idx+vq->num-VHOST_MAX_PEND)%UIO_MAXIOV+==nvq->done_idx;+}+/* Expects to be always run from workqueue - which acts as*read-sizecriticalsectionforourkindofRCU.*/staticvoidhandle_tx(structvhost_net*net)
@@ -394,8 +403,7 @@ static void handle_tx(struct vhost_net *net)/* If more outstanding DMAs, queue the work.*Handleupend_idxwraparound*/-if(unlikely((nvq->upend_idx+vq->num-VHOST_MAX_PEND)-%UIO_MAXIOV==nvq->done_idx))+if(unlikely(vhost_exceeds_maxpend(net)))break;head=vhost_net_tx_get_vq_desc(net,vq,vq->iov,
@@ -454,6 +462,16 @@ static void handle_tx(struct vhost_net *net)msg.msg_control=NULL;ubufs=NULL;}++total_len+=len;+if(total_len<VHOST_NET_WEIGHT&&+!vhost_vq_avail_empty(&net->dev,vq)&&+likely(!vhost_exceeds_maxpend(net))){+msg.msg_flags|=MSG_MORE;+}else{+msg.msg_flags&=~MSG_MORE;+}+/* TODO: Check specific error and bomb out unless ENOBUFS? */err=sock->ops->sendmsg(sock,&msg,len);if(unlikely(err<0)){
From: Jason Wang <hidden> Date: 2017-01-06 02:13:17
We can only process 1 packet at one time during sendmsg(). This often
lead bad cache utilization under heavy load. So this patch tries to do
some batching during rx before submitting them to host network
stack. This is done through accepting MSG_MORE as a hint from
sendmsg() caller, if it was set, batch the packet temporarily in a
linked list and submit them all once MSG_MORE were cleared.
Tests were done by pktgen (burst=128) in guest over mlx4(noqueue) on host:
Mpps -+%
rx-frames = 0 0.91 +0%
rx-frames = 4 1.00 +9.8%
rx-frames = 8 1.00 +9.8%
rx-frames = 16 1.01 +10.9%
rx-frames = 32 1.07 +17.5%
rx-frames = 48 1.07 +17.5%
rx-frames = 64 1.08 +18.6%
rx-frames = 64 (no MSG_MORE) 0.91 +0%
User were allowed to change per device batched packets through
ethtool -C rx-frames. NAPI_POLL_WEIGHT were used as upper limitation
to prevent bh from being disabled too long.
Signed-off-by: Jason Wang <redacted>
---
drivers/net/tun.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 6 deletions(-)
@@ -1140,10 +1142,45 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,returnskb;}+staticvoidtun_rx_batched(structtun_struct*tun,structtun_file*tfile,+structsk_buff*skb,intmore)+{+structsk_buff_head*queue=&tfile->sk.sk_write_queue;+structsk_buff_headprocess_queue;+u32rx_batched=tun->rx_batched;+boolrcv=false;++if(!rx_batched||(!more&&skb_queue_empty(queue))){+local_bh_disable();+netif_receive_skb(skb);+local_bh_enable();+return;+}++spin_lock(&queue->lock);+if(!more||skb_queue_len(queue)==rx_batched){+__skb_queue_head_init(&process_queue);+skb_queue_splice_tail_init(queue,&process_queue);+rcv=true;+}else{+__skb_queue_tail(queue,skb);+}+spin_unlock(&queue->lock);++if(rcv){+structsk_buff*nskb;+local_bh_disable();+while((nskb=__skb_dequeue(&process_queue)))+netif_receive_skb(nskb);+netif_receive_skb(skb);+local_bh_enable();+}+}+/* Get packet from user space buffer */staticssize_ttun_get_user(structtun_struct*tun,structtun_file*tfile,void*msg_control,structiov_iter*from,-intnoblock)+intnoblock,boolmore){structtun_pipi={0,cpu_to_be16(ETH_P_IP)};structsk_buff*skb;
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-01-06 19:47:34
On Fri, Jan 06, 2017 at 10:13:17AM +0800, Jason Wang wrote:
quoted hunk
We can only process 1 packet at one time during sendmsg(). This often
lead bad cache utilization under heavy load. So this patch tries to do
some batching during rx before submitting them to host network
stack. This is done through accepting MSG_MORE as a hint from
sendmsg() caller, if it was set, batch the packet temporarily in a
linked list and submit them all once MSG_MORE were cleared.
Tests were done by pktgen (burst=128) in guest over mlx4(noqueue) on host:
Mpps -+%
rx-frames = 0 0.91 +0%
rx-frames = 4 1.00 +9.8%
rx-frames = 8 1.00 +9.8%
rx-frames = 16 1.01 +10.9%
rx-frames = 32 1.07 +17.5%
rx-frames = 48 1.07 +17.5%
rx-frames = 64 1.08 +18.6%
rx-frames = 64 (no MSG_MORE) 0.91 +0%
User were allowed to change per device batched packets through
ethtool -C rx-frames. NAPI_POLL_WEIGHT were used as upper limitation
to prevent bh from being disabled too long.
Signed-off-by: Jason Wang <redacted>
---
drivers/net/tun.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 6 deletions(-)
@@ -1140,10 +1142,45 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,returnskb;}+staticvoidtun_rx_batched(structtun_struct*tun,structtun_file*tfile,+structsk_buff*skb,intmore)+{+structsk_buff_head*queue=&tfile->sk.sk_write_queue;+structsk_buff_headprocess_queue;+u32rx_batched=tun->rx_batched;+boolrcv=false;++if(!rx_batched||(!more&&skb_queue_empty(queue))){+local_bh_disable();+netif_receive_skb(skb);+local_bh_enable();+return;+}++spin_lock(&queue->lock);+if(!more||skb_queue_len(queue)==rx_batched){+__skb_queue_head_init(&process_queue);+skb_queue_splice_tail_init(queue,&process_queue);+rcv=true;+}else{+__skb_queue_tail(queue,skb);+}+spin_unlock(&queue->lock);++if(rcv){+structsk_buff*nskb;+local_bh_disable();+while((nskb=__skb_dequeue(&process_queue)))+netif_receive_skb(nskb);+netif_receive_skb(skb);+local_bh_enable();+}+}+/* Get packet from user space buffer */staticssize_ttun_get_user(structtun_struct*tun,structtun_file*tfile,void*msg_control,structiov_iter*from,-intnoblock)+intnoblock,boolmore){structtun_pipi={0,cpu_to_be16(ETH_P_IP)};structsk_buff*skb;
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-01-06 19:55:24
On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
quoted hunk
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
So again, this did not address the issue I pointed out in v1:
if we have 1 buffer in RX queue and
that is not enough to store the whole packet,
vhost_vq_avail_empty returns false, then we re-read
the descriptors again and again.
You have saved a single index access but not the more expensive
descriptor access.
I think that a way to address this could be to have this
return current index for the caller. Then as long as that
index isn't changed, you don't poke at descriptor ring.
So what should userspace do? Keep trying until it succeeds?
I think it's better to just use NAPI_POLL_WEIGHT instead and DTRT here.
Well, looking at how set_coalesce is implemented in other drivers,
-EINVAL is usually used when user give a value that exceeds the
limitation. For tuntap, what missed here is probably just a
documentation for coalescing in tuntap.txt. (Or extend ethtool to return
the max value). This seems much better than silently reduce the value to
the limitation.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Jason Wang <hidden> Date: 2017-01-09 02:59:16
On 2017年01月07日 03:55, Michael S. Tsirkin wrote:
On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
quoted
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
So again, this did not address the issue I pointed out in v1:
if we have 1 buffer in RX queue and
that is not enough to store the whole packet,
vhost_vq_avail_empty returns false, then we re-read
the descriptors again and again.
You have saved a single index access but not the more expensive
descriptor access.
Looks not, if I understand the code correctly, in this case,
get_rx_bufs() will return zero, and we will try to enable rx kick and
exit the loop.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-01-09 23:10:41
On Mon, Jan 09, 2017 at 10:59:16AM +0800, Jason Wang wrote:
On 2017年01月07日 03:55, Michael S. Tsirkin wrote:
quoted
On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
quoted
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
So again, this did not address the issue I pointed out in v1:
if we have 1 buffer in RX queue and
that is not enough to store the whole packet,
vhost_vq_avail_empty returns false, then we re-read
the descriptors again and again.
You have saved a single index access but not the more expensive
descriptor access.
Looks not, if I understand the code correctly, in this case, get_rx_bufs()
will return zero, and we will try to enable rx kick and exit the loop.
Thanks
I mean this:
while (vhost_can_busy_poll(vq->dev, endtime) &&
vhost_vq_avail_empty(vq->dev, vq))
cpu_relax();
preempt_enable();
r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
out_num, in_num, NULL, NULL);
vhost_vq_avail_empty returns false so we break out of the loop
and call vhost_get_vq_desc.
--
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
So what should userspace do? Keep trying until it succeeds?
I think it's better to just use NAPI_POLL_WEIGHT instead and DTRT here.
Well, looking at how set_coalesce is implemented in other drivers, -EINVAL
is usually used when user give a value that exceeds the limitation. For
tuntap, what missed here is probably just a documentation for coalescing in
tuntap.txt. (Or extend ethtool to return the max value). This seems much
better than silently reduce the value to the limitation.
Thanks
I don't think it's better, it's mostly that
1. there's a hardware limit so it does not change much
2. default is enabled and no one bothers changing
I don't see how will tuntap.txt help if we want to change it
in the future.
--
MST
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: Jason Wang <hidden> Date: 2017-01-10 02:22:42
On 2017年01月10日 07:10, Michael S. Tsirkin wrote:
On Mon, Jan 09, 2017 at 10:59:16AM +0800, Jason Wang wrote:
quoted
On 2017年01月07日 03:55, Michael S. Tsirkin wrote:
quoted
On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
quoted
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
So again, this did not address the issue I pointed out in v1:
if we have 1 buffer in RX queue and
that is not enough to store the whole packet,
vhost_vq_avail_empty returns false, then we re-read
the descriptors again and again.
You have saved a single index access but not the more expensive
descriptor access.
Looks not, if I understand the code correctly, in this case, get_rx_bufs()
will return zero, and we will try to enable rx kick and exit the loop.
Thanks
I mean this:
while (vhost_can_busy_poll(vq->dev, endtime) &&
vhost_vq_avail_empty(vq->dev, vq))
cpu_relax();
preempt_enable();
r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
out_num, in_num, NULL, NULL);
vhost_vq_avail_empty returns false so we break out of the loop
and call vhost_get_vq_desc.
So what should userspace do? Keep trying until it succeeds?
I think it's better to just use NAPI_POLL_WEIGHT instead and DTRT here.
Well, looking at how set_coalesce is implemented in other drivers, -EINVAL
is usually used when user give a value that exceeds the limitation. For
tuntap, what missed here is probably just a documentation for coalescing in
tuntap.txt. (Or extend ethtool to return the max value). This seems much
better than silently reduce the value to the limitation.
Thanks
I don't think it's better, it's mostly that
1. there's a hardware limit so it does not change much
2. default is enabled and no one bothers changing
I don't see how will tuntap.txt help if we want to change it
in the future.
Ok, so I will limit it to NAPI_POLL_WEIGHT if user gives a value that is
greater than that.
Thanks
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-01-10 02:57:40
On Tue, Jan 10, 2017 at 10:22:42AM +0800, Jason Wang wrote:
On 2017年01月10日 07:10, Michael S. Tsirkin wrote:
quoted
On Mon, Jan 09, 2017 at 10:59:16AM +0800, Jason Wang wrote:
quoted
On 2017年01月07日 03:55, Michael S. Tsirkin wrote:
quoted
On Fri, Jan 06, 2017 at 10:13:15AM +0800, Jason Wang wrote:
quoted
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
So again, this did not address the issue I pointed out in v1:
if we have 1 buffer in RX queue and
that is not enough to store the whole packet,
vhost_vq_avail_empty returns false, then we re-read
the descriptors again and again.
You have saved a single index access but not the more expensive
descriptor access.
Looks not, if I understand the code correctly, in this case, get_rx_bufs()
will return zero, and we will try to enable rx kick and exit the loop.
Thanks
I mean this:
while (vhost_can_busy_poll(vq->dev, endtime) &&
vhost_vq_avail_empty(vq->dev, vq))
cpu_relax();
preempt_enable();
r = vhost_get_vq_desc(vq, vq->iov, ARRAY_SIZE(vq->iov),
out_num, in_num, NULL, NULL);
vhost_vq_avail_empty returns false so we break out of the loop
and call vhost_get_vq_desc.
But this is the code for polling tx vq not rx I think?
Thanks