mirror of https://gitee.com/openkylin/linux.git
etf: Use cached rb_root
ETF's peek() operation is heavily used so use an rb_root_cached instead and leverage rb_first_cached() which will run in O(1) instead of O(log n). Even if on 'timesortedlist_clear()' we could be using rb_erase(), we choose to use rb_erase_cached(), because if in the future we allow runtime changes to ETF parameters, and need to do a '_clear()', this might cause some hard to debug issues. Signed-off-by: Jesus Sanchez-Palencia <jesus.s.palencia@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3fcbdaee3b
commit
09fd4860ea
|
@ -30,7 +30,7 @@ struct etf_sched_data {
|
||||||
int queue;
|
int queue;
|
||||||
s32 delta; /* in ns */
|
s32 delta; /* in ns */
|
||||||
ktime_t last; /* The txtime of the last skb sent to the netdevice. */
|
ktime_t last; /* The txtime of the last skb sent to the netdevice. */
|
||||||
struct rb_root head;
|
struct rb_root_cached head;
|
||||||
struct qdisc_watchdog watchdog;
|
struct qdisc_watchdog watchdog;
|
||||||
ktime_t (*get_time)(void);
|
ktime_t (*get_time)(void);
|
||||||
};
|
};
|
||||||
|
@ -104,7 +104,7 @@ static struct sk_buff *etf_peek_timesortedlist(struct Qdisc *sch)
|
||||||
struct etf_sched_data *q = qdisc_priv(sch);
|
struct etf_sched_data *q = qdisc_priv(sch);
|
||||||
struct rb_node *p;
|
struct rb_node *p;
|
||||||
|
|
||||||
p = rb_first(&q->head);
|
p = rb_first_cached(&q->head);
|
||||||
if (!p)
|
if (!p)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -156,8 +156,9 @@ static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
|
||||||
struct sk_buff **to_free)
|
struct sk_buff **to_free)
|
||||||
{
|
{
|
||||||
struct etf_sched_data *q = qdisc_priv(sch);
|
struct etf_sched_data *q = qdisc_priv(sch);
|
||||||
struct rb_node **p = &q->head.rb_node, *parent = NULL;
|
struct rb_node **p = &q->head.rb_root.rb_node, *parent = NULL;
|
||||||
ktime_t txtime = nskb->tstamp;
|
ktime_t txtime = nskb->tstamp;
|
||||||
|
bool leftmost = true;
|
||||||
|
|
||||||
if (!is_packet_valid(sch, nskb)) {
|
if (!is_packet_valid(sch, nskb)) {
|
||||||
report_sock_error(nskb, EINVAL,
|
report_sock_error(nskb, EINVAL,
|
||||||
|
@ -170,13 +171,15 @@ static int etf_enqueue_timesortedlist(struct sk_buff *nskb, struct Qdisc *sch,
|
||||||
|
|
||||||
parent = *p;
|
parent = *p;
|
||||||
skb = rb_to_skb(parent);
|
skb = rb_to_skb(parent);
|
||||||
if (ktime_after(txtime, skb->tstamp))
|
if (ktime_after(txtime, skb->tstamp)) {
|
||||||
p = &parent->rb_right;
|
p = &parent->rb_right;
|
||||||
else
|
leftmost = false;
|
||||||
|
} else {
|
||||||
p = &parent->rb_left;
|
p = &parent->rb_left;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
rb_link_node(&nskb->rbnode, parent, p);
|
rb_link_node(&nskb->rbnode, parent, p);
|
||||||
rb_insert_color(&nskb->rbnode, &q->head);
|
rb_insert_color_cached(&nskb->rbnode, &q->head, leftmost);
|
||||||
|
|
||||||
qdisc_qstats_backlog_inc(sch, nskb);
|
qdisc_qstats_backlog_inc(sch, nskb);
|
||||||
sch->q.qlen++;
|
sch->q.qlen++;
|
||||||
|
@ -192,7 +195,7 @@ static void timesortedlist_erase(struct Qdisc *sch, struct sk_buff *skb,
|
||||||
{
|
{
|
||||||
struct etf_sched_data *q = qdisc_priv(sch);
|
struct etf_sched_data *q = qdisc_priv(sch);
|
||||||
|
|
||||||
rb_erase(&skb->rbnode, &q->head);
|
rb_erase_cached(&skb->rbnode, &q->head);
|
||||||
|
|
||||||
/* The rbnode field in the skb re-uses these fields, now that
|
/* The rbnode field in the skb re-uses these fields, now that
|
||||||
* we are done with the rbnode, reset them.
|
* we are done with the rbnode, reset them.
|
||||||
|
@ -388,14 +391,14 @@ static int etf_init(struct Qdisc *sch, struct nlattr *opt,
|
||||||
static void timesortedlist_clear(struct Qdisc *sch)
|
static void timesortedlist_clear(struct Qdisc *sch)
|
||||||
{
|
{
|
||||||
struct etf_sched_data *q = qdisc_priv(sch);
|
struct etf_sched_data *q = qdisc_priv(sch);
|
||||||
struct rb_node *p = rb_first(&q->head);
|
struct rb_node *p = rb_first_cached(&q->head);
|
||||||
|
|
||||||
while (p) {
|
while (p) {
|
||||||
struct sk_buff *skb = rb_to_skb(p);
|
struct sk_buff *skb = rb_to_skb(p);
|
||||||
|
|
||||||
p = rb_next(p);
|
p = rb_next(p);
|
||||||
|
|
||||||
rb_erase(&skb->rbnode, &q->head);
|
rb_erase_cached(&skb->rbnode, &q->head);
|
||||||
rtnl_kfree_skbs(skb, skb);
|
rtnl_kfree_skbs(skb, skb);
|
||||||
sch->q.qlen--;
|
sch->q.qlen--;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue