diff options
author | Eric Dumazet <edumazet@google.com> | 2012-12-11 10:54:33 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-12 00:16:47 -0500 |
commit | 1abbe1394a84c10919e32242318e715b04d7e33b (patch) | |
tree | ec3930413339cd3c77498c133b41475737494279 /net/sched | |
parent | cae49ede00ec3d0cda290b03fee55b72b49efc11 (diff) |
pkt_sched: avoid requeues if possible
With BQL being deployed, we can more likely have following behavior :
We dequeue a packet from qdisc in dequeue_skb(), then we realize target
tx queue is in XOFF state in sch_direct_xmit(), and we have to hold the
skb into gso_skb for later.
This shows in stats (tc -s qdisc dev eth0) as requeues.
Problem of these requeues is that high priority packets can not be
dequeued as long as this (possibly low prio and big TSO packet) is not
removed from gso_skb.
At 1Gbps speed, a full size TSO packet is 500 us of extra latency.
In some cases, we know that all packets dequeued from a qdisc are
for a particular and known txq :
- If device is non multi queue
- For all MQ/MQPRIO slave qdiscs
This patch introduces a new qdisc flag, TCQ_F_ONETXQUEUE to mark
this capability, so that dequeue_skb() is allowed to dequeue a packet
only if the associated txq is not stopped.
This indeed reduce latencies for high prio packets (or improve fairness
with sfq/fq_codel), and almost remove qdisc 'requeues'.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/sch_api.c | 2 | ||||
-rw-r--r-- | net/sched/sch_generic.c | 11 | ||||
-rw-r--r-- | net/sched/sch_mq.c | 4 | ||||
-rw-r--r-- | net/sched/sch_mqprio.c | 4 |
4 files changed, 15 insertions, 6 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4799c4840c1a..d84f7e734cd7 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -833,6 +833,8 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, | |||
833 | goto err_out3; | 833 | goto err_out3; |
834 | } | 834 | } |
835 | lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); | 835 | lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); |
836 | if (!netif_is_multiqueue(dev)) | ||
837 | sch->flags |= TCQ_F_ONETXQUEUE; | ||
836 | } | 838 | } |
837 | 839 | ||
838 | sch->handle = handle; | 840 | sch->handle = handle; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index aefc1504dc88..5d81a4478514 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -53,20 +53,19 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) | |||
53 | static inline struct sk_buff *dequeue_skb(struct Qdisc *q) | 53 | static inline struct sk_buff *dequeue_skb(struct Qdisc *q) |
54 | { | 54 | { |
55 | struct sk_buff *skb = q->gso_skb; | 55 | struct sk_buff *skb = q->gso_skb; |
56 | const struct netdev_queue *txq = q->dev_queue; | ||
56 | 57 | ||
57 | if (unlikely(skb)) { | 58 | if (unlikely(skb)) { |
58 | struct net_device *dev = qdisc_dev(q); | ||
59 | struct netdev_queue *txq; | ||
60 | |||
61 | /* check the reason of requeuing without tx lock first */ | 59 | /* check the reason of requeuing without tx lock first */ |
62 | txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); | 60 | txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb)); |
63 | if (!netif_xmit_frozen_or_stopped(txq)) { | 61 | if (!netif_xmit_frozen_or_stopped(txq)) { |
64 | q->gso_skb = NULL; | 62 | q->gso_skb = NULL; |
65 | q->q.qlen--; | 63 | q->q.qlen--; |
66 | } else | 64 | } else |
67 | skb = NULL; | 65 | skb = NULL; |
68 | } else { | 66 | } else { |
69 | skb = q->dequeue(q); | 67 | if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq)) |
68 | skb = q->dequeue(q); | ||
70 | } | 69 | } |
71 | 70 | ||
72 | return skb; | 71 | return skb; |
@@ -686,6 +685,8 @@ static void attach_one_default_qdisc(struct net_device *dev, | |||
686 | netdev_info(dev, "activation failed\n"); | 685 | netdev_info(dev, "activation failed\n"); |
687 | return; | 686 | return; |
688 | } | 687 | } |
688 | if (!netif_is_multiqueue(dev)) | ||
689 | qdisc->flags |= TCQ_F_ONETXQUEUE; | ||
689 | } | 690 | } |
690 | dev_queue->qdisc_sleeping = qdisc; | 691 | dev_queue->qdisc_sleeping = qdisc; |
691 | } | 692 | } |
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 0a4b2f9a0094..5da78a19ac9a 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c | |||
@@ -63,6 +63,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt) | |||
63 | if (qdisc == NULL) | 63 | if (qdisc == NULL) |
64 | goto err; | 64 | goto err; |
65 | priv->qdiscs[ntx] = qdisc; | 65 | priv->qdiscs[ntx] = qdisc; |
66 | qdisc->flags |= TCQ_F_ONETXQUEUE; | ||
66 | } | 67 | } |
67 | 68 | ||
68 | sch->flags |= TCQ_F_MQROOT; | 69 | sch->flags |= TCQ_F_MQROOT; |
@@ -150,7 +151,8 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, | |||
150 | dev_deactivate(dev); | 151 | dev_deactivate(dev); |
151 | 152 | ||
152 | *old = dev_graft_qdisc(dev_queue, new); | 153 | *old = dev_graft_qdisc(dev_queue, new); |
153 | 154 | if (new) | |
155 | new->flags |= TCQ_F_ONETXQUEUE; | ||
154 | if (dev->flags & IFF_UP) | 156 | if (dev->flags & IFF_UP) |
155 | dev_activate(dev); | 157 | dev_activate(dev); |
156 | return 0; | 158 | return 0; |
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index d1831ca966d4..accec33c454c 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c | |||
@@ -132,6 +132,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) | |||
132 | goto err; | 132 | goto err; |
133 | } | 133 | } |
134 | priv->qdiscs[i] = qdisc; | 134 | priv->qdiscs[i] = qdisc; |
135 | qdisc->flags |= TCQ_F_ONETXQUEUE; | ||
135 | } | 136 | } |
136 | 137 | ||
137 | /* If the mqprio options indicate that hardware should own | 138 | /* If the mqprio options indicate that hardware should own |
@@ -205,6 +206,9 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, | |||
205 | 206 | ||
206 | *old = dev_graft_qdisc(dev_queue, new); | 207 | *old = dev_graft_qdisc(dev_queue, new); |
207 | 208 | ||
209 | if (new) | ||
210 | new->flags |= TCQ_F_ONETXQUEUE; | ||
211 | |||
208 | if (dev->flags & IFF_UP) | 212 | if (dev->flags & IFF_UP) |
209 | dev_activate(dev); | 213 | dev_activate(dev); |
210 | 214 | ||