* [PATCH net-next 1/2] netvsc: fix NAPI performance regression
2017-03-20 20:28 [PATCH net-next 0/2] netvsc: performance regressions in net-next Stephen Hemminger
@ 2017-03-20 20:28 ` Stephen Hemminger
2017-03-20 20:28 ` [PATCH net-next 2/2] vmbus: no longer expose iterator internals Stephen Hemminger
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Stephen Hemminger @ 2017-03-20 20:28 UTC (permalink / raw)
To: kys, davem; +Cc: haiyangz, netdev, Stephen Hemminger
When using NAPI, the single stream performance declined signifcantly
because the poll routine was updating host after every burst
of packets. This excess signalling caused host throttling.
This fix restores the old behavior. Host is only signalled
after the ring has been emptied.
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
drivers/net/hyperv/hyperv_net.h | 1 +
drivers/net/hyperv/netvsc.c | 41 ++++++++++++++++++-----------------------
2 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index 6b5f75217694..a33f2ee86044 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -723,6 +723,7 @@ struct net_device_context {
/* Per channel data */
struct netvsc_channel {
struct vmbus_channel *channel;
+ const struct vmpacket_descriptor *desc;
struct napi_struct napi;
struct multi_send_data msd;
struct multi_recv_comp mrc;
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 989b7cd99380..727762d0f13b 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -1173,7 +1173,6 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
struct vmbus_channel *channel,
struct netvsc_device *net_device,
struct net_device *ndev,
- u64 request_id,
const struct vmpacket_descriptor *desc)
{
struct net_device_context *net_device_ctx = netdev_priv(ndev);
@@ -1195,7 +1194,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
default:
netdev_err(ndev, "unhandled packet type %d, tid %llx\n",
- desc->type, request_id);
+ desc->type, desc->trans_id);
break;
}
@@ -1222,28 +1221,20 @@ int netvsc_poll(struct napi_struct *napi, int budget)
u16 q_idx = channel->offermsg.offer.sub_channel_index;
struct net_device *ndev = hv_get_drvdata(device);
struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
- const struct vmpacket_descriptor *desc;
int work_done = 0;
- desc = hv_pkt_iter_first(channel);
- while (desc) {
- int count;
+ /* If starting a new interval */
+ if (!nvchan->desc)
+ nvchan->desc = hv_pkt_iter_first(channel);
- count = netvsc_process_raw_pkt(device, channel, net_device,
- ndev, desc->trans_id, desc);
- work_done += count;
- desc = __hv_pkt_iter_next(channel, desc);
-
- /* If receive packet budget is exhausted, reschedule */
- if (work_done >= budget) {
- work_done = budget;
- break;
- }
+ while (nvchan->desc && work_done < budget) {
+ work_done += netvsc_process_raw_pkt(device, channel, net_device,
+ ndev, nvchan->desc);
+ nvchan->desc = hv_pkt_iter_next(channel, nvchan->desc);
}
- hv_pkt_iter_close(channel);
- /* If budget was not exhausted and
- * not doing busy poll
+ /* If receive ring was exhausted
+ * and not doing busy poll
* then re-enable host interrupts
* and reschedule if ring is not empty.
*/
@@ -1253,7 +1244,9 @@ int netvsc_poll(struct napi_struct *napi, int budget)
napi_reschedule(napi);
netvsc_chk_recv_comp(net_device, channel, q_idx);
- return work_done;
+
+ /* Driver may overshoot since multiple packets per descriptor */
+ return min(work_done, budget);
}
/* Call back when data is available in host ring buffer.
@@ -1263,10 +1256,12 @@ void netvsc_channel_cb(void *context)
{
struct netvsc_channel *nvchan = context;
- /* disable interupts from host */
- hv_begin_read(&nvchan->channel->inbound);
+ if (napi_schedule_prep(&nvchan->napi)) {
+ /* disable interupts from host */
+ hv_begin_read(&nvchan->channel->inbound);
- napi_schedule(&nvchan->napi);
+ __napi_schedule(&nvchan->napi);
+ }
}
/*
--
2.11.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net-next 2/2] vmbus: no longer expose iterator internals
2017-03-20 20:28 [PATCH net-next 0/2] netvsc: performance regressions in net-next Stephen Hemminger
2017-03-20 20:28 ` [PATCH net-next 1/2] netvsc: fix NAPI performance regression Stephen Hemminger
@ 2017-03-20 20:28 ` Stephen Hemminger
2017-03-20 20:31 ` [PATCH net-next 0/2] netvsc: performance regressions in net-next Stephen Hemminger
2017-03-22 18:22 ` David Miller
3 siblings, 0 replies; 6+ messages in thread
From: Stephen Hemminger @ 2017-03-20 20:28 UTC (permalink / raw)
To: kys, davem; +Cc: haiyangz, netdev, Stephen Hemminger
Since NAPI no longer needs to jump out of iterator early,
no need to expose the internal iterator steps.
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
drivers/hv/ring_buffer.c | 51 ++++++++++++++++++++++++------------------------
include/linux/hyperv.h | 22 +--------------------
2 files changed, 27 insertions(+), 46 deletions(-)
diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c
index c3f1a9e33cef..280e2010913f 100644
--- a/drivers/hv/ring_buffer.c
+++ b/drivers/hv/ring_buffer.c
@@ -458,13 +458,31 @@ struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
/*
+ * Update host ring buffer after iterating over packets.
+ */
+static void hv_pkt_iter_close(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+ /*
+ * Make sure all reads are done before we update the read index since
+ * the writer may start writing to the read area once the read index
+ * is updated.
+ */
+ virt_rmb();
+ rbi->ring_buffer->read_index = rbi->priv_read_index;
+
+ hv_signal_on_read(channel);
+}
+
+/*
* Get next vmbus packet from ring buffer.
*
* Advances the current location (priv_read_index) and checks for more
- * data. If the end of the ring buffer is reached, then return NULL.
+ * data. If at end of list, return NULL and update host.
*/
struct vmpacket_descriptor *
-__hv_pkt_iter_next(struct vmbus_channel *channel,
+hv_pkt_iter_next(struct vmbus_channel *channel,
const struct vmpacket_descriptor *desc)
{
struct hv_ring_buffer_info *rbi = &channel->inbound;
@@ -476,29 +494,12 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
if (rbi->priv_read_index >= dsize)
rbi->priv_read_index -= dsize;
- /* more data? */
- if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ /* if no more data? */
+ if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) {
+ hv_pkt_iter_close(channel);
return NULL;
- else
- return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
-}
-EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
-
-/*
- * Update host ring buffer after iterating over packets.
- */
-void hv_pkt_iter_close(struct vmbus_channel *channel)
-{
- struct hv_ring_buffer_info *rbi = &channel->inbound;
-
- /*
- * Make sure all reads are done before we update the read index since
- * the writer may start writing to the read area once the read index
- * is updated.
- */
- virt_rmb();
- rbi->ring_buffer->read_index = rbi->priv_read_index;
+ }
- hv_signal_on_read(channel);
+ return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
}
-EXPORT_SYMBOL_GPL(hv_pkt_iter_close);
+EXPORT_SYMBOL_GPL(hv_pkt_iter_next);
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 36162485d663..7df6ab5b3067 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1550,32 +1550,12 @@ static inline u32 hv_pkt_datalen(const struct vmpacket_descriptor *desc)
return (desc->len8 << 3) - (desc->offset8 << 3);
}
-
struct vmpacket_descriptor *
hv_pkt_iter_first(struct vmbus_channel *channel);
struct vmpacket_descriptor *
-__hv_pkt_iter_next(struct vmbus_channel *channel,
- const struct vmpacket_descriptor *pkt);
-
-void hv_pkt_iter_close(struct vmbus_channel *channel);
-
-/*
- * Get next packet descriptor from iterator
- * If at end of list, return NULL and update host.
- */
-static inline struct vmpacket_descriptor *
hv_pkt_iter_next(struct vmbus_channel *channel,
- const struct vmpacket_descriptor *pkt)
-{
- struct vmpacket_descriptor *nxt;
-
- nxt = __hv_pkt_iter_next(channel, pkt);
- if (!nxt)
- hv_pkt_iter_close(channel);
-
- return nxt;
-}
+ const struct vmpacket_descriptor *pkt);
#define foreach_vmbus_pkt(pkt, channel) \
for (pkt = hv_pkt_iter_first(channel); pkt; \
--
2.11.0
^ permalink raw reply related [flat|nested] 6+ messages in thread