From: Jason Wang <hidden> Date: 2017-03-30 07:22:41
Hi all:
This series tries to implement rx batching for vhost-net. This is done
by batching the dequeuing from skb_array which was exported by
underlayer socket and pass the sbk back through msg_control to finish
userspace copying.
Tests shows at most 19% improvment on rx pps.
Please review.
Thanks
Changes from V1:
- switch to use for() in __ptr_ring_consume_batched()
- rename peek_head_len_batched() to fetch_skbs()
- use skb_array_consume_batched() instead of
skb_array_consume_batched_bh() since no consumer run in bh
- drop the lockless peeking patch since skb_array could be resized, so
it's not safe to call lockless one
Jason Wang (7):
ptr_ring: introduce batch dequeuing
skb_array: introduce batch dequeuing
tun: export skb_array
tap: export skb_array
tun: support receiving skb through msg_control
tap: support receiving skb from msg_control
vhost_net: try batch dequing from skb array
drivers/net/tap.c | 25 +++++++++++++++---
drivers/net/tun.c | 31 ++++++++++++++++------
drivers/vhost/net.c | 64 +++++++++++++++++++++++++++++++++++++++++++---
include/linux/if_tap.h | 5 ++++
include/linux/if_tun.h | 5 ++++
include/linux/ptr_ring.h | 65 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/skb_array.h | 25 ++++++++++++++++++
7 files changed, 204 insertions(+), 16 deletions(-)
--
2.7.4
From: Jason Wang <hidden> Date: 2017-03-30 07:22:45
This patch introduce a batched version of consuming, consumer can
dequeue more than one pointers from the ring at a time. We don't care
about the reorder of reading here so no need for compiler barrier.
Signed-off-by: Jason Wang <redacted>
---
include/linux/ptr_ring.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
@@ -297,6 +313,55 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r)returnptr;}+staticinlineintptr_ring_consume_batched(structptr_ring*r,+void**array,intn)+{+intret;++spin_lock(&r->consumer_lock);+ret=__ptr_ring_consume_batched(r,array,n);+spin_unlock(&r->consumer_lock);++returnret;+}++staticinlineintptr_ring_consume_batched_irq(structptr_ring*r,+void**array,intn)+{+intret;++spin_lock_irq(&r->consumer_lock);+ret=__ptr_ring_consume_batched(r,array,n);+spin_unlock_irq(&r->consumer_lock);++returnret;+}++staticinlineintptr_ring_consume_batched_any(structptr_ring*r,+void**array,intn)+{+unsignedlongflags;+intret;++spin_lock_irqsave(&r->consumer_lock,flags);+ret=__ptr_ring_consume_batched(r,array,n);+spin_unlock_irqrestore(&r->consumer_lock,flags);++returnret;+}++staticinlineintptr_ring_consume_batched_bh(structptr_ring*r,+void**array,intn)+{+intret;++spin_lock_bh(&r->consumer_lock);+ret=__ptr_ring_consume_batched(r,array,n);+spin_unlock_bh(&r->consumer_lock);++returnret;+}+/* Cast to structure type and call a function without discarding from FIFO.*Functionmustreturnavalue.*Callersmusttakeconsumer_lock.
From: Jason Wang <hidden> Date: 2017-03-30 07:23:07
This patch makes tun_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang <redacted>
---
drivers/net/tun.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
From: Jason Wang <hidden> Date: 2017-03-30 07:23:11
This patch makes tap_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang <redacted>
---
drivers/net/tap.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
From: Jason Wang <hidden> Date: 2017-03-30 07:23:13
We used to dequeue one skb during recvmsg() from skb_array, this could
be inefficient because of the bad cache utilization and spinlock
touching for each packet. This patch tries to batch them by calling
batch dequeuing helpers explicitly on the exported skb array and pass
the skb back through msg_control for underlayer socket to finish the
userspace copying.
Tests were done by XDP1:
- small buffer:
Before: 1.88Mpps
After : 2.25Mpps (+19.6%)
- mergeable buffer:
Before: 1.83Mpps
After : 2.10Mpps (+14.7%)
Signed-off-by: Jason Wang <redacted>
---
drivers/vhost/net.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 60 insertions(+), 4 deletions(-)
@@ -535,12 +561,14 @@ static int sk_has_rx_data(struct sock *sk)returnskb_queue_empty(&sk->sk_receive_queue);}-staticintvhost_net_rx_peek_head_len(structvhost_net*net,structsock*sk)+staticintvhost_net_rx_peek_head_len(structvhost_net*net,+structsock*sk){+structvhost_net_virtqueue*rvq=&net->vqs[VHOST_NET_VQ_RX];structvhost_net_virtqueue*nvq=&net->vqs[VHOST_NET_VQ_TX];structvhost_virtqueue*vq=&nvq->vq;unsignedlonguninitialized_var(endtime);-intlen=peek_head_len(sk);+intlen=peek_head_len(rvq,sk);if(!len&&vq->busyloop_timeout){/* Both tx vq and rx socket were polled here */
@@ -699,6 +727,8 @@ static void handle_rx(struct vhost_net *net)/* On error, stop handling until the next kick. */if(unlikely(headcount<0))gotoout;+if(nvq->rx_array)+msg.msg_control=nvq->rxq[nvq->rh++];/* On overrun, truncate and discard */if(unlikely(headcount>UIO_MAXIOV)){iov_iter_init(&msg.msg_iter,READ,vq->iov,1,1);
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-03-30 13:53:11
On Thu, Mar 30, 2017 at 03:22:24PM +0800, Jason Wang wrote:
quoted hunk
This patch introduce a batched version of consuming, consumer can
dequeue more than one pointers from the ring at a time. We don't care
about the reorder of reading here so no need for compiler barrier.
Signed-off-by: Jason Wang <redacted>
---
include/linux/ptr_ring.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
Can we use a shorter name? ptr_ring_consume_batch?
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ ptr = __ptr_ring_consume(r);
+ if (!ptr)
+ break;
+ array[i] = ptr;
+ }
+
+ return i;
+}
+
/*
* Note: resize (below) nests producer lock within consumer lock, so if you
* call this in interrupt or BH context, you must disable interrupts/BH when
I'd like to add a code comment here explaining why we don't
care about cpu or compiler reordering. And I think the reason is
in the way you use this API: in vhost it does not matter
if you get less entries than present in the ring.
That's ok but needs to be noted
in a code comment so people use this function correctly.
Also, I think you need to repeat the comment about cpu_relax
near this function: if someone uses it in a loop,
a compiler barrier is needed to prevent compiler from
optimizing it out.
I note that ptr_ring_consume currently lacks any of these
comments so I'm ok with merging as is, and I'll add
documentation on top.
Like this perhaps?
/* Consume up to n entries and return the number of entries consumed
* or 0 on ring empty.
* Note: this might return early with less entries than present in the
* ring.
* Note: callers invoking this in a loop must use a compiler barrier,
* for example cpu_relax(). Callers must take consumer_lock
* if the ring is ever resized - see e.g. ptr_ring_consume_batch.
*/
quoted hunk
@@ -297,6 +313,55 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r) return ptr; }+static inline int ptr_ring_consume_batched(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_irq(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_irq(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irq(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_any(struct ptr_ring *r,+ void **array, int n)+{+ unsigned long flags;+ int ret;++ spin_lock_irqsave(&r->consumer_lock, flags);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irqrestore(&r->consumer_lock, flags);++ return ret;+}++static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_bh(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_bh(&r->consumer_lock);++ return ret;+}+ /* Cast to structure type and call a function without discarding from FIFO. * Function must return a value. * Callers must take consumer_lock.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-03-30 14:21:49
On Thu, Mar 30, 2017 at 03:22:30PM +0800, Jason Wang wrote:
We used to dequeue one skb during recvmsg() from skb_array, this could
be inefficient because of the bad cache utilization
which cache does this refer to btw?
and spinlock
touching for each packet.
Do you mean the effect of extra two atomics here?
This patch tries to batch them by calling
batch dequeuing helpers explicitly on the exported skb array and pass
the skb back through msg_control for underlayer socket to finish the
userspace copying.
Tests were done by XDP1:
- small buffer:
Before: 1.88Mpps
After : 2.25Mpps (+19.6%)
- mergeable buffer:
Before: 1.83Mpps
After : 2.10Mpps (+14.7%)
Signed-off-by: Jason Wang <redacted>
Looks like I misread the code previously. More comments below,
sorry about not asking these questions earlier.
@@ -503,13 +512,30 @@ static void handle_tx(struct vhost_net *net) mutex_unlock(&vq->mutex); }-static int peek_head_len(struct sock *sk)+static int fetch_skbs(struct vhost_net_virtqueue *rvq)+{+ if (rvq->rh != rvq->rt)+ goto out;++ rvq->rh = rvq->rt = 0;+ rvq->rt = skb_array_consume_batched(rvq->rx_array, rvq->rxq,+ VHOST_RX_BATCH);+ if (!rvq->rt)+ return 0;+out:+ return __skb_array_len_with_tag(rvq->rxq[rvq->rh]);+}++static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk) { struct socket *sock = sk->sk_socket; struct sk_buff *head; int len = 0; unsigned long flags;+ if (rvq->rx_array)+ return fetch_skbs(rvq);+ if (sock->ops->peek_len) return sock->ops->peek_len(sock);
@@ -535,12 +561,14 @@ static int sk_has_rx_data(struct sock *sk) return skb_queue_empty(&sk->sk_receive_queue); }-static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk)+static int vhost_net_rx_peek_head_len(struct vhost_net *net,+ struct sock *sk) {+ struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX]; struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *vq = &nvq->vq; unsigned long uninitialized_var(endtime);- int len = peek_head_len(sk);+ int len = peek_head_len(rvq, sk); if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */
@@ -561,7 +589,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) vhost_poll_queue(&vq->poll); mutex_unlock(&vq->mutex);- len = peek_head_len(sk);+ len = peek_head_len(rvq, sk); } return len;
@@ -699,6 +727,8 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out;+ if (nvq->rx_array)+ msg.msg_control = nvq->rxq[nvq->rh++]; /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
So there's a bit of a mystery here. vhost code isn't
batched, all we are batching is the fetch from the tun ring.
So what is the source of the speedup?
Are queued spinlocks that expensive? They shouldn't be ...
Could you try using virt_spin_lock instead (at least as a quick hack)
to see whether that helps?
So I didn't realise it but of course the effect will be
dropped packets if we just connect and disconnect without
consuming anything.
So I think it's worth it to try analysing the speedup a bit
and see whether we can get the gains without queueing
the skbs in vhost.
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-03-30 15:03:09
On Thu, Mar 30, 2017 at 03:22:29PM +0800, Jason Wang wrote:
quoted hunk
This patch makes tap_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang <redacted>
---
drivers/net/tap.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-03-30 15:06:38
On Thu, Mar 30, 2017 at 03:22:28PM +0800, Jason Wang wrote:
This patch makes tun_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang <redacted>
Do we need to bother with tun? I didn't realize one
can even use that with vhost. What would be the point of
all the virtio header stuff dealing with checksums etc?
Even if you see a use-case is it worth optimizing?
From: Jason Wang <hidden> Date: 2017-03-31 03:52:37
On 2017年03月30日 21:53, Michael S. Tsirkin wrote:
On Thu, Mar 30, 2017 at 03:22:24PM +0800, Jason Wang wrote:
quoted
This patch introduce a batched version of consuming, consumer can
dequeue more than one pointers from the ring at a time. We don't care
about the reorder of reading here so no need for compiler barrier.
Signed-off-by: Jason Wang <redacted>
---
include/linux/ptr_ring.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
Can we use a shorter name? ptr_ring_consume_batch?
Ok, but at least we need to keep the prefix since there's a locked version.
quoted
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ ptr = __ptr_ring_consume(r);
+ if (!ptr)
+ break;
+ array[i] = ptr;
+ }
+
+ return i;
+}
+
/*
* Note: resize (below) nests producer lock within consumer lock, so if you
* call this in interrupt or BH context, you must disable interrupts/BH when
I'd like to add a code comment here explaining why we don't
care about cpu or compiler reordering. And I think the reason is
in the way you use this API: in vhost it does not matter
if you get less entries than present in the ring.
That's ok but needs to be noted
in a code comment so people use this function correctly.
Interesting, but I still think it's not necessary.
If consumer is doing a busy polling, it will eventually get the entries.
If the consumer need notification from producer, it should drain the
queue which means it need enable notification before last try of
consuming call, otherwise it was a bug. The batch consuming function in
this patch can guarantee return at least one pointer if there's many,
this looks sufficient for the correctness?
Thanks
Also, I think you need to repeat the comment about cpu_relax
near this function: if someone uses it in a loop,
a compiler barrier is needed to prevent compiler from
optimizing it out.
I note that ptr_ring_consume currently lacks any of these
comments so I'm ok with merging as is, and I'll add
documentation on top.
Like this perhaps?
/* Consume up to n entries and return the number of entries consumed
* or 0 on ring empty.
* Note: this might return early with less entries than present in the
* ring.
* Note: callers invoking this in a loop must use a compiler barrier,
* for example cpu_relax(). Callers must take consumer_lock
* if the ring is ever resized - see e.g. ptr_ring_consume_batch.
*/
quoted
@@ -297,6 +313,55 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r) return ptr; }+static inline int ptr_ring_consume_batched(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_irq(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_irq(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irq(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_any(struct ptr_ring *r,+ void **array, int n)+{+ unsigned long flags;+ int ret;++ spin_lock_irqsave(&r->consumer_lock, flags);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irqrestore(&r->consumer_lock, flags);++ return ret;+}++static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_bh(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_bh(&r->consumer_lock);++ return ret;+}+ /* Cast to structure type and call a function without discarding from FIFO. * Function must return a value. * Callers must take consumer_lock.
From: Jason Wang <hidden> Date: 2017-03-31 04:02:12
On 2017年03月30日 22:21, Michael S. Tsirkin wrote:
On Thu, Mar 30, 2017 at 03:22:30PM +0800, Jason Wang wrote:
quoted
We used to dequeue one skb during recvmsg() from skb_array, this could
be inefficient because of the bad cache utilization
which cache does this refer to btw?
Both icache and dcache more or less.
quoted
and spinlock
touching for each packet.
Do you mean the effect of extra two atomics here?
In fact four, packet length peeking needs another two.
quoted
This patch tries to batch them by calling
batch dequeuing helpers explicitly on the exported skb array and pass
the skb back through msg_control for underlayer socket to finish the
userspace copying.
Tests were done by XDP1:
- small buffer:
Before: 1.88Mpps
After : 2.25Mpps (+19.6%)
- mergeable buffer:
Before: 1.83Mpps
After : 2.10Mpps (+14.7%)
Signed-off-by: Jason Wang <redacted>
Looks like I misread the code previously. More comments below,
sorry about not asking these questions earlier.
@@ -503,13 +512,30 @@ static void handle_tx(struct vhost_net *net) mutex_unlock(&vq->mutex); }-static int peek_head_len(struct sock *sk)+static int fetch_skbs(struct vhost_net_virtqueue *rvq)+{+ if (rvq->rh != rvq->rt)+ goto out;++ rvq->rh = rvq->rt = 0;+ rvq->rt = skb_array_consume_batched(rvq->rx_array, rvq->rxq,+ VHOST_RX_BATCH);+ if (!rvq->rt)+ return 0;+out:+ return __skb_array_len_with_tag(rvq->rxq[rvq->rh]);+}++static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk) { struct socket *sock = sk->sk_socket; struct sk_buff *head; int len = 0; unsigned long flags;+ if (rvq->rx_array)+ return fetch_skbs(rvq);+ if (sock->ops->peek_len) return sock->ops->peek_len(sock);
@@ -535,12 +561,14 @@ static int sk_has_rx_data(struct sock *sk) return skb_queue_empty(&sk->sk_receive_queue); }-static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk)+static int vhost_net_rx_peek_head_len(struct vhost_net *net,+ struct sock *sk) {+ struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX]; struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX]; struct vhost_virtqueue *vq = &nvq->vq; unsigned long uninitialized_var(endtime);- int len = peek_head_len(sk);+ int len = peek_head_len(rvq, sk); if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */
@@ -561,7 +589,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) vhost_poll_queue(&vq->poll); mutex_unlock(&vq->mutex);- len = peek_head_len(sk);+ len = peek_head_len(rvq, sk); } return len;
@@ -699,6 +727,8 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out;+ if (nvq->rx_array)+ msg.msg_control = nvq->rxq[nvq->rh++]; /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
So there's a bit of a mystery here. vhost code isn't
batched, all we are batching is the fetch from the tun ring.
I've already had vhost batching code on top (e.g descriptor indices
prefetching and used ring batched updating like dpdk). Baching dequing
from skb array is the requirement for them.
Are queued spinlocks that expensive? They shouldn't be ...
Could you try using virt_spin_lock instead (at least as a quick hack)
to see whether that helps?
From: Jason Wang <hidden> Date: 2017-03-31 04:07:54
On 2017年03月30日 23:03, Michael S. Tsirkin wrote:
On Thu, Mar 30, 2017 at 03:22:29PM +0800, Jason Wang wrote:
quoted
This patch makes tap_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang<redacted>
---
drivers/net/tap.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
From: Jason Wang <hidden> Date: 2017-03-31 04:10:24
On 2017年03月30日 23:06, Michael S. Tsirkin wrote:
On Thu, Mar 30, 2017 at 03:22:28PM +0800, Jason Wang wrote:
quoted
This patch makes tun_recvmsg() can receive from skb from its caller
through msg_control. Vhost_net will be the first user.
Signed-off-by: Jason Wang<redacted>
Do we need to bother with tun? I didn't realize one
can even use that with vhost. What would be the point of
all the virtio header stuff dealing with checksums etc?
Even if you see a use-case is it worth optimizing?
It's for tap in fact. I use "tun" just because we have already had a
tap.c which is used by macvtap.
Thanks
From: Jason Wang <hidden> Date: 2017-03-31 06:47:50
On 2017年03月31日 12:02, Jason Wang wrote:
On 2017年03月30日 22:21, Michael S. Tsirkin wrote:
quoted
On Thu, Mar 30, 2017 at 03:22:30PM +0800, Jason Wang wrote:
quoted
We used to dequeue one skb during recvmsg() from skb_array, this could
be inefficient because of the bad cache utilization
which cache does this refer to btw?
Both icache and dcache more or less.
quoted
quoted
and spinlock
touching for each packet.
Do you mean the effect of extra two atomics here?
In fact four, packet length peeking needs another two.
quoted
quoted
This patch tries to batch them by calling
batch dequeuing helpers explicitly on the exported skb array and pass
the skb back through msg_control for underlayer socket to finish the
userspace copying.
Tests were done by XDP1:
- small buffer:
Before: 1.88Mpps
After : 2.25Mpps (+19.6%)
- mergeable buffer:
Before: 1.83Mpps
After : 2.10Mpps (+14.7%)
Signed-off-by: Jason Wang <redacted>
Looks like I misread the code previously. More comments below,
sorry about not asking these questions earlier.
@@ -503,13 +512,30 @@ static void handle_tx(struct vhost_net *net) mutex_unlock(&vq->mutex); } -static int peek_head_len(struct sock *sk)+static int fetch_skbs(struct vhost_net_virtqueue *rvq)+{+ if (rvq->rh != rvq->rt)+ goto out;++ rvq->rh = rvq->rt = 0;+ rvq->rt = skb_array_consume_batched(rvq->rx_array, rvq->rxq,+ VHOST_RX_BATCH);+ if (!rvq->rt)+ return 0;+out:+ return __skb_array_len_with_tag(rvq->rxq[rvq->rh]);+}++static int peek_head_len(struct vhost_net_virtqueue *rvq, struct
sock *sk)
{
struct socket *sock = sk->sk_socket;
struct sk_buff *head;
int len = 0;
unsigned long flags;
+ if (rvq->rx_array)
+ return fetch_skbs(rvq);
+
if (sock->ops->peek_len)
return sock->ops->peek_len(sock);
@@ -535,12 +561,14 @@ static int sk_has_rx_data(struct sock *sk)
return skb_queue_empty(&sk->sk_receive_queue);
}
-static int vhost_net_rx_peek_head_len(struct vhost_net *net,
struct sock *sk)
+static int vhost_net_rx_peek_head_len(struct vhost_net *net,
+ struct sock *sk)
{
+ struct vhost_net_virtqueue *rvq = &net->vqs[VHOST_NET_VQ_RX];
struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
struct vhost_virtqueue *vq = &nvq->vq;
unsigned long uninitialized_var(endtime);
- int len = peek_head_len(sk);
+ int len = peek_head_len(rvq, sk);
if (!len && vq->busyloop_timeout) {
/* Both tx vq and rx socket were polled here */
@@ -561,7 +589,7 @@ static int vhost_net_rx_peek_head_len(struct
vhost_net *net, struct sock *sk)
vhost_poll_queue(&vq->poll);
mutex_unlock(&vq->mutex);
- len = peek_head_len(sk);
+ len = peek_head_len(rvq, sk);
}
return len;
@@ -699,6 +727,8 @@ static void handle_rx(struct vhost_net *net) /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) goto out;+ if (nvq->rx_array)+ msg.msg_control = nvq->rxq[nvq->rh++]; /* On overrun, truncate and discard */ if (unlikely(headcount > UIO_MAXIOV)) { iov_iter_init(&msg.msg_iter, READ, vq->iov, 1, 1);
So there's a bit of a mystery here. vhost code isn't
batched, all we are batching is the fetch from the tun ring.
I've already had vhost batching code on top (e.g descriptor indices
prefetching and used ring batched updating like dpdk). Baching dequing
from skb array is the requirement for them.
Are queued spinlocks that expensive? They shouldn't be ...
Could you try using virt_spin_lock instead (at least as a quick hack)
to see whether that helps?
Will try.
I suspect it will have much difference, virt_spin_lock() has:
do {
while (atomic_read(&lock->val) != 0)
cpu_relax();
} while (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) != 0);
while queued_spin_lock():
val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
if (likely(val == 0))
return;
queued_spin_lock_slowpath(lock, val);
Since no other consumers during the test, the only difference is queued
version use a relaxed version of atomic_cmpxchg_acquire().
Thanks
quoted
quoted
@@ -841,6 +871,8 @@ static int vhost_net_open(struct inode *inode,
From: "Michael S. Tsirkin" <mst@redhat.com> Date: 2017-03-31 14:31:45
On Fri, Mar 31, 2017 at 11:52:24AM +0800, Jason Wang wrote:
On 2017年03月30日 21:53, Michael S. Tsirkin wrote:
quoted
On Thu, Mar 30, 2017 at 03:22:24PM +0800, Jason Wang wrote:
quoted
This patch introduce a batched version of consuming, consumer can
dequeue more than one pointers from the ring at a time. We don't care
about the reorder of reading here so no need for compiler barrier.
Signed-off-by: Jason Wang <redacted>
---
include/linux/ptr_ring.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
Can we use a shorter name? ptr_ring_consume_batch?
Ok, but at least we need to keep the prefix since there's a locked version.
quoted
quoted
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ ptr = __ptr_ring_consume(r);
+ if (!ptr)
+ break;
+ array[i] = ptr;
+ }
+
+ return i;
+}
+
/*
* Note: resize (below) nests producer lock within consumer lock, so if you
* call this in interrupt or BH context, you must disable interrupts/BH when
I'd like to add a code comment here explaining why we don't
care about cpu or compiler reordering. And I think the reason is
in the way you use this API: in vhost it does not matter
if you get less entries than present in the ring.
That's ok but needs to be noted
in a code comment so people use this function correctly.
Interesting, but I still think it's not necessary.
If consumer is doing a busy polling, it will eventually get the entries. If
the consumer need notification from producer, it should drain the queue
which means it need enable notification before last try of consuming call,
otherwise it was a bug. The batch consuming function in this patch can
guarantee return at least one pointer if there's many, this looks sufficient
for the correctness?
Thanks
You ask for N entries but get N-1. This seems to imply the
ring is now empty. Do we guarantee this?
quoted
Also, I think you need to repeat the comment about cpu_relax
near this function: if someone uses it in a loop,
a compiler barrier is needed to prevent compiler from
optimizing it out.
I note that ptr_ring_consume currently lacks any of these
comments so I'm ok with merging as is, and I'll add
documentation on top.
Like this perhaps?
/* Consume up to n entries and return the number of entries consumed
* or 0 on ring empty.
* Note: this might return early with less entries than present in the
* ring.
* Note: callers invoking this in a loop must use a compiler barrier,
* for example cpu_relax(). Callers must take consumer_lock
* if the ring is ever resized - see e.g. ptr_ring_consume_batch.
*/
quoted
@@ -297,6 +313,55 @@ static inline void *ptr_ring_consume_bh(struct ptr_ring *r) return ptr; }+static inline int ptr_ring_consume_batched(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_irq(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_irq(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irq(&r->consumer_lock);++ return ret;+}++static inline int ptr_ring_consume_batched_any(struct ptr_ring *r,+ void **array, int n)+{+ unsigned long flags;+ int ret;++ spin_lock_irqsave(&r->consumer_lock, flags);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_irqrestore(&r->consumer_lock, flags);++ return ret;+}++static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,+ void **array, int n)+{+ int ret;++ spin_lock_bh(&r->consumer_lock);+ ret = __ptr_ring_consume_batched(r, array, n);+ spin_unlock_bh(&r->consumer_lock);++ return ret;+}+ /* Cast to structure type and call a function without discarding from FIFO. * Function must return a value. * Callers must take consumer_lock.
From: Jason Wang <hidden> Date: 2017-04-01 05:14:20
On 2017年03月31日 22:31, Michael S. Tsirkin wrote:
On Fri, Mar 31, 2017 at 11:52:24AM +0800, Jason Wang wrote:
quoted
On 2017年03月30日 21:53, Michael S. Tsirkin wrote:
quoted
On Thu, Mar 30, 2017 at 03:22:24PM +0800, Jason Wang wrote:
quoted
This patch introduce a batched version of consuming, consumer can
dequeue more than one pointers from the ring at a time. We don't care
about the reorder of reading here so no need for compiler barrier.
Signed-off-by: Jason Wang<redacted>
---
include/linux/ptr_ring.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
Can we use a shorter name? ptr_ring_consume_batch?
Ok, but at least we need to keep the prefix since there's a locked version.
quoted
quoted
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < n; i++) {
+ ptr = __ptr_ring_consume(r);
+ if (!ptr)
+ break;
+ array[i] = ptr;
+ }
+
+ return i;
+}
+
/*
* Note: resize (below) nests producer lock within consumer lock, so if you
* call this in interrupt or BH context, you must disable interrupts/BH when
I'd like to add a code comment here explaining why we don't
care about cpu or compiler reordering. And I think the reason is
in the way you use this API: in vhost it does not matter
if you get less entries than present in the ring.
That's ok but needs to be noted
in a code comment so people use this function correctly.
Interesting, but I still think it's not necessary.
If consumer is doing a busy polling, it will eventually get the entries. If
the consumer need notification from producer, it should drain the queue
which means it need enable notification before last try of consuming call,
otherwise it was a bug. The batch consuming function in this patch can
guarantee return at least one pointer if there's many, this looks sufficient
for the correctness?
Thanks
You ask for N entries but get N-1. This seems to imply the
ring is now empty. Do we guarantee this?
I think consumer can not assume ring is empty consider producer can
produce at the same time. It need enable notification and do another
poll in this case.
Thanks