Skip to contentSkip to conversation

net: batch skb dequeueing from softnet input_pkt_queue

PATCH Superseded Changli Gao 5 participants 13 messages Apr 14, 2010 – Apr 22, 2010

Subsystems (2)

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 net: batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

----

 include/linux/netdevice.h |    1 
 net/core/dev.c            |   56 ++++++++++++++++++++++++++++++++--------------
 2 files changed, 40 insertions(+), 17 deletions(-)
include/linux/netdevice.h +1 -0
index d1a21b5..898bc62 100644
@@ -1335,6 +1335,7 @@ struct softnet_data {
 	struct call_single_data	csd ____cacheline_aligned_in_smp;
 #endif
 	struct sk_buff_head	input_pkt_queue;
+	struct sk_buff_head	processing_queue;
 	struct napi_struct	backlog;
 };
 
net/core/dev.c +39 -17

117 lines not on this page · raw message

#1 lore raw
Quoted 6 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

It seems we are now going to generate a lot more IPIs with such a change. At least this is what i am imagining.
CPU0: packet comes in,queue empty, generate an IPI to CPU1
CPU0: second packet comes in, enqueue
CPU1: grab two packets to process and run with them
CPU0: packet comes in,queue empty, generate an IPI to CPU1 ..
...
.....

IPIs add to latency (refer to my other email). Did you test this to reach some conclusion that it improves thing or was it just by inspection?

cheers,
jamal

#2 lore raw
Quoted 7 lines · jamal

It seems we are now going to generate a lot more IPIs with such a change. At least this is what i am imagining.
CPU0: packet comes in,queue empty, generate an IPI to CPU1
CPU0: second packet comes in, enqueue
CPU1: grab two packets to process and run with them
CPU0: packet comes in,queue empty, generate an IPI to CPU1

No extra IPI is needed.

