Commit 1c1393ea authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[NET_SCHED]: Replace actlist by rbtrees in HFSC scheduler.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent a01977ff
...@@ -135,8 +135,10 @@ struct hfsc_class ...@@ -135,8 +135,10 @@ struct hfsc_class
struct Qdisc *qdisc; /* leaf qdisc */ struct Qdisc *qdisc; /* leaf qdisc */
struct rb_node el_node; /* qdisc's eligible tree member */ struct rb_node el_node; /* qdisc's eligible tree member */
struct list_head actlist; /* active children list */ struct rb_root vt_tree; /* active children sorted by cl_vt */
struct list_head alist; /* active children list member */ struct rb_node vt_node; /* parent's vt_tree member */
struct rb_root cf_tree; /* active children sorted by cl_f */
struct rb_node cf_node; /* parent's cf_heap member */
struct list_head hlist; /* hash list member */ struct list_head hlist; /* hash list member */
struct list_head dlist; /* drop list member */ struct list_head dlist; /* drop list member */
...@@ -286,84 +288,51 @@ eltree_get_minel(struct hfsc_sched *q) ...@@ -286,84 +288,51 @@ eltree_get_minel(struct hfsc_sched *q)
} }
/* /*
* active children list holds backlogged child classes being sorted * vttree holds holds backlogged child classes being sorted by their virtual
* by their virtual time. each intermediate class has one active * time. each intermediate class has one vttree.
* children list.
*/ */
static void static void
actlist_insert(struct hfsc_class *cl) vttree_insert(struct hfsc_class *cl)
{ {
struct list_head *head = &cl->cl_parent->actlist; struct rb_node **p = &cl->cl_parent->vt_tree.rb_node;
struct hfsc_class *p; struct rb_node *parent = NULL;
struct hfsc_class *cl1;
/* check the last entry first */
if (list_empty(head) ||
((p = list_entry(head->prev, struct hfsc_class, alist)) &&
p->cl_vt <= cl->cl_vt)) {
list_add_tail(&cl->alist, head);
return;
}
list_for_each_entry(p, head, alist) { while (*p != NULL) {
if (cl->cl_vt < p->cl_vt) { parent = *p;
/* insert cl before p */ cl1 = rb_entry(parent, struct hfsc_class, vt_node);
list_add_tail(&cl->alist, &p->alist); if (cl->cl_vt >= cl1->cl_vt)
return; p = &parent->rb_right;
} else
p = &parent->rb_left;
} }
ASSERT(0); /* should not reach here */ rb_link_node(&cl->vt_node, parent, p);
rb_insert_color(&cl->vt_node, &cl->cl_parent->vt_tree);
} }
static inline void static inline void
actlist_remove(struct hfsc_class *cl) vttree_remove(struct hfsc_class *cl)
{ {
list_del(&cl->alist); rb_erase(&cl->vt_node, &cl->cl_parent->vt_tree);
} }
static void static inline void
actlist_update(struct hfsc_class *cl) vttree_update(struct hfsc_class *cl)
{ {
struct list_head *head = &cl->cl_parent->actlist; vttree_remove(cl);
struct hfsc_class *p, *last; vttree_insert(cl);
/*
* the virtual time of a class increases monotonically.
* if the next entry has a larger virtual time, nothing to do.
*/
if (cl->alist.next == head ||
((p = list_entry(cl->alist.next, struct hfsc_class, alist)) &&
cl->cl_vt <= p->cl_vt))
return;
/* check the last entry */
last = list_entry(head->prev, struct hfsc_class, alist);
if (last->cl_vt <= cl->cl_vt) {
list_move_tail(&cl->alist, head);
return;
}
/*
* the new position must be between the next entry
* and the last entry
*/
list_for_each_entry_continue(p, head, alist) {
if (cl->cl_vt < p->cl_vt) {
list_move_tail(&cl->alist, &p->alist);
return;
}
}
ASSERT(0); /* should not reach here */
} }
static inline struct hfsc_class * static inline struct hfsc_class *
actlist_firstfit(struct hfsc_class *cl, u64 cur_time) vttree_firstfit(struct hfsc_class *cl, u64 cur_time)
{ {
struct hfsc_class *p; struct hfsc_class *p;
struct rb_node *n;
list_for_each_entry(p, &cl->actlist, alist) { for (n = rb_first(&cl->vt_tree); n != NULL; n = rb_next(n)) {
if (p->cl_f <= cur_time) { p = rb_entry(n, struct hfsc_class, vt_node);
if (p->cl_f <= cur_time)
return p; return p;
}
} }
return NULL; return NULL;
} }
...@@ -372,14 +341,14 @@ actlist_firstfit(struct hfsc_class *cl, u64 cur_time) ...@@ -372,14 +341,14 @@ actlist_firstfit(struct hfsc_class *cl, u64 cur_time)
* get the leaf class with the minimum vt in the hierarchy * get the leaf class with the minimum vt in the hierarchy
*/ */
static struct hfsc_class * static struct hfsc_class *
actlist_get_minvt(struct hfsc_class *cl, u64 cur_time) vttree_get_minvt(struct hfsc_class *cl, u64 cur_time)
{ {
/* if root-class's cfmin is bigger than cur_time nothing to do */ /* if root-class's cfmin is bigger than cur_time nothing to do */
if (cl->cl_cfmin > cur_time) if (cl->cl_cfmin > cur_time)
return NULL; return NULL;
while (cl->level > 0) { while (cl->level > 0) {
cl = actlist_firstfit(cl, cur_time); cl = vttree_firstfit(cl, cur_time);
if (cl == NULL) if (cl == NULL)
return NULL; return NULL;
/* /*
...@@ -391,6 +360,38 @@ actlist_get_minvt(struct hfsc_class *cl, u64 cur_time) ...@@ -391,6 +360,38 @@ actlist_get_minvt(struct hfsc_class *cl, u64 cur_time)
return cl; return cl;
} }
static void
cftree_insert(struct hfsc_class *cl)
{
struct rb_node **p = &cl->cl_parent->cf_tree.rb_node;
struct rb_node *parent = NULL;
struct hfsc_class *cl1;
while (*p != NULL) {
parent = *p;
cl1 = rb_entry(parent, struct hfsc_class, cf_node);
if (cl->cl_f >= cl1->cl_f)
p = &parent->rb_right;
else
p = &parent->rb_left;
}
rb_link_node(&cl->cf_node, parent, p);
rb_insert_color(&cl->cf_node, &cl->cl_parent->cf_tree);
}
static inline void
cftree_remove(struct hfsc_class *cl)
{
rb_erase(&cl->cf_node, &cl->cl_parent->cf_tree);
}
static inline void
cftree_update(struct hfsc_class *cl)
{
cftree_remove(cl);
cftree_insert(cl);
}
/* /*
* service curve support functions * service curve support functions
* *
...@@ -702,32 +703,25 @@ update_d(struct hfsc_class *cl, unsigned int next_len) ...@@ -702,32 +703,25 @@ update_d(struct hfsc_class *cl, unsigned int next_len)
cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
} }
static void static inline void
update_cfmin(struct hfsc_class *cl) update_cfmin(struct hfsc_class *cl)
{ {
struct rb_node *n = rb_first(&cl->cf_tree);
struct hfsc_class *p; struct hfsc_class *p;
u64 cfmin;
if (list_empty(&cl->actlist)) { if (n == NULL) {
cl->cl_cfmin = 0; cl->cl_cfmin = 0;
return; return;
} }
cfmin = HT_INFINITY; p = rb_entry(n, struct hfsc_class, cf_node);
list_for_each_entry(p, &cl->actlist, alist) { cl->cl_cfmin = p->cl_f;
if (p->cl_f == 0) {
cl->cl_cfmin = 0;
return;
}
if (p->cl_f < cfmin)
cfmin = p->cl_f;
}
cl->cl_cfmin = cfmin;
} }
static void static void
init_vf(struct hfsc_class *cl, unsigned int len) init_vf(struct hfsc_class *cl, unsigned int len)
{ {
struct hfsc_class *max_cl, *p; struct hfsc_class *max_cl, *p;
struct rb_node *n;
u64 vt, f, cur_time; u64 vt, f, cur_time;
int go_active; int go_active;
...@@ -740,9 +734,9 @@ init_vf(struct hfsc_class *cl, unsigned int len) ...@@ -740,9 +734,9 @@ init_vf(struct hfsc_class *cl, unsigned int len)
go_active = 0; go_active = 0;
if (go_active) { if (go_active) {
if (!list_empty(&cl->cl_parent->actlist)) { n = rb_last(&cl->cl_parent->vt_tree);
max_cl = list_entry(cl->cl_parent->actlist.prev, if (n != NULL) {
struct hfsc_class, alist); max_cl = rb_entry(n, struct hfsc_class,vt_node);
/* /*
* set vt to the average of the min and max * set vt to the average of the min and max
* classes. if the parent's period didn't * classes. if the parent's period didn't
...@@ -787,7 +781,8 @@ init_vf(struct hfsc_class *cl, unsigned int len) ...@@ -787,7 +781,8 @@ init_vf(struct hfsc_class *cl, unsigned int len)
cl->cl_parentperiod++; cl->cl_parentperiod++;
cl->cl_f = 0; cl->cl_f = 0;
actlist_insert(cl); vttree_insert(cl);
cftree_insert(cl);
if (cl->cl_flags & HFSC_USC) { if (cl->cl_flags & HFSC_USC) {
/* class has upper limit curve */ /* class has upper limit curve */
...@@ -807,6 +802,7 @@ init_vf(struct hfsc_class *cl, unsigned int len) ...@@ -807,6 +802,7 @@ init_vf(struct hfsc_class *cl, unsigned int len)
f = max(cl->cl_myf, cl->cl_cfmin); f = max(cl->cl_myf, cl->cl_cfmin);
if (f != cl->cl_f) { if (f != cl->cl_f) {
cl->cl_f = f; cl->cl_f = f;
cftree_update(cl);
update_cfmin(cl->cl_parent); update_cfmin(cl->cl_parent);
} }
} }
...@@ -839,9 +835,10 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time) ...@@ -839,9 +835,10 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
if (cl->cl_vt > cl->cl_parent->cl_cvtmax) if (cl->cl_vt > cl->cl_parent->cl_cvtmax)
cl->cl_parent->cl_cvtmax = cl->cl_vt; cl->cl_parent->cl_cvtmax = cl->cl_vt;
/* remove this class from the vt list */ /* remove this class from the vt tree */
actlist_remove(cl); vttree_remove(cl);
cftree_remove(cl);
update_cfmin(cl->cl_parent); update_cfmin(cl->cl_parent);
continue; continue;
...@@ -863,8 +860,8 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time) ...@@ -863,8 +860,8 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
cl->cl_vt = cl->cl_parent->cl_cvtmin; cl->cl_vt = cl->cl_parent->cl_cvtmin;
} }
/* update the vt list */ /* update the vt tree */
actlist_update(cl); vttree_update(cl);
if (cl->cl_flags & HFSC_USC) { if (cl->cl_flags & HFSC_USC) {
cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit, cl->cl_myf = cl->cl_myfadj + rtsc_y2x(&cl->cl_ulimit,
...@@ -894,6 +891,7 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time) ...@@ -894,6 +891,7 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
f = max(cl->cl_myf, cl->cl_cfmin); f = max(cl->cl_myf, cl->cl_cfmin);
if (f != cl->cl_f) { if (f != cl->cl_f) {
cl->cl_f = f; cl->cl_f = f;
cftree_update(cl);
update_cfmin(cl->cl_parent); update_cfmin(cl->cl_parent);
} }
} }
...@@ -919,8 +917,8 @@ set_passive(struct hfsc_class *cl) ...@@ -919,8 +917,8 @@ set_passive(struct hfsc_class *cl)
list_del(&cl->dlist); list_del(&cl->dlist);
/* /*
* actlist is now handled in update_vf() so that update_vf(cl, 0, 0) * vttree is now handled in update_vf() so that update_vf(cl, 0, 0)
* needs to be called explicitly to remove a class from actlist * needs to be called explicitly to remove a class from vttree.
*/ */
} }
...@@ -1144,7 +1142,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1144,7 +1142,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
cl->stats_lock = &sch->dev->queue_lock; cl->stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&cl->children); INIT_LIST_HEAD(&cl->children);
INIT_LIST_HEAD(&cl->actlist); cl->vt_tree = RB_ROOT;
cl->cf_tree = RB_ROOT;
sch_tree_lock(sch); sch_tree_lock(sch);
list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]);
...@@ -1544,7 +1543,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt) ...@@ -1544,7 +1543,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
q->root.qdisc = &noop_qdisc; q->root.qdisc = &noop_qdisc;
q->root.stats_lock = &sch->dev->queue_lock; q->root.stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&q->root.children); INIT_LIST_HEAD(&q->root.children);
INIT_LIST_HEAD(&q->root.actlist); q->root.vt_tree = RB_ROOT;
q->root.cf_tree = RB_ROOT;
list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]);
...@@ -1591,7 +1591,9 @@ hfsc_reset_class(struct hfsc_class *cl) ...@@ -1591,7 +1591,9 @@ hfsc_reset_class(struct hfsc_class *cl)
cl->cl_myfadj = 0; cl->cl_myfadj = 0;
cl->cl_cfmin = 0; cl->cl_cfmin = 0;
cl->cl_nactive = 0; cl->cl_nactive = 0;
INIT_LIST_HEAD(&cl->actlist);
cl->vt_tree = RB_ROOT;
cl->cf_tree = RB_ROOT;
qdisc_reset(cl->qdisc); qdisc_reset(cl->qdisc);
if (cl->cl_flags & HFSC_RSC) if (cl->cl_flags & HFSC_RSC)
...@@ -1729,7 +1731,7 @@ hfsc_dequeue(struct Qdisc *sch) ...@@ -1729,7 +1731,7 @@ hfsc_dequeue(struct Qdisc *sch)
* use link-sharing criteria * use link-sharing criteria
* get the class with the minimum vt in the hierarchy * get the class with the minimum vt in the hierarchy
*/ */
cl = actlist_get_minvt(&q->root, cur_time); cl = vttree_get_minvt(&q->root, cur_time);
if (cl == NULL) { if (cl == NULL) {
sch->stats.overlimits++; sch->stats.overlimits++;
hfsc_schedule_watchdog(sch, cur_time); hfsc_schedule_watchdog(sch, cur_time);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment