提交 fd5207be 编写于 作者: G Guan Jing 提交者: Zheng Zengkai

sched: Implement the function of qos smt expeller

hulk inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I52611
CVE: NA

--------------------------------

We implement the function of qos smt expeller by this following two points:
a)when online tasks and offline tasks are running on the same physical cpu,
online tasks will send ipi to expel offline tasks on the smt sibling cpus.
b)when online tasks are running, the smt sibling cpus will not allow
offline tasks to be selected.
Signed-off-by: NGuan Jing <guanjing6@huawei.com>
Reviewed-by: NChen Hui <judy.chenhui@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 4e57e412
...@@ -1830,9 +1830,16 @@ extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk); ...@@ -1830,9 +1830,16 @@ extern char *__get_task_comm(char *to, size_t len, struct task_struct *tsk);
__get_task_comm(buf, sizeof(buf), tsk); \ __get_task_comm(buf, sizeof(buf), tsk); \
}) })
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
void qos_smt_check_need_resched(void);
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static __always_inline void scheduler_ipi(void) static __always_inline void scheduler_ipi(void)
{ {
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
qos_smt_check_need_resched();
#endif
/* /*
* Fold TIF_NEED_RESCHED into the preempt_count; anybody setting * Fold TIF_NEED_RESCHED into the preempt_count; anybody setting
* TIF_NEED_RESCHED remotely (for the first time) will also send * TIF_NEED_RESCHED remotely (for the first time) will also send
......
...@@ -130,6 +130,10 @@ unsigned int sysctl_offline_wait_interval = 100; /* in ms */ ...@@ -130,6 +130,10 @@ unsigned int sysctl_offline_wait_interval = 100; /* in ms */
static int unthrottle_qos_cfs_rqs(int cpu); static int unthrottle_qos_cfs_rqs(int cpu);
#endif #endif
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
static DEFINE_PER_CPU(int, qos_smt_status);
#endif
#ifdef CONFIG_CFS_BANDWIDTH #ifdef CONFIG_CFS_BANDWIDTH
/* /*
* Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool * Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool
...@@ -7381,6 +7385,131 @@ void init_qos_hrtimer(int cpu) ...@@ -7381,6 +7385,131 @@ void init_qos_hrtimer(int cpu)
} }
#endif #endif
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
static bool qos_smt_check_siblings_status(int this_cpu)
{
int cpu;
if (!sched_smt_active())
return false;
for_each_cpu(cpu, cpu_smt_mask(this_cpu)) {
if (cpu == this_cpu)
continue;
if (per_cpu(qos_smt_status, cpu) == QOS_LEVEL_ONLINE)
return true;
}
return false;
}
static bool qos_smt_expelled(int this_cpu)
{
/*
* The qos_smt_status of siblings cpu is online, and current cpu only has
* offline tasks enqueued, there is not suitable task,
* so pick_next_task_fair return null.
*/
if (qos_smt_check_siblings_status(this_cpu) && sched_idle_cpu(this_cpu))
return true;
return false;
}
static bool qos_smt_update_status(struct task_struct *p)
{
int status = QOS_LEVEL_OFFLINE;
if (p != NULL && task_group(p)->qos_level >= QOS_LEVEL_ONLINE)
status = QOS_LEVEL_ONLINE;
if (__this_cpu_read(qos_smt_status) == status)
return false;
__this_cpu_write(qos_smt_status, status);
return true;
}
static void qos_smt_send_ipi(int this_cpu)
{
int cpu;
struct rq *rq = NULL;
if (!sched_smt_active())
return;
for_each_cpu(cpu, cpu_smt_mask(this_cpu)) {
if (cpu == this_cpu)
continue;
rq = cpu_rq(cpu);
/*
* There are two cases where current don't need to send scheduler_ipi:
* a) The qos_smt_status of siblings cpu is online;
* b) The cfs.h_nr_running of siblings cpu is 0.
*/
if (per_cpu(qos_smt_status, cpu) == QOS_LEVEL_ONLINE ||
rq->cfs.h_nr_running == 0)
continue;
smp_send_reschedule(cpu);
}
}
static void qos_smt_expel(int this_cpu, struct task_struct *p)
{
if (qos_smt_update_status(p))
qos_smt_send_ipi(this_cpu);
}
static bool _qos_smt_check_need_resched(int this_cpu, struct rq *rq)
{
int cpu;
if (!sched_smt_active())
return false;
for_each_cpu(cpu, cpu_smt_mask(this_cpu)) {
if (cpu == this_cpu)
continue;
/*
* There are two cases rely on the set need_resched to drive away
* offline task:
* a) The qos_smt_status of siblings cpu is online, the task of current cpu is offline;
* b) The qos_smt_status of siblings cpu is offline, the task of current cpu is idle,
* and current cpu only has SCHED_IDLE tasks enqueued.
*/
if (per_cpu(qos_smt_status, cpu) == QOS_LEVEL_ONLINE &&
task_group(current)->qos_level < QOS_LEVEL_ONLINE)
return true;
if (per_cpu(qos_smt_status, cpu) == QOS_LEVEL_OFFLINE &&
rq->curr == rq->idle && sched_idle_cpu(this_cpu))
return true;
}
return false;
}
void qos_smt_check_need_resched(void)
{
struct rq *rq = this_rq();
int this_cpu = rq->cpu;
if (test_tsk_need_resched(current))
return;
if (_qos_smt_check_need_resched(this_cpu, rq)) {
set_tsk_need_resched(current);
set_preempt_need_resched();
}
}
#endif
struct task_struct * struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf) pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{ {
...@@ -7389,14 +7518,32 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf ...@@ -7389,14 +7518,32 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
struct task_struct *p; struct task_struct *p;
int new_tasks; int new_tasks;
unsigned long time; unsigned long time;
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
int this_cpu = rq->cpu;
#endif
again: again:
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
if (qos_smt_expelled(this_cpu)) {
__this_cpu_write(qos_smt_status, QOS_LEVEL_OFFLINE);
return NULL;
}
#endif
if (!sched_fair_runnable(rq)) if (!sched_fair_runnable(rq))
goto idle; goto idle;
#ifdef CONFIG_FAIR_GROUP_SCHED #ifdef CONFIG_FAIR_GROUP_SCHED
if (!prev || prev->sched_class != &fair_sched_class) if (!prev || prev->sched_class != &fair_sched_class) {
goto simple; #ifdef CONFIG_QOS_SCHED
if (cfs_rq->idle_h_nr_running != 0 && rq->online)
goto qos_simple;
else
#endif
goto simple;
}
/* /*
* Because of the set_next_buddy() in dequeue_task_fair() it is rather * Because of the set_next_buddy() in dequeue_task_fair() it is rather
...@@ -7480,6 +7627,34 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf ...@@ -7480,6 +7627,34 @@ pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf
} }
goto done; goto done;
#ifdef CONFIG_QOS_SCHED
qos_simple:
if (prev)
put_prev_task(rq, prev);
do {
se = pick_next_entity(cfs_rq, NULL);
if (check_qos_cfs_rq(group_cfs_rq(se))) {
cfs_rq = &rq->cfs;
if (!cfs_rq->nr_running)
goto idle;
continue;
}
cfs_rq = group_cfs_rq(se);
} while (cfs_rq);
p = task_of(se);
while (se) {
set_next_entity(cfs_rq_of(se), se);
se = parent_entity(se);
}
goto done;
#endif
simple: simple:
#endif #endif
if (prev) if (prev)
...@@ -7508,6 +7683,9 @@ done: __maybe_unused; ...@@ -7508,6 +7683,9 @@ done: __maybe_unused;
update_misfit_status(p, rq); update_misfit_status(p, rq);
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
qos_smt_expel(this_cpu, p);
#endif
return p; return p;
idle: idle:
...@@ -7556,6 +7734,9 @@ done: __maybe_unused; ...@@ -7556,6 +7734,9 @@ done: __maybe_unused;
*/ */
update_idle_rq_clock_pelt(rq); update_idle_rq_clock_pelt(rq);
#ifdef CONFIG_QOS_SCHED_SMT_EXPELLER
qos_smt_expel(this_cpu, NULL);
#endif
return NULL; return NULL;
} }
......
...@@ -1136,6 +1136,11 @@ static inline int cpu_of(struct rq *rq) ...@@ -1136,6 +1136,11 @@ static inline int cpu_of(struct rq *rq)
} }
#ifdef CONFIG_QOS_SCHED #ifdef CONFIG_QOS_SCHED
enum task_qos_level {
QOS_LEVEL_OFFLINE = -1,
QOS_LEVEL_ONLINE = 0,
QOS_LEVEL_MAX
};
void init_qos_hrtimer(int cpu); void init_qos_hrtimer(int cpu);
#endif #endif
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册