Skip to content

Commit bdad7f9

Browse files
committed
Merge branch 'net_sched-reduce-the-number-of-qdisc-resets'
Cong Wang says: ==================== net_sched: reduce the number of qdisc resets This patchset aims to reduce the number of qdisc resets during qdisc tear down. Patch 1~3 are preparation for their following patches, especially patch 2 and patch 3 add a few tracepoints so that we can observe the whole lifetime of qdisc's. Patch 4 and patch 5 are the ones do the actual work. Please find more details in each patch description. Vaclav Zindulka tested this patchset and his large ruleset with over 13k qdiscs defined got from 22s to 520ms. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents b3037ac + 759ae57 commit bdad7f9

File tree

3 files changed

+110
-43
lines changed

3 files changed

+110
-43
lines changed

include/trace/events/qdisc.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <linux/netdevice.h>
99
#include <linux/tracepoint.h>
1010
#include <linux/ftrace.h>
11+
#include <linux/pkt_sched.h>
12+
#include <net/sch_generic.h>
1113

1214
TRACE_EVENT(qdisc_dequeue,
1315

@@ -44,6 +46,79 @@ TRACE_EVENT(qdisc_dequeue,
4446
__entry->txq_state, __entry->packets, __entry->skbaddr )
4547
);
4648

49+
TRACE_EVENT(qdisc_reset,
50+
51+
TP_PROTO(struct Qdisc *q),
52+
53+
TP_ARGS(q),
54+
55+
TP_STRUCT__entry(
56+
__string( dev, qdisc_dev(q) )
57+
__string( kind, q->ops->id )
58+
__field( u32, parent )
59+
__field( u32, handle )
60+
),
61+
62+
TP_fast_assign(
63+
__assign_str(dev, qdisc_dev(q));
64+
__assign_str(kind, q->ops->id);
65+
__entry->parent = q->parent;
66+
__entry->handle = q->handle;
67+
),
68+
69+
TP_printk("dev=%s kind=%s parent=%x:%x handle=%x:%x", __get_str(dev),
70+
__get_str(kind), TC_H_MAJ(__entry->parent) >> 16, TC_H_MIN(__entry->parent),
71+
TC_H_MAJ(__entry->handle) >> 16, TC_H_MIN(__entry->handle))
72+
);
73+
74+
TRACE_EVENT(qdisc_destroy,
75+
76+
TP_PROTO(struct Qdisc *q),
77+
78+
TP_ARGS(q),
79+
80+
TP_STRUCT__entry(
81+
__string( dev, qdisc_dev(q) )
82+
__string( kind, q->ops->id )
83+
__field( u32, parent )
84+
__field( u32, handle )
85+
),
86+
87+
TP_fast_assign(
88+
__assign_str(dev, qdisc_dev(q));
89+
__assign_str(kind, q->ops->id);
90+
__entry->parent = q->parent;
91+
__entry->handle = q->handle;
92+
),
93+
94+
TP_printk("dev=%s kind=%s parent=%x:%x handle=%x:%x", __get_str(dev),
95+
__get_str(kind), TC_H_MAJ(__entry->parent) >> 16, TC_H_MIN(__entry->parent),
96+
TC_H_MAJ(__entry->handle) >> 16, TC_H_MIN(__entry->handle))
97+
);
98+
99+
TRACE_EVENT(qdisc_create,
100+
101+
TP_PROTO(const struct Qdisc_ops *ops, struct net_device *dev, u32 parent),
102+
103+
TP_ARGS(ops, dev, parent),
104+
105+
TP_STRUCT__entry(
106+
__string( dev, dev->name )
107+
__string( kind, ops->id )
108+
__field( u32, parent )
109+
),
110+
111+
TP_fast_assign(
112+
__assign_str(dev, dev->name);
113+
__assign_str(kind, ops->id);
114+
__entry->parent = parent;
115+
),
116+
117+
TP_printk("dev=%s kind=%s parent=%x:%x",
118+
__get_str(dev), __get_str(kind),
119+
TC_H_MAJ(__entry->parent) >> 16, TC_H_MIN(__entry->parent))
120+
);
121+
47122
#endif /* _TRACE_QDISC_H */
48123

49124
/* This part must be outside protection */

net/sched/sch_api.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <net/pkt_sched.h>
3333
#include <net/pkt_cls.h>
3434

