Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 132 additions & 55 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,17 +789,22 @@ static inline u64 cfs_rq_max_slice(struct cfs_rq *cfs_rq);
*
* -r_max < lag < max(r_max, q)
*/
static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
static s64 entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 avruntime)
{
u64 max_slice = cfs_rq_max_slice(cfs_rq) + TICK_NSEC;
s64 vlag, limit;

WARN_ON_ONCE(!se->on_rq);

vlag = avg_vruntime(cfs_rq) - se->vruntime;
vlag = avruntime - se->vruntime;
limit = calc_delta_fair(max_slice, se);

se->vlag = clamp(vlag, -limit, limit);
return clamp(vlag, -limit, limit);
}

static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
WARN_ON_ONCE(!se->on_rq);

se->vlag = entity_lag(cfs_rq, se, avg_vruntime(cfs_rq));
}

/*
Expand Down Expand Up @@ -3879,29 +3884,125 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
cfs_rq->avg.load_avg * PELT_MIN_DIVIDER);
}

static void place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags);
static void
rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vprot)
{
unsigned long old_weight = se->load.weight;

/*
* VRUNTIME
* --------
*
* COROLLARY #1: The virtual runtime of the entity needs to be
* adjusted if re-weight at !0-lag point.
*
* Proof: For contradiction assume this is not true, so we can
* re-weight without changing vruntime at !0-lag point.
*
* Weight VRuntime Avg-VRuntime
* before w v V
* after w' v' V'
*
* Since lag needs to be preserved through re-weight:
*
* lag = (V - v)*w = (V'- v')*w', where v = v'
* ==> V' = (V - v)*w/w' + v (1)
*
* Let W be the total weight of the entities before reweight,
* since V' is the new weighted average of entities:
*
* V' = (WV + w'v - wv) / (W + w' - w) (2)
*
* by using (1) & (2) we obtain:
*
* (WV + w'v - wv) / (W + w' - w) = (V - v)*w/w' + v
* ==> (WV-Wv+Wv+w'v-wv)/(W+w'-w) = (V - v)*w/w' + v
* ==> (WV - Wv)/(W + w' - w) + v = (V - v)*w/w' + v
* ==> (V - v)*W/(W + w' - w) = (V - v)*w/w' (3)
*
* Since we are doing at !0-lag point which means V != v, we
* can simplify (3):
*
* ==> W / (W + w' - w) = w / w'
* ==> Ww' = Ww + ww' - ww
* ==> W * (w' - w) = w * (w' - w)
* ==> W = w (re-weight indicates w' != w)
*
* So the cfs_rq contains only one entity, hence vruntime of
* the entity @v should always equal to the cfs_rq's weighted
* average vruntime @V, which means we will always re-weight
* at 0-lag point, thus breach assumption. Proof completed.
*
*
* COROLLARY #2: Re-weight does NOT affect weighted average
* vruntime of all the entities.
*
* Proof: According to corollary #1, Eq. (1) should be:
*
* (V - v)*w = (V' - v')*w'
* ==> v' = V' - (V - v)*w/w' (4)
*
* According to the weighted average formula, we have:
*
* V' = (WV - wv + w'v') / (W - w + w')
* = (WV - wv + w'(V' - (V - v)w/w')) / (W - w + w')
* = (WV - wv + w'V' - Vw + wv) / (W - w + w')
* = (WV + w'V' - Vw) / (W - w + w')
*
* ==> V'*(W - w + w') = WV + w'V' - Vw
* ==> V' * (W - w) = (W - w) * V (5)
*
* If the entity is the only one in the cfs_rq, then reweight
* always occurs at 0-lag point, so V won't change. Or else
* there are other entities, hence W != w, then Eq. (5) turns
* into V' = V. So V won't change in either case, proof done.
*
*
* So according to corollary #1 & #2, the effect of re-weight
* on vruntime should be:
*
* v' = V' - (V - v) * w / w' (4)
* = V - (V - v) * w / w'
* = V - vl * w / w'
* = V - vl'
*/
se->vlag = div64_long(se->vlag * old_weight, weight);

/*
* DEADLINE
* --------
*
* When the weight changes, the virtual time slope changes and
* we should adjust the relative virtual deadline accordingly.
*
* d' = v' + (d - v)*w/w'
* = V' - (V - v)*w/w' + (d - v)*w/w'
* = V - (V - v)*w/w' + (d - v)*w/w'
* = V + (d - V)*w/w'
*/
if (se->rel_deadline)
se->deadline = div64_long(se->deadline * old_weight, weight);

if (rel_vprot)
se->vprot = div64_long(se->vprot * old_weight, weight);
}

