FROMLIST: sched/pelt: Introduce PELT multiplier

The new sysctl sched_pelt_multiplier allows a user to set a clock
multiplier to x2 or x4 (x1 being the default). This clock multiplier
artificially speeds up PELT ramp up/down similarly to use a faster
half-life than the default 32ms.

  - x1: 32ms half-life
  - x2: 16ms half-life
  - x4: 8ms  half-life

Internally, a new clock is created: rq->clock_task_mult. It sits in the
clock hierarchy between rq->clock_task and rq->clock_pelt.

Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>
Signed-off-by: Dietmar Eggemann <dietmar.eggemann@arm.com>

Bug: 263742061
Link: https://lore.kernel.org/lkml/20220829055450.1703092-2-dietmar.eggemann@arm.com
Change-Id: Id379ff3cf07733ae63a854bc1e5af64426576788
Signed-off-by: Jing-Ting Wu <Jing-Ting.Wu@mediatek.com>
This commit is contained in:
Jing-Ting Wu 2023-01-05 18:09:06 +08:00
parent c0b208dbee
commit 0baa11384b
4 changed files with 100 additions and 5 deletions

View File

@ -733,7 +733,7 @@ static void update_rq_clock_task(struct rq *rq, s64 delta)
if ((irq_delta + steal) && sched_feat(NONTASK_CAPACITY))
update_irq_load_avg(rq, irq_delta + steal);
#endif
update_rq_clock_pelt(rq, delta);
update_rq_clock_task_mult(rq, delta);
}
void update_rq_clock(struct rq *rq)

View File

@ -468,3 +468,63 @@ int update_irq_load_avg(struct rq *rq, u64 running)
return ret;
}
#endif
__read_mostly unsigned int sched_pelt_lshift;
#ifdef CONFIG_SYSCTL
static unsigned int sysctl_sched_pelt_multiplier = 1;
int sched_pelt_multiplier(struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
static DEFINE_MUTEX(mutex);
unsigned int old;
int ret;
mutex_lock(&mutex);
old = sysctl_sched_pelt_multiplier;
ret = proc_dointvec(table, write, buffer, lenp, ppos);
if (ret)
goto undo;
if (!write)
goto done;
switch (sysctl_sched_pelt_multiplier) {
case 1:
fallthrough;
case 2:
fallthrough;
case 4:
WRITE_ONCE(sched_pelt_lshift,
sysctl_sched_pelt_multiplier >> 1);
goto done;
default:
ret = -EINVAL;
}
undo:
sysctl_sched_pelt_multiplier = old;
done:
mutex_unlock(&mutex);
return ret;
}
static struct ctl_table sched_pelt_sysctls[] = {
{
.procname = "sched_pelt_multiplier",
.data = &sysctl_sched_pelt_multiplier,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = sched_pelt_multiplier,
},
{}
};
static int __init sched_pelt_sysctl_init(void)
{
register_sysctl_init("kernel", sched_pelt_sysctls);
return 0;
}
late_initcall(sched_pelt_sysctl_init);
#endif

View File

@ -61,6 +61,14 @@ static inline void cfs_se_util_change(struct sched_avg *avg)
WRITE_ONCE(avg->util_est.enqueued, enqueued);
}
static inline u64 rq_clock_task_mult(struct rq *rq)
{
lockdep_assert_rq_held(rq);
assert_clock_updated(rq);
return rq->clock_task_mult;
}
static inline u64 rq_clock_pelt(struct rq *rq)
{
lockdep_assert_rq_held(rq);
@ -72,7 +80,7 @@ static inline u64 rq_clock_pelt(struct rq *rq)
/* The rq is idle, we can sync to clock_task */
static inline void _update_idle_rq_clock_pelt(struct rq *rq)
{
rq->clock_pelt = rq_clock_task(rq);
rq->clock_pelt = rq_clock_task_mult(rq);
u64_u32_store(rq->clock_idle, rq_clock(rq));
/* Paired with smp_rmb in migrate_se_pelt_lag() */
@ -121,6 +129,27 @@ static inline void update_rq_clock_pelt(struct rq *rq, s64 delta)
rq->clock_pelt += delta;
}
extern unsigned int sched_pelt_lshift;
/*
* absolute time |1 |2 |3 |4 |5 |6 |
* @ mult = 1 --------****************--------****************-
* @ mult = 2 --------********----------------********---------
* @ mult = 4 --------****--------------------****-------------
* clock task mult
* @ mult = 2 | | |2 |3 | | | | |5 |6 | | |
* @ mult = 4 | | | | |2|3| | | | | | | | | | |5|6| | | | | | |
*
*/
static inline void update_rq_clock_task_mult(struct rq *rq, s64 delta)
{
delta <<= READ_ONCE(sched_pelt_lshift);
rq->clock_task_mult += delta;
update_rq_clock_pelt(rq, delta);
}
/*
* When rq becomes idle, we have to check if it has lost idle time
* because it was fully busy. A rq is fully used when the /Sum util_sum
@ -147,7 +176,7 @@ static inline void update_idle_rq_clock_pelt(struct rq *rq)
* rq's clock_task.
*/
if (util_sum >= divider)
rq->lost_idle_time += rq_clock_task(rq) - rq->clock_pelt;
rq->lost_idle_time += rq_clock_task_mult(rq) - rq->clock_pelt;
_update_idle_rq_clock_pelt(rq);
}
@ -218,13 +247,18 @@ update_irq_load_avg(struct rq *rq, u64 running)
return 0;
}
static inline u64 rq_clock_pelt(struct rq *rq)
static inline u64 rq_clock_task_mult(struct rq *rq)
{
return rq_clock_task(rq);
}
static inline u64 rq_clock_pelt(struct rq *rq)
{
return rq_clock_task_mult(rq);
}
static inline void
update_rq_clock_pelt(struct rq *rq, s64 delta) { }
update_rq_clock_task_mult(struct rq *rq, s64 delta) { }
static inline void
update_idle_rq_clock_pelt(struct rq *rq) { }

View File

@ -1022,6 +1022,7 @@ struct rq {
u64 clock;
/* Ensure that all clocks are in the same cache line */
u64 clock_task ____cacheline_aligned;
u64 clock_task_mult;
u64 clock_pelt;
unsigned long lost_idle_time;
u64 clock_pelt_idle;