+ qlen = queue->input_pkt_queue.qlen + queue->processing_queue.qlen;
+ if (qlen <= netdev_max_backlog) {
+ if (qlen) {

the packets in processing_queue are counted too.

Quoted 5 lines

IPIs add to latency (refer to my other email). Did you test this to reach some conclusion that it improves thing or was it just by inspection?

:( only insepection.

Signature · 2 lines
Regards,
Changli Gao([email protected])
#3 lore raw
Quoted 9 lines · Changli Gao

On Wed, Apr 14, 2010 at 7:58 PM, jamal <[email protected]> wrote:

No extra IPI is needed.

net/core/dev.c +3 -0
+       qlen = queue->input_pkt_queue.qlen + queue->processing_queue.qlen;
+       if (qlen <= netdev_max_backlog) {
+               if (qlen) {

the packets in processing_queue are counted too.

Ok - Looks reasonable.

Quoted 6 lines
Quoted 4 lines

IPIs add to latency (refer to my other email). Did you test this to reach some conclusion that it improves thing or was it just by inspection?

:( only insepection.

I am probably being pushy, but one simple test for latency of single flow is:

from machine 1, send ping -f

on rps machine:
Base test: no rps on ( a fresh boot with no sysctls should do fine) Test 1: irq affinity on cpuX, rps to cpuY
Test 2: repeat test1 with your change.

It should show no difference between test1 and 2. If it shows improvement better - but showing worse latency is bad.

cheers,
jamal

#4 lore raw
In reply to Changli Gao
Quoted 6 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

Adding stop_machine() with no explanation ?

No ack from my previous comments, suggestions, and still same logic ?

Are we supposed to read patch, test it, make some benches, correct bugs, say Amen ?

This is becoming silly, if you ask me.

This is a NACK of this patch, obviously.

#5 lore raw
Quoted 9 lines · Eric Dumazet
Quoted 6 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

Adding stop_machine() with no explanation ?

stop_machine() is added to flush the processing_queue. Because the old flush_backlog() runs in IRQ context, it can't touch the things, which are only valid in softirq context.

Quoted 2 lines

No ack from my previous comments, suggestions, and still same logic ?

In this patch, the volatile variable flush_processing_queue is removed, and the corresponding lines are removed too.

Oh, I should splice the old message back, as stop_machine is used instead. So, the processing queue will be removed from softnet_data, and a single int counter will be used instead to count the packets which are being processing.

one issue you concern is potential cache miss when summing in enqueue function. It won't happen all the time, in fact, I think it should happen seldom, and it is the responsibility of hardware to cache the data frequently used.

Quoted 4 lines

Are we supposed to read patch, test it, make some benches, correct bugs, say Amen ?

OK, I'll test it.

Signature · 2 lines
Regards,
Changli Gao([email protected])
#6 lore raw
In reply to Changli Gao
Quoted 7 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

----

lock contention _is_ a problem, Jamal tests can show it.

irq disabling/enabling is not, and force to use stop_machine() killer.

I suggest something very simple, like a small buffer (16 slots), so that process_backlog() can batch 16 buffers at once.

Following patch not tested, but its late here and I need to sleep ;)

This is a RFC, not for inclusion, and based on current net-next-2.6 tree

[RFC] net: introduce a batch mode in process_backlog()

We see a lock contention on input_pkt_queue.lock in RPS benches.

As suggested by Changli Gao, we can batch several skbs at once in process_backlog(), so that we dirty input_pkt_queue less often.

I chose to batch at most 16 skbs per round, and place them in softnet_data zone where flush_backlog() can find them and eventually free this skbs at device dismantle.

---
 include/linux/netdevice.h |    2 +
 net/core/dev.c            |   48 +++++++++++++++++++++++++++---------
 2 files changed, 38 insertions(+), 12 deletions(-)
include/linux/netdevice.h +2 -0
index 3c5ed5f..16da8db 100644
@@ -1383,11 +1383,13 @@ static inline int unregister_gifconf(unsigned int family)
 /*
  * Incoming packets are placed on per-cpu queues
  */
+#define SD_BATCH_SZ 16
 struct softnet_data {
 	struct Qdisc		*output_queue;
 	struct list_head	poll_list;
 	struct sk_buff		*completion_queue;
 
+	struct sk_buff		*batch[SD_BATCH_SZ]; /* process_backlog() & flush_backlog() */
 #ifdef CONFIG_RPS
 	struct softnet_data	*rps_ipi_list;
 
net/core/dev.c +38 -12

79 lines not on this page · raw message

#7 lore raw
Quoted 7 lines

       do {
-               struct sk_buff *skb;
+               lim = quota - work;
+               if (lim > ARRAY_SIZE(sd->batch))
+                       lim = ARRAY_SIZE(sd->batch);
+               /* batch at most 16 buffers */

How about just using two input_pkt_queue's (define input_pkt_queue[2])? One that is used to enqueue from RPS, and one that is being processed by process_backlog. Then the only thing that needs to be done under lock in process_backlog is to switch the queues; something like sd->current_input_pkt_queue ^= 1

Tom

Quoted 44 lines

-               local_irq_disable();
               rps_lock(sd);
-               skb = __skb_dequeue(&sd->input_pkt_queue);
-               if (!skb) {
+               for (n = 0; n < lim; n++) {
+                       sd->batch[n] = __skb_dequeue(&sd->input_pkt_queue);
+                       if (!sd->batch[n])
+                               break;
+               }
+               if (!sd->input_pkt_queue.qlen) { __napi_complete(napi);
-                       rps_unlock(sd);
-                       local_irq_enable();
-                       break;
+                       quota = 0;
               }
-               input_queue_head_incr(sd);
               rps_unlock(sd);
-               local_irq_enable();

-               __netif_receive_skb(skb);
-       } while (++work < quota);
+               /* Now process our batch */
+               for (i = 0; i < n; i++) {
+                       skb = sd->batch[i];
+                       /* flush_backlog() might have stolen this skb */
+                       input_queue_head_incr(sd);
+                       if (likely(skb)) {
+                               sd->batch[i] = NULL;
+                               local_irq_enable();
+                               __netif_receive_skb(skb);
+                               local_irq_disable();
+                       }
+               }
+               work += n;
+       } while (work < quota);

+       local_irq_enable();
       return work;
 }

#8 lore raw
Quoted 7 lines · Tom Herbert

How about just using two input_pkt_queue's (define input_pkt_queue[2])?  One that is used to enqueue from RPS, and one that is being processed by process_backlog.  Then the only thing that needs to be done under lock in process_backlog is to switch the queues;  something like sd->current_input_pkt_queue ^= 1

It is a better idea, IMO.

Signature · 2 lines
Regards,
Changli Gao([email protected])
#9 lore raw
In reply to Eric Dumazet
Quoted 6 lines · Eric Dumazet
Quoted 5 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

Quoted 7 lines
Quoted 2 lines

----

lock contention _is_ a problem, Jamal tests can show it.

irq disabling/enabling is not, and force to use stop_machine() killer.

Although irq_disabling/enabling is not, we should do our best to make fast path as quickly as possible, and because stop_machine() is used in slow patch, I think we can afford its weight.

Signature · 2 lines
Regards,
Changli Gao([email protected])
#10 lore raw
Quoted 10 lines · Changli Gao
Quoted 9 lines · Eric Dumazet
Quoted 7 lines · Changli Gao

batch skb dequeueing from softnet input_pkt_queue

batch skb dequeueing from softnet input_pkt_queue to reduce potential lock contention and irq disabling/enabling.

----

Quoted 10 lines
Quoted 4 lines

lock contention _is_ a problem, Jamal tests can show it.

irq disabling/enabling is not, and force to use stop_machine() killer.

Although irq_disabling/enabling is not, we should do our best to make fast path as quickly as possible, and because stop_machine() is used in slow patch, I think we can afford its weight.

No thanks, this is out of the question.

Talk to ixiacom guys, some people settle/dismantle dozens of network device per second, on production machines.

maintainer
#11 lore raw

From: Eric Dumazet <[email protected]>
Date: Thu, 22 Apr 2010 09:13:22 +0200

Quoted 4 lines

No thanks, this is out of the question.

Talk to ixiacom guys, some people settle/dismantle dozens of network device per second, on production machines.

Yes, ifup/ifdown performance is very important these days.

Recently we've had to do a lot of work to increase scalability and latency in this area, let's not undo that.

#12 lore raw
In reply to Eric Dumazet
Quoted 7 lines · Eric Dumazet

[RFC] net: introduce a batch mode in process_backlog()

We see a lock contention on input_pkt_queue.lock in RPS benches.

As suggested by Changli Gao, we can batch several skbs at once in process_backlog(), so that we dirty input_pkt_queue less often.

Ok, so i grab the latest and greatest net-next and apply this before testing? Let me know..

cheers,
jamal