void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
unsigned long weight)
unsigned long weight)
{
bool curr = cfs_rq->curr == se;
bool rel_vprot = false;
u64 vprot;
#ifdef CONFIG_SCHED_BORE
s64 vlag_unscaled = 0;
#endif /* !CONFIG_SCHED_BORE */
u64 avruntime = 0;

if (se->on_rq) {
/* commit outstanding execution time */
update_curr(cfs_rq);
update_entity_lag(cfs_rq, se);
#ifdef CONFIG_SCHED_BORE
vlag_unscaled = se->vlag;
#endif /* !CONFIG_SCHED_BORE */
se->deadline -= se->vruntime;
avruntime = avg_vruntime(cfs_rq);
se->vlag = entity_lag(cfs_rq, se, avruntime);
se->deadline -= avruntime;
se->rel_deadline = 1;
if (curr && protect_slice(se)) {
vprot = se->vprot - se->vruntime;
se->vprot -= avruntime;
rel_vprot = true;
Comment on lines 3997 to 4006
}

Expand All @@ -3912,40 +4013,23 @@ void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
}
dequeue_load_avg(cfs_rq, se);

/*
* Because we keep se->vlag = V - v_i, while: lag_i = w_i*(V - v_i),
* we need to scale se->vlag when w_i changes.
*/
se->vlag = div_s64(se->vlag * se->load.weight, weight);
if (se->rel_deadline)
se->deadline = div_s64(se->deadline * se->load.weight, weight);

if (rel_vprot)
vprot = div_s64(vprot * se->load.weight, weight);
rescale_entity(se, weight, rel_vprot);

update_load_set(&se->load, weight);

do {
u32 divider = get_pelt_divider(&se->avg);

se->avg.load_avg = div_u64(se_weight(se) * se->avg.load_sum, divider);
} while (0);

enqueue_load_avg(cfs_rq, se);
if (se->on_rq) {
#ifdef CONFIG_SCHED_BORE
if (curr) {
se->vruntime += vlag_unscaled - se->vlag;
if (se->rel_deadline) {
se->deadline += se->vruntime;
se->rel_deadline = 0;
}
}
else
#endif /* !CONFIG_SCHED_BORE */
place_entity(cfs_rq, se, 0);
if (rel_vprot)
se->vprot = se->vruntime + vprot;
se->vprot += avruntime;
se->deadline += avruntime;
se->rel_deadline = 0;
se->vruntime = avruntime - se->vlag;

update_load_add(&cfs_rq->load, se->load.weight);
if (!curr)
__enqueue_entity(cfs_rq, se);
Expand Down Expand Up @@ -5344,7 +5428,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)

se->vruntime = vruntime - lag;

if (se->rel_deadline) {
if (sched_feat(PLACE_REL_DEADLINE) && se->rel_deadline) {
se->deadline += se->vruntime;
se->rel_deadline = 0;
return;
Expand Down Expand Up @@ -5540,10 +5624,6 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
if (sched_feat(DELAY_DEQUEUE) && delay &&
!entity_eligible(cfs_rq, se)) {
update_load_avg(cfs_rq, se, 0);
#ifdef CONFIG_SCHED_BORE
if (static_branch_likely(&sched_bore_key) && sched_feat(DELAY_ZERO))
update_entity_lag(cfs_rq, se);
#endif /* CONFIG_SCHED_BORE */
set_delayed(se);
return false;
}
Expand Down Expand Up @@ -7027,22 +7107,19 @@ requeue_delayed_entity(struct sched_entity *se, int flags)
WARN_ON_ONCE(!se->on_rq);

if (sched_feat(DELAY_ZERO)) {
#ifdef CONFIG_SCHED_BORE
if (static_branch_likely(&sched_bore_key))
flags |= ENQUEUE_WAKEUP;
else {
#endif /* CONFIG_SCHED_BORE */
flags = 0;
update_entity_lag(cfs_rq, se);
#ifdef CONFIG_SCHED_BORE
}
#endif /* CONFIG_SCHED_BORE */
if (se->vlag > 0) {
cfs_rq->nr_queued--;
if (se != cfs_rq->curr)
__dequeue_entity(cfs_rq, se);
se->vlag = 0;
place_entity(cfs_rq, se, flags);
#ifdef CONFIG_SCHED_BORE
if (static_branch_likely(&sched_bore_key))
flags |= ENQUEUE_WAKEUP;
else
#endif /* CONFIG_SCHED_BORE */
flags = 0;
place_entity(cfs_rq, se, flags);
if (se != cfs_rq->curr)
__enqueue_entity(cfs_rq, se);
cfs_rq->nr_queued++;
Expand Down
Loading