35+
#include <trace/events/qdisc.h>
36+
3537
/*
3638
3739
Short review.
@@ -1283,6 +1285,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
12831285
}
12841286

12851287
qdisc_hash_add(sch, false);
1288+
trace_qdisc_create(ops, dev, parent);
12861289

12871290
return sch;
12881291

net/sched/sch_generic.c

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -896,8 +896,10 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
896896
}
897897
sch->parent = parentid;
898898

899-
if (!ops->init || ops->init(sch, NULL, extack) == 0)
899+
if (!ops->init || ops->init(sch, NULL, extack) == 0) {
900+
trace_qdisc_create(ops, dev_queue->dev, parentid);
900901
return sch;
902+
}
901903

902904
qdisc_put(sch);
903905
return NULL;
@@ -911,6 +913,8 @@ void qdisc_reset(struct Qdisc *qdisc)
911913
const struct Qdisc_ops *ops = qdisc->ops;
912914
struct sk_buff *skb, *tmp;
913915

916+
trace_qdisc_reset(qdisc);
917+
914918
if (ops->reset)
915919
ops->reset(qdisc);
916920

@@ -949,31 +953,23 @@ static void qdisc_free_cb(struct rcu_head *head)
949953
static void qdisc_destroy(struct Qdisc *qdisc)
950954
{
951955
const struct Qdisc_ops *ops = qdisc->ops;
952-
struct sk_buff *skb, *tmp;
953956

954957
#ifdef CONFIG_NET_SCHED
955958
qdisc_hash_del(qdisc);
956959

957960
qdisc_put_stab(rtnl_dereference(qdisc->stab));
958961
#endif
959962
gen_kill_estimator(&qdisc->rate_est);
960-
if (ops->reset)
961-
ops->reset(qdisc);
963+
964+
qdisc_reset(qdisc);
965+
962966
if (ops->destroy)
963967
ops->destroy(qdisc);
964968

965969
module_put(ops->owner);
966970
dev_put(qdisc_dev(qdisc));
967971

968-
skb_queue_walk_safe(&qdisc->gso_skb, skb, tmp) {
969-
__skb_unlink(skb, &qdisc->gso_skb);
970-
kfree_skb_list(skb);
971-
}
972-
973-
skb_queue_walk_safe(&qdisc->skb_bad_txq, skb, tmp) {
974-
__skb_unlink(skb, &qdisc->skb_bad_txq);
975-
kfree_skb_list(skb);
976-
}
972+
trace_qdisc_destroy(qdisc);
977973

978974
call_rcu(&qdisc->rcu, qdisc_free_cb);
979975
}
@@ -1132,6 +1128,28 @@ void dev_activate(struct net_device *dev)
11321128
}
11331129
EXPORT_SYMBOL(dev_activate);
11341130

1131+
static void qdisc_deactivate(struct Qdisc *qdisc)
1132+
{
1133+
bool nolock = qdisc->flags & TCQ_F_NOLOCK;
1134+
1135+
if (qdisc->flags & TCQ_F_BUILTIN)
1136+
return;
1137+
if (test_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state))
1138+
return;
1139+
1140+
if (nolock)
1141+
spin_lock_bh(&qdisc->seqlock);
1142+
spin_lock_bh(qdisc_lock(qdisc));
1143+
1144+
set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
1145+
1146+
qdisc_reset(qdisc);
1147+
1148+
spin_unlock_bh(qdisc_lock(qdisc));
1149+
if (nolock)
1150+
spin_unlock_bh(&qdisc->seqlock);
1151+
}
1152+
11351153
static void dev_deactivate_queue(struct net_device *dev,
11361154
struct netdev_queue *dev_queue,
11371155
void *_qdisc_default)
@@ -1141,21 +1159,8 @@ static void dev_deactivate_queue(struct net_device *dev,
11411159

11421160
qdisc = rtnl_dereference(dev_queue->qdisc);
11431161
if (qdisc) {
1144-
bool nolock = qdisc->flags & TCQ_F_NOLOCK;
1145-
1146-
if (nolock)
1147-
spin_lock_bh(&qdisc->seqlock);
1148-
spin_lock_bh(qdisc_lock(qdisc));
1149-
1150-
if (!(qdisc->flags & TCQ_F_BUILTIN))
1151-
set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state);
1152-
1162+
qdisc_deactivate(qdisc);
11531163
rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
1154-
qdisc_reset(qdisc);
1155-
1156-
spin_unlock_bh(qdisc_lock(qdisc));
1157-
if (nolock)
1158-
spin_unlock_bh(&qdisc->seqlock);
11591164
}
11601165
}
11611166

@@ -1186,16 +1191,6 @@ static bool some_qdisc_is_busy(struct net_device *dev)
11861191
return false;
11871192
}
11881193

1189-
static void dev_qdisc_reset(struct net_device *dev,
1190-
struct netdev_queue *dev_queue,
1191-
void *none)
1192-
{
1193-
struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
1194-
1195-
if (qdisc)
1196-
qdisc_reset(qdisc);
1197-
}
1198-
11991194
/**
12001195
* dev_deactivate_many - deactivate transmissions on several devices
12011196
* @head: list of devices to deactivate
@@ -1232,12 +1227,6 @@ void dev_deactivate_many(struct list_head *head)
12321227
*/
12331228
schedule_timeout_uninterruptible(1);
12341229
}
1235-
/* The new qdisc is assigned at this point so we can safely
1236-
* unwind stale skb lists and qdisc statistics
1237-
*/
1238-
netdev_for_each_tx_queue(dev, dev_qdisc_reset, NULL);
1239-
if (dev_ingress_queue(dev))
1240-
dev_qdisc_reset(dev, dev_ingress_queue(dev), NULL);
12411230
}
12421231
}
12431232

0 commit comments

Comments
 (0)