2019-05-19 12:08:55 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2011-11-15 16:14:39 +00:00
|
|
|
* kernel/sched/core.c
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Core kernel scheduler code and related syscalls
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 1991-2002 Linus Torvalds
|
|
|
|
*/
|
2018-03-03 11:20:47 +00:00
|
|
|
#include "sched.h"
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-04-20 12:29:51 +00:00
|
|
|
#include <linux/nospec.h>
|
kthread, sched/wait: Fix kthread_parkme() completion issue
Even with the wait-loop fixed, there is a further issue with
kthread_parkme(). Upon hotplug, when we do takedown_cpu(),
smpboot_park_threads() can return before all those threads are in fact
blocked, due to the placement of the complete() in __kthread_parkme().
When that happens, sched_cpu_dying() -> migrate_tasks() can end up
migrating such a still runnable task onto another CPU.
Normally the task will have hit schedule() and gone to sleep by the
time we do kthread_unpark(), which will then do __kthread_bind() to
re-bind the task to the correct CPU.
However, when we loose the initial TASK_PARKED store to the concurrent
wakeup issue described previously, do the complete(), get migrated, it
is possible to either:
- observe kthread_unpark()'s clearing of SHOULD_PARK and terminate
the park and set TASK_RUNNING, or
- __kthread_bind()'s wait_task_inactive() to observe the competing
TASK_RUNNING store.
Either way the WARN() in __kthread_bind() will trigger and fail to
correctly set the CPU affinity.
Fix this by only issuing the complete() when the kthread has scheduled
out. This does away with all the icky 'still running' nonsense.
The alternative is to promote TASK_PARKED to a special state, this
guarantees wait_task_inactive() cannot observe a 'stale' TASK_RUNNING
and we'll end up doing the right thing, but this preserves the whole
icky business of potentially migating the still runnable thing.
Reported-by: Gaurav Kohli <gkohli@codeaurora.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-05-01 16:14:45 +00:00
|
|
|
|
sched/core / kcov: avoid kcov_area during task switch
During a context switch, we first switch_mm() to the next task's mm,
then switch_to() that new task. This means that vmalloc'd regions which
had previously been faulted in can transiently disappear in the context
of the prev task.
Functions instrumented by KCOV may try to access a vmalloc'd kcov_area
during this window, and as the fault handling code is instrumented, this
results in a recursive fault.
We must avoid accessing any kcov_area during this window. We can do so
with a new flag in kcov_mode, set prior to switching the mm, and cleared
once the new task is live. Since task_struct::kcov_mode isn't always a
specific enum kcov_mode value, this is made an unsigned int.
The manipulation is hidden behind kcov_{prepare,finish}_switch() helpers,
which are empty for !CONFIG_KCOV kernels.
The code uses macros because I can't use static inline functions without a
circular include dependency between <linux/sched.h> and <linux/kcov.h>,
since the definition of task_struct uses things defined in <linux/kcov.h>
Link: http://lkml.kernel.org/r/20180504135535.53744-4-mark.rutland@arm.com
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-06-14 22:27:41 +00:00
|
|
|
#include <linux/kcov.h>
|
|
|
|
|
2012-03-28 17:30:03 +00:00
|
|
|
#include <asm/switch_to.h>
|
2007-05-08 07:32:57 +00:00
|
|
|
#include <asm/tlb.h>
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-01-18 22:05:55 +00:00
|
|
|
#include "../workqueue_internal.h"
|
2019-10-22 16:25:58 +00:00
|
|
|
#include "../../fs/io-wq.h"
|
2012-04-20 13:05:45 +00:00
|
|
|
#include "../smpboot.h"
|
2008-05-12 19:21:01 +00:00
|
|
|
|
2018-06-28 15:45:09 +00:00
|
|
|
#include "pelt.h"
|
|
|
|
|
2009-04-10 13:36:00 +00:00
|
|
|
#define CREATE_TRACE_POINTS
|
2009-04-14 23:39:12 +00:00
|
|
|
#include <trace/events/sched.h>
|
2009-04-10 13:36:00 +00:00
|
|
|
|
2019-06-04 11:14:59 +00:00
|
|
|
/*
|
|
|
|
* Export tracepoints that act as a bare tracehook (ie: have no trace event
|
|
|
|
* associated with them) to allow external modules to probe them.
|
|
|
|
*/
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_cfs_tp);
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_rt_tp);
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_dl_tp);
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_irq_tp);
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(pelt_se_tp);
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL_GPL(sched_overutilized_tp);
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
|
2010-06-08 09:40:42 +00:00
|
|
|
|
2018-12-30 15:14:15 +00:00
|
|
|
#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_JUMP_LABEL)
|
2007-10-15 15:00:04 +00:00
|
|
|
/*
|
|
|
|
* Debugging: various feature bits
|
sched/core: Optimize sched_feat() for !CONFIG_SCHED_DEBUG builds
When the kernel is compiled with !CONFIG_SCHED_DEBUG support, we expect that
all SCHED_FEAT are turned into compile time constants being propagated
to support compiler optimizations.
Specifically, we expect that code blocks like this:
if (sched_feat(FEATURE_NAME) [&& <other_conditions>]) {
/* FEATURE CODE */
}
are turned into dead-code in case FEATURE_NAME defaults to FALSE, and thus
being removed by the compiler from the finale image.
For this mechanism to properly work it's required for the compiler to
have full access, from each translation unit, to whatever is the value
defined by the sched_feat macro. This macro is defined as:
#define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
and thus, the compiler can optimize that code only if the value of
sysctl_sched_features is visible within each translation unit.
Since:
029632fbb ("sched: Make separate sched*.c translation units")
the scheduler code has been split into separate translation units
however the definition of sysctl_sched_features is part of
kernel/sched/core.c while, for all the other scheduler modules, it is
visible only via kernel/sched/sched.h as an:
extern const_debug unsigned int sysctl_sched_features
Unfortunately, an extern reference does not allow the compiler to apply
constants propagation. Thus, on !CONFIG_SCHED_DEBUG kernel we still end up
with code to load a memory reference and (eventually) doing an unconditional
jump of a chunk of code.
This mechanism is unavoidable when sched_features can be turned on and off at
run-time. However, this is not the case for "production" kernels compiled with
!CONFIG_SCHED_DEBUG. In this case, sysctl_sched_features is just a constant value
which cannot be changed at run-time and thus memory loads and jumps can be
avoided altogether.
This patch fixes the case of !CONFIG_SCHED_DEBUG kernel by declaring a local version
of the sysctl_sched_features constant for each translation unit. This will
ultimately allow the compiler to perform constants propagation and dead-code
pruning.
Tests have been done, with !CONFIG_SCHED_DEBUG on a v4.14-rc8 with and without
the patch, by running 30 iterations of:
perf bench sched messaging --pipe --thread --group 4 --loop 50000
on a 40 cores Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz using the
powersave governor to rule out variations due to frequency scaling.
Statistics on the reported completion time:
count mean std min 99% max
v4.14-rc8 30.0 15.7831 0.176032 15.442 16.01226 16.014
v4.14-rc8+patch 30.0 15.5033 0.189681 15.232 15.93938 15.962
... show a 1.8% speedup on average completion time and 0.5% speedup in the
99 percentile.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Chris Redpath <chris.redpath@arm.com>
Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Reviewed-by: Brendan Jackman <brendan.jackman@arm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Link: http://lkml.kernel.org/r/20171108184101.16006-1-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-11-08 18:41:01 +00:00
|
|
|
*
|
|
|
|
* If SCHED_DEBUG is disabled, each compilation unit has its own copy of
|
|
|
|
* sysctl_sched_features, defined in sched.h, to allow constants propagation
|
|
|
|
* at compile time and compiler optimization based on features default.
|
2007-10-15 15:00:04 +00:00
|
|
|
*/
|
2008-04-19 17:45:00 +00:00
|
|
|
#define SCHED_FEAT(name, enabled) \
|
|
|
|
(1UL << __SCHED_FEAT_##name) * enabled |
|
2007-10-15 15:00:04 +00:00
|
|
|
const_debug unsigned int sysctl_sched_features =
|
2011-11-15 16:14:39 +00:00
|
|
|
#include "features.h"
|
2008-04-19 17:45:00 +00:00
|
|
|
0;
|
|
|
|
#undef SCHED_FEAT
|
sched/core: Optimize sched_feat() for !CONFIG_SCHED_DEBUG builds
When the kernel is compiled with !CONFIG_SCHED_DEBUG support, we expect that
all SCHED_FEAT are turned into compile time constants being propagated
to support compiler optimizations.
Specifically, we expect that code blocks like this:
if (sched_feat(FEATURE_NAME) [&& <other_conditions>]) {
/* FEATURE CODE */
}
are turned into dead-code in case FEATURE_NAME defaults to FALSE, and thus
being removed by the compiler from the finale image.
For this mechanism to properly work it's required for the compiler to
have full access, from each translation unit, to whatever is the value
defined by the sched_feat macro. This macro is defined as:
#define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x))
and thus, the compiler can optimize that code only if the value of
sysctl_sched_features is visible within each translation unit.
Since:
029632fbb ("sched: Make separate sched*.c translation units")
the scheduler code has been split into separate translation units
however the definition of sysctl_sched_features is part of
kernel/sched/core.c while, for all the other scheduler modules, it is
visible only via kernel/sched/sched.h as an:
extern const_debug unsigned int sysctl_sched_features
Unfortunately, an extern reference does not allow the compiler to apply
constants propagation. Thus, on !CONFIG_SCHED_DEBUG kernel we still end up
with code to load a memory reference and (eventually) doing an unconditional
jump of a chunk of code.
This mechanism is unavoidable when sched_features can be turned on and off at
run-time. However, this is not the case for "production" kernels compiled with
!CONFIG_SCHED_DEBUG. In this case, sysctl_sched_features is just a constant value
which cannot be changed at run-time and thus memory loads and jumps can be
avoided altogether.
This patch fixes the case of !CONFIG_SCHED_DEBUG kernel by declaring a local version
of the sysctl_sched_features constant for each translation unit. This will
ultimately allow the compiler to perform constants propagation and dead-code
pruning.
Tests have been done, with !CONFIG_SCHED_DEBUG on a v4.14-rc8 with and without
the patch, by running 30 iterations of:
perf bench sched messaging --pipe --thread --group 4 --loop 50000
on a 40 cores Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz using the
powersave governor to rule out variations due to frequency scaling.
Statistics on the reported completion time:
count mean std min 99% max
v4.14-rc8 30.0 15.7831 0.176032 15.442 16.01226 16.014
v4.14-rc8+patch 30.0 15.5033 0.189681 15.232 15.93938 15.962
... show a 1.8% speedup on average completion time and 0.5% speedup in the
99 percentile.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Chris Redpath <chris.redpath@arm.com>
Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Reviewed-by: Brendan Jackman <brendan.jackman@arm.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Link: http://lkml.kernel.org/r/20171108184101.16006-1-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-11-08 18:41:01 +00:00
|
|
|
#endif
|
2008-04-19 17:45:00 +00:00
|
|
|
|
2007-11-09 21:39:39 +00:00
|
|
|
/*
|
|
|
|
* Number of tasks to iterate in a single balance run.
|
|
|
|
* Limited because this is done with IRQs disabled.
|
|
|
|
*/
|
|
|
|
const_debug unsigned int sysctl_sched_nr_migrate = 32;
|
|
|
|
|
2008-01-25 20:08:29 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* period over which we measure -rt task CPU usage in us.
|
2008-01-25 20:08:29 +00:00
|
|
|
* default: 1s
|
|
|
|
*/
|
2008-02-13 14:45:39 +00:00
|
|
|
unsigned int sysctl_sched_rt_period = 1000000;
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
__read_mostly int scheduler_running;
|
2008-02-13 13:02:36 +00:00
|
|
|
|
2008-02-13 14:45:39 +00:00
|
|
|
/*
|
|
|
|
* part of the period that we allow rt tasks to run in us.
|
|
|
|
* default: 0.95s
|
|
|
|
*/
|
|
|
|
int sysctl_sched_rt_runtime = 950000;
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2016-04-28 14:16:33 +00:00
|
|
|
/*
|
|
|
|
* __task_rq_lock - lock the rq @p resides on.
|
|
|
|
*/
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf)
|
2016-04-28 14:16:33 +00:00
|
|
|
__acquires(rq->lock)
|
|
|
|
{
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
lockdep_assert_held(&p->pi_lock);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
rq = task_rq(p);
|
|
|
|
raw_spin_lock(&rq->lock);
|
|
|
|
if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_pin_lock(rq, rf);
|
2016-04-28 14:16:33 +00:00
|
|
|
return rq;
|
|
|
|
}
|
|
|
|
raw_spin_unlock(&rq->lock);
|
|
|
|
|
|
|
|
while (unlikely(task_on_rq_migrating(p)))
|
|
|
|
cpu_relax();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* task_rq_lock - lock p->pi_lock and lock the rq @p resides on.
|
|
|
|
*/
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf)
|
2016-04-28 14:16:33 +00:00
|
|
|
__acquires(p->pi_lock)
|
|
|
|
__acquires(rq->lock)
|
|
|
|
{
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
for (;;) {
|
2015-07-31 19:28:18 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, rf->flags);
|
2016-04-28 14:16:33 +00:00
|
|
|
rq = task_rq(p);
|
|
|
|
raw_spin_lock(&rq->lock);
|
|
|
|
/*
|
|
|
|
* move_queued_task() task_rq_lock()
|
|
|
|
*
|
|
|
|
* ACQUIRE (rq->lock)
|
|
|
|
* [S] ->on_rq = MIGRATING [L] rq = task_rq()
|
|
|
|
* WMB (__set_task_cpu()) ACQUIRE (rq->lock);
|
|
|
|
* [S] ->cpu = new_cpu [L] task_rq()
|
|
|
|
* [L] ->on_rq
|
|
|
|
* RELEASE (rq->lock)
|
|
|
|
*
|
2019-01-21 15:52:40 +00:00
|
|
|
* If we observe the old CPU in task_rq_lock(), the acquire of
|
2016-04-28 14:16:33 +00:00
|
|
|
* the old rq->lock will fully serialize against the stores.
|
|
|
|
*
|
2019-01-21 15:52:40 +00:00
|
|
|
* If we observe the new CPU in task_rq_lock(), the address
|
|
|
|
* dependency headed by '[L] rq = task_rq()' and the acquire
|
|
|
|
* will pair with the WMB to ensure we then also see migrating.
|
2016-04-28 14:16:33 +00:00
|
|
|
*/
|
|
|
|
if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) {
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_pin_lock(rq, rf);
|
2016-04-28 14:16:33 +00:00
|
|
|
return rq;
|
|
|
|
}
|
|
|
|
raw_spin_unlock(&rq->lock);
|
2015-07-31 19:28:18 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags);
|
2016-04-28 14:16:33 +00:00
|
|
|
|
|
|
|
while (unlikely(task_on_rq_migrating(p)))
|
|
|
|
cpu_relax();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-01 11:29:21 +00:00
|
|
|
/*
|
|
|
|
* RQ-clock updating methods:
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void update_rq_clock_task(struct rq *rq, s64 delta)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* In theory, the compile should just see 0 here, and optimize out the call
|
|
|
|
* to sched_rt_avg_update. But I don't trust it...
|
|
|
|
*/
|
2018-09-25 09:17:42 +00:00
|
|
|
s64 __maybe_unused steal = 0, irq_delta = 0;
|
|
|
|
|
2017-02-01 11:29:21 +00:00
|
|
|
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
|
|
|
|
irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since irq_time is only updated on {soft,}irq_exit, we might run into
|
|
|
|
* this case when a previous update_rq_clock() happened inside a
|
|
|
|
* {soft,}irq region.
|
|
|
|
*
|
|
|
|
* When this happens, we stop ->clock_task and only update the
|
|
|
|
* prev_irq_time stamp to account for the part that fit, so that a next
|
|
|
|
* update will consume the rest. This ensures ->clock_task is
|
|
|
|
* monotonic.
|
|
|
|
*
|
|
|
|
* It does however cause some slight miss-attribution of {soft,}irq
|
|
|
|
* time, a more accurate solution would be to update the irq_time using
|
|
|
|
* the current rq->clock timestamp, except that would require using
|
|
|
|
* atomic ops.
|
|
|
|
*/
|
|
|
|
if (irq_delta > delta)
|
|
|
|
irq_delta = delta;
|
|
|
|
|
|
|
|
rq->prev_irq_time += irq_delta;
|
|
|
|
delta -= irq_delta;
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING
|
|
|
|
if (static_key_false((¶virt_steal_rq_enabled))) {
|
|
|
|
steal = paravirt_steal_clock(cpu_of(rq));
|
|
|
|
steal -= rq->prev_steal_time_rq;
|
|
|
|
|
|
|
|
if (unlikely(steal > delta))
|
|
|
|
steal = delta;
|
|
|
|
|
|
|
|
rq->prev_steal_time_rq += steal;
|
|
|
|
delta -= steal;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rq->clock_task += delta;
|
|
|
|
|
2018-09-25 09:17:42 +00:00
|
|
|
#ifdef CONFIG_HAVE_SCHED_AVG_IRQ
|
2017-02-01 11:29:21 +00:00
|
|
|
if ((irq_delta + steal) && sched_feat(NONTASK_CAPACITY))
|
2018-06-28 15:45:09 +00:00
|
|
|
update_irq_load_avg(rq, irq_delta + steal);
|
2017-02-01 11:29:21 +00:00
|
|
|
#endif
|
sched/fair: Update scale invariance of PELT
The current implementation of load tracking invariance scales the
contribution with current frequency and uarch performance (only for
utilization) of the CPU. One main result of this formula is that the
figures are capped by current capacity of CPU. Another one is that the
load_avg is not invariant because not scaled with uarch.
The util_avg of a periodic task that runs r time slots every p time slots
varies in the range :
U * (1-y^r)/(1-y^p) * y^i < Utilization < U * (1-y^r)/(1-y^p)
with U is the max util_avg value = SCHED_CAPACITY_SCALE
At a lower capacity, the range becomes:
U * C * (1-y^r')/(1-y^p) * y^i' < Utilization < U * C * (1-y^r')/(1-y^p)
with C reflecting the compute capacity ratio between current capacity and
max capacity.
so C tries to compensate changes in (1-y^r') but it can't be accurate.
Instead of scaling the contribution value of PELT algo, we should scale the
running time. The PELT signal aims to track the amount of computation of
tasks and/or rq so it seems more correct to scale the running time to
reflect the effective amount of computation done since the last update.
In order to be fully invariant, we need to apply the same amount of
running time and idle time whatever the current capacity. Because running
at lower capacity implies that the task will run longer, we have to ensure
that the same amount of idle time will be applied when system becomes idle
and no idle time has been "stolen". But reaching the maximum utilization
value (SCHED_CAPACITY_SCALE) means that the task is seen as an
always-running task whatever the capacity of the CPU (even at max compute
capacity). In this case, we can discard this "stolen" idle times which
becomes meaningless.
In order to achieve this time scaling, a new clock_pelt is created per rq.
The increase of this clock scales with current capacity when something
is running on rq and synchronizes with clock_task when rq is idle. With
this mechanism, we ensure the same running and idle time whatever the
current capacity. This also enables to simplify the pelt algorithm by
removing all references of uarch and frequency and applying the same
contribution to utilization and loads. Furthermore, the scaling is done
only once per update of clock (update_rq_clock_task()) instead of during
each update of sched_entities and cfs/rt/dl_rq of the rq like the current
implementation. This is interesting when cgroup are involved as shown in
the results below:
On a hikey (octo Arm64 platform).
Performance cpufreq governor and only shallowest c-state to remove variance
generated by those power features so we only track the impact of pelt algo.
each test runs 16 times:
./perf bench sched pipe
(higher is better)
kernel tip/sched/core + patch
ops/seconds ops/seconds diff
cgroup
root 59652(+/- 0.18%) 59876(+/- 0.24%) +0.38%
level1 55608(+/- 0.27%) 55923(+/- 0.24%) +0.57%
level2 52115(+/- 0.29%) 52564(+/- 0.22%) +0.86%
hackbench -l 1000
(lower is better)
kernel tip/sched/core + patch
duration(sec) duration(sec) diff
cgroup
root 4.453(+/- 2.37%) 4.383(+/- 2.88%) -1.57%
level1 4.859(+/- 8.50%) 4.830(+/- 7.07%) -0.60%
level2 5.063(+/- 9.83%) 4.928(+/- 9.66%) -2.66%
Then, the responsiveness of PELT is improved when CPU is not running at max
capacity with this new algorithm. I have put below some examples of
duration to reach some typical load values according to the capacity of the
CPU with current implementation and with this patch. These values has been
computed based on the geometric series and the half period value:
Util (%) max capacity half capacity(mainline) half capacity(w/ patch)
972 (95%) 138ms not reachable 276ms
486 (47.5%) 30ms 138ms 60ms
256 (25%) 13ms 32ms 26ms
On my hikey (octo Arm64 platform) with schedutil governor, the time to
reach max OPP when starting from a null utilization, decreases from 223ms
with current scale invariance down to 121ms with the new algorithm.
Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Morten.Rasmussen@arm.com
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: bsegall@google.com
Cc: dietmar.eggemann@arm.com
Cc: patrick.bellasi@arm.com
Cc: pjt@google.com
Cc: pkondeti@codeaurora.org
Cc: quentin.perret@arm.com
Cc: rjw@rjwysocki.net
Cc: srinivas.pandruvada@linux.intel.com
Cc: thara.gopinath@linaro.org
Link: https://lkml.kernel.org/r/1548257214-13745-3-git-send-email-vincent.guittot@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-01-23 15:26:53 +00:00
|
|
|
update_rq_clock_pelt(rq, delta);
|
2017-02-01 11:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void update_rq_clock(struct rq *rq)
|
|
|
|
{
|
|
|
|
s64 delta;
|
|
|
|
|
|
|
|
lockdep_assert_held(&rq->lock);
|
|
|
|
|
|
|
|
if (rq->clock_update_flags & RQCF_ACT_SKIP)
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SCHED_DEBUG
|
2016-10-03 14:53:49 +00:00
|
|
|
if (sched_feat(WARN_DOUBLE_CLOCK))
|
|
|
|
SCHED_WARN_ON(rq->clock_update_flags & RQCF_UPDATED);
|
2017-02-01 11:29:21 +00:00
|
|
|
rq->clock_update_flags |= RQCF_UPDATED;
|
|
|
|
#endif
|
2016-10-03 14:53:49 +00:00
|
|
|
|
2017-02-01 11:29:21 +00:00
|
|
|
delta = sched_clock_cpu(cpu_of(rq)) - rq->clock;
|
|
|
|
if (delta < 0)
|
|
|
|
return;
|
|
|
|
rq->clock += delta;
|
|
|
|
update_rq_clock_task(rq, delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-01-25 20:08:29 +00:00
|
|
|
#ifdef CONFIG_SCHED_HRTICK
|
|
|
|
/*
|
|
|
|
* Use HR-timers to deliver accurate preemption points.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void hrtick_clear(struct rq *rq)
|
|
|
|
{
|
|
|
|
if (hrtimer_active(&rq->hrtick_timer))
|
|
|
|
hrtimer_cancel(&rq->hrtick_timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* High-resolution timer tick.
|
|
|
|
* Runs from hardirq context with interrupts disabled.
|
|
|
|
*/
|
|
|
|
static enum hrtimer_restart hrtick(struct hrtimer *timer)
|
|
|
|
{
|
|
|
|
struct rq *rq = container_of(timer, struct rq, hrtick_timer);
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2008-01-25 20:08:29 +00:00
|
|
|
|
|
|
|
WARN_ON_ONCE(cpu_of(rq) != smp_processor_id());
|
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
2008-05-03 16:29:28 +00:00
|
|
|
update_rq_clock(rq);
|
2008-01-25 20:08:29 +00:00
|
|
|
rq->curr->sched_class->task_tick(rq, rq->curr, 1);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, &rf);
|
2008-01-25 20:08:29 +00:00
|
|
|
|
|
|
|
return HRTIMER_NORESTART;
|
|
|
|
}
|
|
|
|
|
2008-05-11 00:25:33 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2013-06-28 09:18:53 +00:00
|
|
|
|
2015-04-14 21:09:05 +00:00
|
|
|
static void __hrtick_restart(struct rq *rq)
|
2013-06-28 09:18:53 +00:00
|
|
|
{
|
|
|
|
struct hrtimer *timer = &rq->hrtick_timer;
|
|
|
|
|
2019-07-26 18:30:52 +00:00
|
|
|
hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED_HARD);
|
2013-06-28 09:18:53 +00:00
|
|
|
}
|
|
|
|
|
2008-07-18 16:01:23 +00:00
|
|
|
/*
|
|
|
|
* called from hardirq (IPI) context
|
|
|
|
*/
|
|
|
|
static void __hrtick_start(void *arg)
|
2008-04-29 08:02:46 +00:00
|
|
|
{
|
2008-07-18 16:01:23 +00:00
|
|
|
struct rq *rq = arg;
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2008-04-29 08:02:46 +00:00
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
2013-06-28 09:18:53 +00:00
|
|
|
__hrtick_restart(rq);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, &rf);
|
2008-04-29 08:02:46 +00:00
|
|
|
}
|
|
|
|
|
2008-07-18 16:01:23 +00:00
|
|
|
/*
|
|
|
|
* Called to set the hrtick timer state.
|
|
|
|
*
|
|
|
|
* called with rq->lock held and irqs disabled
|
|
|
|
*/
|
2011-10-25 08:00:11 +00:00
|
|
|
void hrtick_start(struct rq *rq, u64 delay)
|
2008-04-29 08:02:46 +00:00
|
|
|
{
|
2008-07-18 16:01:23 +00:00
|
|
|
struct hrtimer *timer = &rq->hrtick_timer;
|
2014-08-26 03:15:41 +00:00
|
|
|
ktime_t time;
|
|
|
|
s64 delta;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't schedule slices shorter than 10000ns, that just
|
|
|
|
* doesn't make sense and can cause timer DoS.
|
|
|
|
*/
|
|
|
|
delta = max_t(s64, delay, 10000LL);
|
|
|
|
time = ktime_add_ns(timer->base->get_time(), delta);
|
2008-04-29 08:02:46 +00:00
|
|
|
|
2008-09-01 22:02:30 +00:00
|
|
|
hrtimer_set_expires(timer, time);
|
2008-07-18 16:01:23 +00:00
|
|
|
|
2019-12-16 21:31:25 +00:00
|
|
|
if (rq == this_rq())
|
2013-06-28 09:18:53 +00:00
|
|
|
__hrtick_restart(rq);
|
2019-12-16 21:31:25 +00:00
|
|
|
else
|
2014-02-24 15:40:02 +00:00
|
|
|
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
|
2008-04-29 08:02:46 +00:00
|
|
|
}
|
|
|
|
|
2008-07-18 16:01:23 +00:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* Called to set the hrtick timer state.
|
|
|
|
*
|
|
|
|
* called with rq->lock held and irqs disabled
|
|
|
|
*/
|
2011-10-25 08:00:11 +00:00
|
|
|
void hrtick_start(struct rq *rq, u64 delay)
|
2008-07-18 16:01:23 +00:00
|
|
|
{
|
2014-11-26 00:44:06 +00:00
|
|
|
/*
|
|
|
|
* Don't schedule slices shorter than 10000ns, that just
|
|
|
|
* doesn't make sense. Rely on vruntime for fairness.
|
|
|
|
*/
|
|
|
|
delay = max_t(u64, delay, 10000LL);
|
2015-04-14 21:09:05 +00:00
|
|
|
hrtimer_start(&rq->hrtick_timer, ns_to_ktime(delay),
|
2019-07-26 18:30:52 +00:00
|
|
|
HRTIMER_MODE_REL_PINNED_HARD);
|
2008-07-18 16:01:23 +00:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_SMP */
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2018-02-21 04:17:23 +00:00
|
|
|
static void hrtick_rq_init(struct rq *rq)
|
2008-01-25 20:08:29 +00:00
|
|
|
{
|
2008-07-18 16:01:23 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
rq->hrtick_csd.flags = 0;
|
|
|
|
rq->hrtick_csd.func = __hrtick_start;
|
|
|
|
rq->hrtick_csd.info = rq;
|
|
|
|
#endif
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2019-07-26 18:30:52 +00:00
|
|
|
hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
|
2008-07-18 16:01:23 +00:00
|
|
|
rq->hrtick_timer.function = hrtick;
|
2008-01-25 20:08:29 +00:00
|
|
|
}
|
2008-09-22 21:55:46 +00:00
|
|
|
#else /* CONFIG_SCHED_HRTICK */
|
2008-01-25 20:08:29 +00:00
|
|
|
static inline void hrtick_clear(struct rq *rq)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-02-21 04:17:23 +00:00
|
|
|
static inline void hrtick_rq_init(struct rq *rq)
|
2008-01-25 20:08:29 +00:00
|
|
|
{
|
|
|
|
}
|
2008-09-22 21:55:46 +00:00
|
|
|
#endif /* CONFIG_SCHED_HRTICK */
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2016-03-24 14:38:01 +00:00
|
|
|
/*
|
|
|
|
* cmpxchg based fetch_or, macro so it works for different integer types
|
|
|
|
*/
|
|
|
|
#define fetch_or(ptr, mask) \
|
|
|
|
({ \
|
|
|
|
typeof(ptr) _ptr = (ptr); \
|
|
|
|
typeof(mask) _mask = (mask); \
|
|
|
|
typeof(*_ptr) _old, _val = *_ptr; \
|
|
|
|
\
|
|
|
|
for (;;) { \
|
|
|
|
_old = cmpxchg(_ptr, _val, _val | _mask); \
|
|
|
|
if (_old == _val) \
|
|
|
|
break; \
|
|
|
|
_val = _old; \
|
|
|
|
} \
|
|
|
|
_old; \
|
|
|
|
})
|
|
|
|
|
2014-06-04 17:31:18 +00:00
|
|
|
#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
|
2014-04-09 13:35:08 +00:00
|
|
|
/*
|
|
|
|
* Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG,
|
|
|
|
* this avoids any races wrt polling state changes and thereby avoids
|
|
|
|
* spurious IPIs.
|
|
|
|
*/
|
|
|
|
static bool set_nr_and_not_polling(struct task_struct *p)
|
|
|
|
{
|
|
|
|
struct thread_info *ti = task_thread_info(p);
|
|
|
|
return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG);
|
|
|
|
}
|
2014-06-04 17:31:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set.
|
|
|
|
*
|
|
|
|
* If this returns true, then the idle task promises to call
|
|
|
|
* sched_ttwu_pending() and reschedule soon.
|
|
|
|
*/
|
|
|
|
static bool set_nr_if_polling(struct task_struct *p)
|
|
|
|
{
|
|
|
|
struct thread_info *ti = task_thread_info(p);
|
2015-04-28 20:00:20 +00:00
|
|
|
typeof(ti->flags) old, val = READ_ONCE(ti->flags);
|
2014-06-04 17:31:18 +00:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (!(val & _TIF_POLLING_NRFLAG))
|
|
|
|
return false;
|
|
|
|
if (val & _TIF_NEED_RESCHED)
|
|
|
|
return true;
|
|
|
|
old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED);
|
|
|
|
if (old == val)
|
|
|
|
break;
|
|
|
|
val = old;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-04-09 13:35:08 +00:00
|
|
|
#else
|
|
|
|
static bool set_nr_and_not_polling(struct task_struct *p)
|
|
|
|
{
|
|
|
|
set_tsk_need_resched(p);
|
|
|
|
return true;
|
|
|
|
}
|
2014-06-04 17:31:18 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
static bool set_nr_if_polling(struct task_struct *p)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
2014-04-09 13:35:08 +00:00
|
|
|
#endif
|
|
|
|
|
2018-12-18 19:53:52 +00:00
|
|
|
static bool __wake_q_add(struct wake_q_head *head, struct task_struct *task)
|
2015-05-01 15:27:50 +00:00
|
|
|
{
|
|
|
|
struct wake_q_node *node = &task->wake_q;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Atomically grab the task, if ->wake_q is !nil already it means
|
|
|
|
* its already queued (either by us or someone else) and will get the
|
|
|
|
* wakeup due to that.
|
|
|
|
*
|
2018-12-17 09:14:53 +00:00
|
|
|
* In order to ensure that a pending wakeup will observe our pending
|
|
|
|
* state, even in the failed case, an explicit smp_mb() must be used.
|
2015-05-01 15:27:50 +00:00
|
|
|
*/
|
2018-12-17 09:14:53 +00:00
|
|
|
smp_mb__before_atomic();
|
2018-12-03 05:31:30 +00:00
|
|
|
if (unlikely(cmpxchg_relaxed(&node->next, NULL, WAKE_Q_TAIL)))
|
2018-12-18 19:53:52 +00:00
|
|
|
return false;
|
2015-05-01 15:27:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The head is context local, there can be no concurrency.
|
|
|
|
*/
|
|
|
|
*head->lastp = node;
|
|
|
|
head->lastp = &node->next;
|
2018-12-18 19:53:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wake_q_add() - queue a wakeup for 'later' waking.
|
|
|
|
* @head: the wake_q_head to add @task to
|
|
|
|
* @task: the task to queue for 'later' wakeup
|
|
|
|
*
|
|
|
|
* Queue a task for later wakeup, most likely by the wake_up_q() call in the
|
|
|
|
* same context, _HOWEVER_ this is not guaranteed, the wakeup can come
|
|
|
|
* instantly.
|
|
|
|
*
|
|
|
|
* This function must be used as-if it were wake_up_process(); IOW the task
|
|
|
|
* must be ready to be woken at this location.
|
|
|
|
*/
|
|
|
|
void wake_q_add(struct wake_q_head *head, struct task_struct *task)
|
|
|
|
{
|
|
|
|
if (__wake_q_add(head, task))
|
|
|
|
get_task_struct(task);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wake_q_add_safe() - safely queue a wakeup for 'later' waking.
|
|
|
|
* @head: the wake_q_head to add @task to
|
|
|
|
* @task: the task to queue for 'later' wakeup
|
|
|
|
*
|
|
|
|
* Queue a task for later wakeup, most likely by the wake_up_q() call in the
|
|
|
|
* same context, _HOWEVER_ this is not guaranteed, the wakeup can come
|
|
|
|
* instantly.
|
|
|
|
*
|
|
|
|
* This function must be used as-if it were wake_up_process(); IOW the task
|
|
|
|
* must be ready to be woken at this location.
|
|
|
|
*
|
|
|
|
* This function is essentially a task-safe equivalent to wake_q_add(). Callers
|
|
|
|
* that already hold reference to @task can call the 'safe' version and trust
|
|
|
|
* wake_q to do the right thing depending whether or not the @task is already
|
|
|
|
* queued for wakeup.
|
|
|
|
*/
|
|
|
|
void wake_q_add_safe(struct wake_q_head *head, struct task_struct *task)
|
|
|
|
{
|
|
|
|
if (!__wake_q_add(head, task))
|
|
|
|
put_task_struct(task);
|
2015-05-01 15:27:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void wake_up_q(struct wake_q_head *head)
|
|
|
|
{
|
|
|
|
struct wake_q_node *node = head->first;
|
|
|
|
|
|
|
|
while (node != WAKE_Q_TAIL) {
|
|
|
|
struct task_struct *task;
|
|
|
|
|
|
|
|
task = container_of(node, struct task_struct, wake_q);
|
|
|
|
BUG_ON(!task);
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Task can safely be re-inserted now: */
|
2015-05-01 15:27:50 +00:00
|
|
|
node = node->next;
|
|
|
|
task->wake_q.next = NULL;
|
|
|
|
|
|
|
|
/*
|
2018-07-16 18:06:03 +00:00
|
|
|
* wake_up_process() executes a full barrier, which pairs with
|
|
|
|
* the queueing in wake_q_add() so as not to miss wakeups.
|
2015-05-01 15:27:50 +00:00
|
|
|
*/
|
|
|
|
wake_up_process(task);
|
|
|
|
put_task_struct(task);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
2014-06-28 20:03:57 +00:00
|
|
|
* resched_curr - mark rq's current task 'to be rescheduled now'.
|
2007-07-09 16:51:59 +00:00
|
|
|
*
|
|
|
|
* On UP this means the setting of the need_resched flag, on SMP it
|
|
|
|
* might also involve a cross-CPU call to trigger the scheduler on
|
|
|
|
* the target CPU.
|
|
|
|
*/
|
2014-06-28 20:03:57 +00:00
|
|
|
void resched_curr(struct rq *rq)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2014-06-28 20:03:57 +00:00
|
|
|
struct task_struct *curr = rq->curr;
|
2007-07-09 16:51:59 +00:00
|
|
|
int cpu;
|
|
|
|
|
2014-06-28 20:03:57 +00:00
|
|
|
lockdep_assert_held(&rq->lock);
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2014-06-28 20:03:57 +00:00
|
|
|
if (test_tsk_need_resched(curr))
|
2007-07-09 16:51:59 +00:00
|
|
|
return;
|
|
|
|
|
2014-06-28 20:03:57 +00:00
|
|
|
cpu = cpu_of(rq);
|
2014-04-09 13:35:08 +00:00
|
|
|
|
2013-08-14 12:55:31 +00:00
|
|
|
if (cpu == smp_processor_id()) {
|
2014-06-28 20:03:57 +00:00
|
|
|
set_tsk_need_resched(curr);
|
2013-08-14 12:55:31 +00:00
|
|
|
set_preempt_need_resched();
|
2007-07-09 16:51:59 +00:00
|
|
|
return;
|
2013-08-14 12:55:31 +00:00
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2014-06-28 20:03:57 +00:00
|
|
|
if (set_nr_and_not_polling(curr))
|
2007-07-09 16:51:59 +00:00
|
|
|
smp_send_reschedule(cpu);
|
2014-06-04 17:31:15 +00:00
|
|
|
else
|
|
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
void resched_cpu(int cpu)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
unsigned long flags;
|
|
|
|
|
2017-09-18 15:54:40 +00:00
|
|
|
raw_spin_lock_irqsave(&rq->lock, flags);
|
2017-10-13 23:24:28 +00:00
|
|
|
if (cpu_online(cpu) || cpu == smp_processor_id())
|
|
|
|
resched_curr(rq);
|
2009-11-17 13:28:38 +00:00
|
|
|
raw_spin_unlock_irqrestore(&rq->lock, flags);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
2008-03-22 08:20:24 +00:00
|
|
|
|
2013-09-17 07:30:55 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2011-08-10 21:21:01 +00:00
|
|
|
#ifdef CONFIG_NO_HZ_COMMON
|
2010-05-22 00:09:41 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* In the semi idle case, use the nearest busy CPU for migrating timers
|
|
|
|
* from an idle CPU. This is good for power-savings.
|
2010-05-22 00:09:41 +00:00
|
|
|
*
|
|
|
|
* We don't do similar optimization for completely idle system, as
|
2017-02-01 10:46:42 +00:00
|
|
|
* selecting an idle CPU will add more delays to the timers than intended
|
|
|
|
* (as that CPU's timer base may not be uptodate wrt jiffies etc).
|
2010-05-22 00:09:41 +00:00
|
|
|
*/
|
2015-05-26 22:50:33 +00:00
|
|
|
int get_nohz_timer_target(void)
|
2010-05-22 00:09:41 +00:00
|
|
|
{
|
2020-01-13 00:50:27 +00:00
|
|
|
int i, cpu = smp_processor_id(), default_cpu = -1;
|
2010-05-22 00:09:41 +00:00
|
|
|
struct sched_domain *sd;
|
|
|
|
|
2020-01-13 00:50:27 +00:00
|
|
|
if (housekeeping_cpu(cpu, HK_FLAG_TIMER)) {
|
|
|
|
if (!idle_cpu(cpu))
|
|
|
|
return cpu;
|
|
|
|
default_cpu = cpu;
|
|
|
|
}
|
2014-03-18 10:56:07 +00:00
|
|
|
|
2011-04-18 09:24:34 +00:00
|
|
|
rcu_read_lock();
|
2010-05-22 00:09:41 +00:00
|
|
|
for_each_domain(cpu, sd) {
|
2020-01-13 00:50:27 +00:00
|
|
|
for_each_cpu_and(i, sched_domain_span(sd),
|
|
|
|
housekeeping_cpumask(HK_FLAG_TIMER)) {
|
sched/nohz: Fix affine unpinned timers mess
The following commit:
9642d18eee2c ("nohz: Affine unpinned timers to housekeepers")'
intended to affine unpinned timers to housekeepers:
unpinned timers(full dynaticks, idle) => nearest busy housekeepers(otherwise, fallback to any housekeepers)
unpinned timers(full dynaticks, busy) => nearest busy housekeepers(otherwise, fallback to any housekeepers)
unpinned timers(houserkeepers, idle) => nearest busy housekeepers(otherwise, fallback to itself)
However, the !idle_cpu(i) && is_housekeeping_cpu(cpu) check modified the
intention to:
unpinned timers(full dynaticks, idle) => any housekeepers(no mattter cpu topology)
unpinned timers(full dynaticks, busy) => any housekeepers(no mattter cpu topology)
unpinned timers(housekeepers, idle) => any busy cpus(otherwise, fallback to any housekeepers)
This patch fixes it by checking if there are busy housekeepers nearby,
otherwise falls to any housekeepers/itself. After the patch:
unpinned timers(full dynaticks, idle) => nearest busy housekeepers(otherwise, fallback to any housekeepers)
unpinned timers(full dynaticks, busy) => nearest busy housekeepers(otherwise, fallback to any housekeepers)
unpinned timers(housekeepers, idle) => nearest busy housekeepers(otherwise, fallback to itself)
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
[ Fixed the changelog. ]
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Fixes: 'commit 9642d18eee2c ("nohz: Affine unpinned timers to housekeepers")'
Link: http://lkml.kernel.org/r/1462344334-8303-1-git-send-email-wanpeng.li@hotmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-05-04 06:45:34 +00:00
|
|
|
if (cpu == i)
|
|
|
|
continue;
|
|
|
|
|
2020-01-13 00:50:27 +00:00
|
|
|
if (!idle_cpu(i)) {
|
2011-04-18 09:24:34 +00:00
|
|
|
cpu = i;
|
|
|
|
goto unlock;
|
|
|
|
}
|
|
|
|
}
|
2010-05-22 00:09:41 +00:00
|
|
|
}
|
2015-09-01 14:50:59 +00:00
|
|
|
|
2020-01-13 00:50:27 +00:00
|
|
|
if (default_cpu == -1)
|
|
|
|
default_cpu = housekeeping_any_cpu(HK_FLAG_TIMER);
|
|
|
|
cpu = default_cpu;
|
2011-04-18 09:24:34 +00:00
|
|
|
unlock:
|
|
|
|
rcu_read_unlock();
|
2010-05-22 00:09:41 +00:00
|
|
|
return cpu;
|
|
|
|
}
|
2017-02-01 10:46:42 +00:00
|
|
|
|
2008-03-22 08:20:24 +00:00
|
|
|
/*
|
|
|
|
* When add_timer_on() enqueues a timer into the timer wheel of an
|
|
|
|
* idle CPU then this timer might expire before the next timer event
|
|
|
|
* which is scheduled to wake up that CPU. In case of a completely
|
|
|
|
* idle system the next event might even be infinite time into the
|
|
|
|
* future. wake_up_idle_cpu() ensures that the CPU is woken up and
|
|
|
|
* leaves the inner idle loop so the newly added timer is taken into
|
|
|
|
* account when the CPU goes back to idle and evaluates the timer
|
|
|
|
* wheel for the next timer event.
|
|
|
|
*/
|
2011-08-10 21:21:01 +00:00
|
|
|
static void wake_up_idle_cpu(int cpu)
|
2008-03-22 08:20:24 +00:00
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
|
|
|
|
if (cpu == smp_processor_id())
|
|
|
|
return;
|
|
|
|
|
2014-06-04 17:31:17 +00:00
|
|
|
if (set_nr_and_not_polling(rq->idle))
|
2008-03-22 08:20:24 +00:00
|
|
|
smp_send_reschedule(cpu);
|
2014-06-04 17:31:15 +00:00
|
|
|
else
|
|
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2013-04-12 14:45:34 +00:00
|
|
|
static bool wake_up_full_nohz_cpu(int cpu)
|
2011-08-10 21:21:01 +00:00
|
|
|
{
|
2014-06-04 14:20:21 +00:00
|
|
|
/*
|
|
|
|
* We just need the target to call irq_exit() and re-evaluate
|
|
|
|
* the next tick. The nohz full kick at least implies that.
|
|
|
|
* If needed we can still optimize that later with an
|
|
|
|
* empty IRQ.
|
|
|
|
*/
|
sched: Make wake_up_nohz_cpu() handle CPUs going offline
Both timers and hrtimers are maintained on the outgoing CPU until
CPU_DEAD time, at which point they are migrated to a surviving CPU. If a
mod_timer() executes between CPU_DYING and CPU_DEAD time, x86 systems
will splat in native_smp_send_reschedule() when attempting to wake up
the just-now-offlined CPU, as shown below from a NO_HZ_FULL kernel:
[ 7976.741556] WARNING: CPU: 0 PID: 661 at /home/paulmck/public_git/linux-rcu/arch/x86/kernel/smp.c:125 native_smp_send_reschedule+0x39/0x40
[ 7976.741595] Modules linked in:
[ 7976.741595] CPU: 0 PID: 661 Comm: rcu_torture_rea Not tainted 4.7.0-rc2+ #1
[ 7976.741595] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
[ 7976.741595] 0000000000000000 ffff88000002fcc8 ffffffff8138ab2e 0000000000000000
[ 7976.741595] 0000000000000000 ffff88000002fd08 ffffffff8105cabc 0000007d1fd0ee18
[ 7976.741595] 0000000000000001 ffff88001fd16d40 ffff88001fd0ee00 ffff88001fd0ee00
[ 7976.741595] Call Trace:
[ 7976.741595] [<ffffffff8138ab2e>] dump_stack+0x67/0x99
[ 7976.741595] [<ffffffff8105cabc>] __warn+0xcc/0xf0
[ 7976.741595] [<ffffffff8105cb98>] warn_slowpath_null+0x18/0x20
[ 7976.741595] [<ffffffff8103cba9>] native_smp_send_reschedule+0x39/0x40
[ 7976.741595] [<ffffffff81089bc2>] wake_up_nohz_cpu+0x82/0x190
[ 7976.741595] [<ffffffff810d275a>] internal_add_timer+0x7a/0x80
[ 7976.741595] [<ffffffff810d3ee7>] mod_timer+0x187/0x2b0
[ 7976.741595] [<ffffffff810c89dd>] rcu_torture_reader+0x33d/0x380
[ 7976.741595] [<ffffffff810c66f0>] ? sched_torture_read_unlock+0x30/0x30
[ 7976.741595] [<ffffffff810c86a0>] ? rcu_bh_torture_read_lock+0x80/0x80
[ 7976.741595] [<ffffffff8108068f>] kthread+0xdf/0x100
[ 7976.741595] [<ffffffff819dd83f>] ret_from_fork+0x1f/0x40
[ 7976.741595] [<ffffffff810805b0>] ? kthread_create_on_node+0x200/0x200
However, in this case, the wakeup is redundant, because the timer
migration will reprogram timer hardware as needed. Note that the fact
that preemption is disabled does not avoid the splat, as the offline
operation has already passed both the synchronize_sched() and the
stop_machine() that would be blocked by disabled preemption.
This commit therefore modifies wake_up_nohz_cpu() to avoid attempting
to wake up offline CPUs. It also adds a comment stating that the
caller must tolerate lost wakeups when the target CPU is going offline,
and suggesting the CPU_DEAD notifier as a recovery mechanism.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
2016-06-30 17:37:20 +00:00
|
|
|
if (cpu_is_offline(cpu))
|
|
|
|
return true; /* Don't try to wake offline CPUs. */
|
2013-04-12 14:45:34 +00:00
|
|
|
if (tick_nohz_full_cpu(cpu)) {
|
2011-08-10 21:21:01 +00:00
|
|
|
if (cpu != smp_processor_id() ||
|
|
|
|
tick_nohz_tick_stopped())
|
2014-06-04 14:20:21 +00:00
|
|
|
tick_nohz_full_kick_cpu(cpu);
|
2011-08-10 21:21:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
sched: Make wake_up_nohz_cpu() handle CPUs going offline
Both timers and hrtimers are maintained on the outgoing CPU until
CPU_DEAD time, at which point they are migrated to a surviving CPU. If a
mod_timer() executes between CPU_DYING and CPU_DEAD time, x86 systems
will splat in native_smp_send_reschedule() when attempting to wake up
the just-now-offlined CPU, as shown below from a NO_HZ_FULL kernel:
[ 7976.741556] WARNING: CPU: 0 PID: 661 at /home/paulmck/public_git/linux-rcu/arch/x86/kernel/smp.c:125 native_smp_send_reschedule+0x39/0x40
[ 7976.741595] Modules linked in:
[ 7976.741595] CPU: 0 PID: 661 Comm: rcu_torture_rea Not tainted 4.7.0-rc2+ #1
[ 7976.741595] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
[ 7976.741595] 0000000000000000 ffff88000002fcc8 ffffffff8138ab2e 0000000000000000
[ 7976.741595] 0000000000000000 ffff88000002fd08 ffffffff8105cabc 0000007d1fd0ee18
[ 7976.741595] 0000000000000001 ffff88001fd16d40 ffff88001fd0ee00 ffff88001fd0ee00
[ 7976.741595] Call Trace:
[ 7976.741595] [<ffffffff8138ab2e>] dump_stack+0x67/0x99
[ 7976.741595] [<ffffffff8105cabc>] __warn+0xcc/0xf0
[ 7976.741595] [<ffffffff8105cb98>] warn_slowpath_null+0x18/0x20
[ 7976.741595] [<ffffffff8103cba9>] native_smp_send_reschedule+0x39/0x40
[ 7976.741595] [<ffffffff81089bc2>] wake_up_nohz_cpu+0x82/0x190
[ 7976.741595] [<ffffffff810d275a>] internal_add_timer+0x7a/0x80
[ 7976.741595] [<ffffffff810d3ee7>] mod_timer+0x187/0x2b0
[ 7976.741595] [<ffffffff810c89dd>] rcu_torture_reader+0x33d/0x380
[ 7976.741595] [<ffffffff810c66f0>] ? sched_torture_read_unlock+0x30/0x30
[ 7976.741595] [<ffffffff810c86a0>] ? rcu_bh_torture_read_lock+0x80/0x80
[ 7976.741595] [<ffffffff8108068f>] kthread+0xdf/0x100
[ 7976.741595] [<ffffffff819dd83f>] ret_from_fork+0x1f/0x40
[ 7976.741595] [<ffffffff810805b0>] ? kthread_create_on_node+0x200/0x200
However, in this case, the wakeup is redundant, because the timer
migration will reprogram timer hardware as needed. Note that the fact
that preemption is disabled does not avoid the splat, as the offline
operation has already passed both the synchronize_sched() and the
stop_machine() that would be blocked by disabled preemption.
This commit therefore modifies wake_up_nohz_cpu() to avoid attempting
to wake up offline CPUs. It also adds a comment stating that the
caller must tolerate lost wakeups when the target CPU is going offline,
and suggesting the CPU_DEAD notifier as a recovery mechanism.
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
2016-06-30 17:37:20 +00:00
|
|
|
/*
|
|
|
|
* Wake up the specified CPU. If the CPU is going offline, it is the
|
|
|
|
* caller's responsibility to deal with the lost wakeup, for example,
|
|
|
|
* by hooking into the CPU_DEAD notifier like timers and hrtimers do.
|
|
|
|
*/
|
2011-08-10 21:21:01 +00:00
|
|
|
void wake_up_nohz_cpu(int cpu)
|
|
|
|
{
|
2013-04-12 14:45:34 +00:00
|
|
|
if (!wake_up_full_nohz_cpu(cpu))
|
2011-08-10 21:21:01 +00:00
|
|
|
wake_up_idle_cpu(cpu);
|
|
|
|
}
|
|
|
|
|
2011-10-03 22:09:00 +00:00
|
|
|
static inline bool got_nohz_idle_kick(void)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2011-12-02 01:07:32 +00:00
|
|
|
int cpu = smp_processor_id();
|
2013-06-05 08:13:11 +00:00
|
|
|
|
2017-12-21 09:11:09 +00:00
|
|
|
if (!(atomic_read(nohz_flags(cpu)) & NOHZ_KICK_MASK))
|
2013-06-05 08:13:11 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (idle_cpu(cpu) && !need_resched())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't run Idle Load Balance on this CPU for this time so we
|
|
|
|
* cancel it and clear NOHZ_BALANCE_KICK
|
|
|
|
*/
|
2017-12-21 09:11:09 +00:00
|
|
|
atomic_andnot(NOHZ_KICK_MASK, nohz_flags(cpu));
|
2013-06-05 08:13:11 +00:00
|
|
|
return false;
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:21:01 +00:00
|
|
|
#else /* CONFIG_NO_HZ_COMMON */
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2011-10-03 22:09:00 +00:00
|
|
|
static inline bool got_nohz_idle_kick(void)
|
2010-11-15 23:47:00 +00:00
|
|
|
{
|
2011-10-03 22:09:00 +00:00
|
|
|
return false;
|
2010-11-15 23:47:00 +00:00
|
|
|
}
|
|
|
|
|
2011-08-10 21:21:01 +00:00
|
|
|
#endif /* CONFIG_NO_HZ_COMMON */
|
2007-12-02 19:04:49 +00:00
|
|
|
|
2013-04-20 13:15:35 +00:00
|
|
|
#ifdef CONFIG_NO_HZ_FULL
|
2015-07-17 20:25:49 +00:00
|
|
|
bool sched_can_stop_tick(struct rq *rq)
|
2013-04-20 13:15:35 +00:00
|
|
|
{
|
2015-07-17 20:25:49 +00:00
|
|
|
int fifo_nr_running;
|
|
|
|
|
|
|
|
/* Deadline tasks, even if single, need the tick */
|
|
|
|
if (rq->dl.dl_nr_running)
|
|
|
|
return false;
|
|
|
|
|
2015-02-16 20:23:49 +00:00
|
|
|
/*
|
2016-04-21 16:03:15 +00:00
|
|
|
* If there are more than one RR tasks, we need the tick to effect the
|
|
|
|
* actual RR behaviour.
|
2015-02-16 20:23:49 +00:00
|
|
|
*/
|
2015-07-17 20:25:49 +00:00
|
|
|
if (rq->rt.rr_nr_running) {
|
|
|
|
if (rq->rt.rr_nr_running == 1)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
2015-02-16 20:23:49 +00:00
|
|
|
}
|
|
|
|
|
2016-04-21 16:03:15 +00:00
|
|
|
/*
|
|
|
|
* If there's no RR tasks, but FIFO tasks, we can skip the tick, no
|
|
|
|
* forced preemption between FIFO tasks.
|
|
|
|
*/
|
|
|
|
fifo_nr_running = rq->rt.rt_nr_running - rq->rt.rr_nr_running;
|
|
|
|
if (fifo_nr_running)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are no DL,RR/FIFO tasks, there must only be CFS tasks left;
|
|
|
|
* if there's more than one we need the tick for involuntary
|
|
|
|
* preemption.
|
|
|
|
*/
|
|
|
|
if (rq->nr_running > 1)
|
2014-06-24 08:34:12 +00:00
|
|
|
return false;
|
2013-04-20 13:15:35 +00:00
|
|
|
|
2014-06-24 08:34:12 +00:00
|
|
|
return true;
|
2013-04-20 13:15:35 +00:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_NO_HZ_FULL */
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
2008-04-19 17:45:00 +00:00
|
|
|
|
2011-07-21 16:43:29 +00:00
|
|
|
#if defined(CONFIG_RT_GROUP_SCHED) || (defined(CONFIG_FAIR_GROUP_SCHED) && \
|
|
|
|
(defined(CONFIG_SMP) || defined(CONFIG_CFS_BANDWIDTH)))
|
2008-06-27 11:41:14 +00:00
|
|
|
/*
|
2011-07-21 16:43:35 +00:00
|
|
|
* Iterate task_group tree rooted at *from, calling @down when first entering a
|
|
|
|
* node and @up when leaving it for the final time.
|
|
|
|
*
|
|
|
|
* Caller must hold rcu_lock or sufficient equivalent.
|
2008-06-27 11:41:14 +00:00
|
|
|
*/
|
2011-10-25 08:00:11 +00:00
|
|
|
int walk_tg_tree_from(struct task_group *from,
|
2011-07-21 16:43:35 +00:00
|
|
|
tg_visitor down, tg_visitor up, void *data)
|
2008-06-27 11:41:14 +00:00
|
|
|
{
|
|
|
|
struct task_group *parent, *child;
|
2008-08-19 10:33:05 +00:00
|
|
|
int ret;
|
2008-06-27 11:41:14 +00:00
|
|
|
|
2011-07-21 16:43:35 +00:00
|
|
|
parent = from;
|
|
|
|
|
2008-06-27 11:41:14 +00:00
|
|
|
down:
|
2008-08-19 10:33:05 +00:00
|
|
|
ret = (*down)(parent, data);
|
|
|
|
if (ret)
|
2011-07-21 16:43:35 +00:00
|
|
|
goto out;
|
2008-06-27 11:41:14 +00:00
|
|
|
list_for_each_entry_rcu(child, &parent->children, siblings) {
|
|
|
|
parent = child;
|
|
|
|
goto down;
|
|
|
|
|
|
|
|
up:
|
|
|
|
continue;
|
|
|
|
}
|
2008-08-19 10:33:05 +00:00
|
|
|
ret = (*up)(parent, data);
|
2011-07-21 16:43:35 +00:00
|
|
|
if (ret || parent == from)
|
|
|
|
goto out;
|
2008-06-27 11:41:14 +00:00
|
|
|
|
|
|
|
child = parent;
|
|
|
|
parent = parent->parent;
|
|
|
|
if (parent)
|
|
|
|
goto up;
|
2011-07-21 16:43:35 +00:00
|
|
|
out:
|
2008-08-19 10:33:05 +00:00
|
|
|
return ret;
|
2008-06-27 11:41:14 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
int tg_nop(struct task_group *tg, void *data)
|
2008-08-19 10:33:05 +00:00
|
|
|
{
|
2011-08-01 09:03:28 +00:00
|
|
|
return 0;
|
2008-08-19 10:33:05 +00:00
|
|
|
}
|
2008-04-19 17:45:00 +00:00
|
|
|
#endif
|
|
|
|
|
2017-05-17 09:50:45 +00:00
|
|
|
static void set_load_weight(struct task_struct *p, bool update_load)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2011-05-18 17:09:38 +00:00
|
|
|
int prio = p->static_prio - MAX_RT_PRIO;
|
|
|
|
struct load_weight *load = &p->se.load;
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
|
|
|
* SCHED_IDLE tasks get minimal weight:
|
|
|
|
*/
|
2018-11-05 11:21:55 +00:00
|
|
|
if (task_has_idle_policy(p)) {
|
sched: Increase SCHED_LOAD_SCALE resolution
Introduce SCHED_LOAD_RESOLUTION, which scales is added to
SCHED_LOAD_SHIFT and increases the resolution of
SCHED_LOAD_SCALE. This patch sets the value of
SCHED_LOAD_RESOLUTION to 10, scaling up the weights for all
sched entities by a factor of 1024. With this extra resolution,
we can handle deeper cgroup hiearchies and the scheduler can do
better shares distribution and load load balancing on larger
systems (especially for low weight task groups).
This does not change the existing user interface, the scaled
weights are only used internally. We do not modify
prio_to_weight values or inverses, but use the original weights
when calculating the inverse which is used to scale execution
time delta in calc_delta_mine(). This ensures we do not lose
accuracy when accounting time to the sched entities. Thanks to
Nikunj Dadhania for fixing an bug in c_d_m() that broken fairness.
Below is some analysis of the performance costs/improvements of
this patch.
1. Micro-arch performance costs:
Experiment was to run Ingo's pipe_test_100k 200 times with the
task pinned to one cpu. I measured instruction, cycles and
stalled-cycles for the runs. See:
http://thread.gmane.org/gmane.linux.kernel/1129232/focus=1129389
for more info.
-tip (baseline):
Performance counter stats for '/root/load-scale/pipe-test-100k' (200 runs):
964,991,769 instructions # 0.82 insns per cycle
# 0.33 stalled cycles per insn
# ( +- 0.05% )
1,171,186,635 cycles # 0.000 GHz ( +- 0.08% )
306,373,664 stalled-cycles-backend # 26.16% backend cycles idle ( +- 0.28% )
314,933,621 stalled-cycles-frontend # 26.89% frontend cycles idle ( +- 0.34% )
1.122405684 seconds time elapsed ( +- 0.05% )
-tip+patches:
Performance counter stats for './load-scale/pipe-test-100k' (200 runs):
963,624,821 instructions # 0.82 insns per cycle
# 0.33 stalled cycles per insn
# ( +- 0.04% )
1,175,215,649 cycles # 0.000 GHz ( +- 0.08% )
315,321,126 stalled-cycles-backend # 26.83% backend cycles idle ( +- 0.28% )
316,835,873 stalled-cycles-frontend # 26.96% frontend cycles idle ( +- 0.29% )
1.122238659 seconds time elapsed ( +- 0.06% )
With this patch, instructions decrease by ~0.10% and cycles
increase by 0.27%. This doesn't look statistically significant.
The number of stalled cycles in the backend increased from
26.16% to 26.83%. This can be attributed to the shifts we do in
c_d_m() and other places. The fraction of stalled cycles in the
frontend remains about the same, at 26.96% compared to 26.89% in -tip.
2. Balancing low-weight task groups
Test setup: run 50 tasks with random sleep/busy times (biased
around 100ms) in a low weight container (with cpu.shares = 2).
Measure %idle as reported by mpstat over a 10s window.
-tip (baseline):
06:47:48 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle intr/s
06:47:49 PM all 94.32 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.62 15888.00
06:47:50 PM all 94.57 0.00 0.62 0.00 0.00 0.00 0.00 0.00 4.81 16180.00
06:47:51 PM all 94.69 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.25 15966.00
06:47:52 PM all 95.81 0.00 0.00 0.00 0.00 0.00 0.00 0.00 4.19 16053.00
06:47:53 PM all 94.88 0.06 0.00 0.00 0.00 0.00 0.00 0.00 5.06 15984.00
06:47:54 PM all 93.31 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.69 15806.00
06:47:55 PM all 94.19 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.75 15896.00
06:47:56 PM all 92.87 0.00 0.00 0.00 0.00 0.00 0.00 0.00 7.13 15716.00
06:47:57 PM all 94.88 0.00 0.00 0.00 0.00 0.00 0.00 0.00 5.12 15982.00
06:47:58 PM all 95.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00 4.56 16075.00
Average: all 94.49 0.01 0.08 0.00 0.00 0.00 0.00 0.00 5.42 15954.60
-tip+patches:
06:47:03 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle intr/s
06:47:04 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16630.00
06:47:05 PM all 99.69 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.31 16580.20
06:47:06 PM all 99.69 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.25 16596.00
06:47:07 PM all 99.20 0.00 0.74 0.00 0.00 0.06 0.00 0.00 0.00 17838.61
06:47:08 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16540.00
06:47:09 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16575.00
06:47:10 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16614.00
06:47:11 PM all 99.94 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.06 16588.00
06:47:12 PM all 99.94 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.00 16593.00
06:47:13 PM all 99.94 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.00 16551.00
Average: all 99.84 0.00 0.09 0.00 0.00 0.01 0.00 0.00 0.06 16711.58
We see an improvement in idle% on the system (drops from 5.42% on -tip to 0.06%
with the patches).
We see an improvement in idle% on the system (drops from 5.42%
on -tip to 0.06% with the patches).
Signed-off-by: Nikhil Rao <ncrao@google.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Cc: Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
Cc: Stephan Barwolf <stephan.baerwolf@tu-ilmenau.de>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: http://lkml.kernel.org/r/1305754668-18792-1-git-send-email-ncrao@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-05-18 21:37:48 +00:00
|
|
|
load->weight = scale_load(WEIGHT_IDLEPRIO);
|
2011-05-18 17:09:38 +00:00
|
|
|
load->inv_weight = WMULT_IDLEPRIO;
|
2007-07-09 16:51:59 +00:00
|
|
|
return;
|
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2017-05-17 09:50:45 +00:00
|
|
|
/*
|
|
|
|
* SCHED_OTHER tasks have to update their load when changing their
|
|
|
|
* weight
|
|
|
|
*/
|
|
|
|
if (update_load && p->sched_class == &fair_sched_class) {
|
|
|
|
reweight_task(p, prio);
|
|
|
|
} else {
|
|
|
|
load->weight = scale_load(sched_prio_to_weight[prio]);
|
|
|
|
load->inv_weight = sched_prio_to_wmult[prio];
|
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
#ifdef CONFIG_UCLAMP_TASK
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
/*
|
|
|
|
* Serializes updates of utilization clamp values
|
|
|
|
*
|
|
|
|
* The (slow-path) user-space triggers utilization clamp value updates which
|
|
|
|
* can require updates on (fast-path) scheduler's data structures used to
|
|
|
|
* support enqueue/dequeue operations.
|
|
|
|
* While the per-CPU rq lock protects fast-path update operations, user-space
|
|
|
|
* requests are serialized using a mutex to reduce the risk of conflicting
|
|
|
|
* updates or API abuses.
|
|
|
|
*/
|
|
|
|
static DEFINE_MUTEX(uclamp_mutex);
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
/* Max allowed minimum utilization */
|
|
|
|
unsigned int sysctl_sched_uclamp_util_min = SCHED_CAPACITY_SCALE;
|
|
|
|
|
|
|
|
/* Max allowed maximum utilization */
|
|
|
|
unsigned int sysctl_sched_uclamp_util_max = SCHED_CAPACITY_SCALE;
|
|
|
|
|
|
|
|
/* All clamps are required to be less or equal than these values */
|
|
|
|
static struct uclamp_se uclamp_default[UCLAMP_CNT];
|
2019-06-21 08:42:02 +00:00
|
|
|
|
|
|
|
/* Integer rounded range for each bucket */
|
|
|
|
#define UCLAMP_BUCKET_DELTA DIV_ROUND_CLOSEST(SCHED_CAPACITY_SCALE, UCLAMP_BUCKETS)
|
|
|
|
|
|
|
|
#define for_each_clamp_id(clamp_id) \
|
|
|
|
for ((clamp_id) = 0; (clamp_id) < UCLAMP_CNT; (clamp_id)++)
|
|
|
|
|
|
|
|
static inline unsigned int uclamp_bucket_id(unsigned int clamp_value)
|
|
|
|
{
|
|
|
|
return clamp_value / UCLAMP_BUCKET_DELTA;
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:03 +00:00
|
|
|
static inline unsigned int uclamp_bucket_base_value(unsigned int clamp_value)
|
|
|
|
{
|
|
|
|
return UCLAMP_BUCKET_DELTA * uclamp_bucket_id(clamp_value);
|
|
|
|
}
|
|
|
|
|
2019-11-15 10:39:08 +00:00
|
|
|
static inline unsigned int uclamp_none(enum uclamp_id clamp_id)
|
2019-06-21 08:42:02 +00:00
|
|
|
{
|
|
|
|
if (clamp_id == UCLAMP_MIN)
|
|
|
|
return 0;
|
|
|
|
return SCHED_CAPACITY_SCALE;
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
static inline void uclamp_se_set(struct uclamp_se *uc_se,
|
|
|
|
unsigned int value, bool user_defined)
|
2019-06-21 08:42:02 +00:00
|
|
|
{
|
|
|
|
uc_se->value = value;
|
|
|
|
uc_se->bucket_id = uclamp_bucket_id(value);
|
2019-06-21 08:42:07 +00:00
|
|
|
uc_se->user_defined = user_defined;
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:04 +00:00
|
|
|
static inline unsigned int
|
2019-08-22 13:28:11 +00:00
|
|
|
uclamp_idle_value(struct rq *rq, enum uclamp_id clamp_id,
|
2019-06-21 08:42:04 +00:00
|
|
|
unsigned int clamp_value)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Avoid blocked utilization pushing up the frequency when we go
|
|
|
|
* idle (which drops the max-clamp) by retaining the last known
|
|
|
|
* max-clamp.
|
|
|
|
*/
|
|
|
|
if (clamp_id == UCLAMP_MAX) {
|
|
|
|
rq->uclamp_flags |= UCLAMP_FLAG_IDLE;
|
|
|
|
return clamp_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return uclamp_none(UCLAMP_MIN);
|
|
|
|
}
|
|
|
|
|
2019-08-22 13:28:11 +00:00
|
|
|
static inline void uclamp_idle_reset(struct rq *rq, enum uclamp_id clamp_id,
|
2019-06-21 08:42:04 +00:00
|
|
|
unsigned int clamp_value)
|
|
|
|
{
|
|
|
|
/* Reset max-clamp retention only on idle exit */
|
|
|
|
if (!(rq->uclamp_flags & UCLAMP_FLAG_IDLE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
WRITE_ONCE(rq->uclamp[clamp_id].value, clamp_value);
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
static inline
|
2019-11-15 10:39:08 +00:00
|
|
|
unsigned int uclamp_rq_max_value(struct rq *rq, enum uclamp_id clamp_id,
|
2019-08-22 13:28:11 +00:00
|
|
|
unsigned int clamp_value)
|
2019-06-21 08:42:02 +00:00
|
|
|
{
|
|
|
|
struct uclamp_bucket *bucket = rq->uclamp[clamp_id].bucket;
|
|
|
|
int bucket_id = UCLAMP_BUCKETS - 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since both min and max clamps are max aggregated, find the
|
|
|
|
* top most bucket with tasks in.
|
|
|
|
*/
|
|
|
|
for ( ; bucket_id >= 0; bucket_id--) {
|
|
|
|
if (!bucket[bucket_id].tasks)
|
|
|
|
continue;
|
|
|
|
return bucket[bucket_id].value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No tasks -- default clamp values */
|
2019-06-21 08:42:04 +00:00
|
|
|
return uclamp_idle_value(rq, clamp_id, clamp_value);
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
sched/uclamp: Use TG's clamps to restrict TASK's clamps
When a task specific clamp value is configured via sched_setattr(2), this
value is accounted in the corresponding clamp bucket every time the task is
{en,de}qeued. However, when cgroups are also in use, the task specific
clamp values could be restricted by the task_group (TG) clamp values.
Update uclamp_cpu_inc() to aggregate task and TG clamp values. Every time a
task is enqueued, it's accounted in the clamp bucket tracking the smaller
clamp between the task specific value and its TG effective value. This
allows to:
1. ensure cgroup clamps are always used to restrict task specific requests,
i.e. boosted not more than its TG effective protection and capped at
least as its TG effective limit.
2. implement a "nice-like" policy, where tasks are still allowed to request
less than what enforced by their TG effective limits and protections
Do this by exploiting the concept of "effective" clamp, which is already
used by a TG to track parent enforced restrictions.
Apply task group clamp restrictions only to tasks belonging to a child
group. While, for tasks in the root group or in an autogroup, system
defaults are still enforced.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-5-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:09 +00:00
|
|
|
static inline struct uclamp_se
|
2019-08-22 13:28:11 +00:00
|
|
|
uclamp_tg_restrict(struct task_struct *p, enum uclamp_id clamp_id)
|
sched/uclamp: Use TG's clamps to restrict TASK's clamps
When a task specific clamp value is configured via sched_setattr(2), this
value is accounted in the corresponding clamp bucket every time the task is
{en,de}qeued. However, when cgroups are also in use, the task specific
clamp values could be restricted by the task_group (TG) clamp values.
Update uclamp_cpu_inc() to aggregate task and TG clamp values. Every time a
task is enqueued, it's accounted in the clamp bucket tracking the smaller
clamp between the task specific value and its TG effective value. This
allows to:
1. ensure cgroup clamps are always used to restrict task specific requests,
i.e. boosted not more than its TG effective protection and capped at
least as its TG effective limit.
2. implement a "nice-like" policy, where tasks are still allowed to request
less than what enforced by their TG effective limits and protections
Do this by exploiting the concept of "effective" clamp, which is already
used by a TG to track parent enforced restrictions.
Apply task group clamp restrictions only to tasks belonging to a child
group. While, for tasks in the root group or in an autogroup, system
defaults are still enforced.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-5-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:09 +00:00
|
|
|
{
|
|
|
|
struct uclamp_se uc_req = p->uclamp_req[clamp_id];
|
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
|
|
|
struct uclamp_se uc_max;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Tasks in autogroups or root task group will be
|
|
|
|
* restricted by system defaults.
|
|
|
|
*/
|
|
|
|
if (task_group_is_autogroup(task_group(p)))
|
|
|
|
return uc_req;
|
|
|
|
if (task_group(p) == &root_task_group)
|
|
|
|
return uc_req;
|
|
|
|
|
|
|
|
uc_max = task_group(p)->uclamp[clamp_id];
|
|
|
|
if (uc_req.value > uc_max.value || !uc_req.user_defined)
|
|
|
|
return uc_max;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return uc_req;
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
/*
|
|
|
|
* The effective clamp bucket index of a task depends on, by increasing
|
|
|
|
* priority:
|
|
|
|
* - the task specific clamp value, when explicitly requested from userspace
|
sched/uclamp: Use TG's clamps to restrict TASK's clamps
When a task specific clamp value is configured via sched_setattr(2), this
value is accounted in the corresponding clamp bucket every time the task is
{en,de}qeued. However, when cgroups are also in use, the task specific
clamp values could be restricted by the task_group (TG) clamp values.
Update uclamp_cpu_inc() to aggregate task and TG clamp values. Every time a
task is enqueued, it's accounted in the clamp bucket tracking the smaller
clamp between the task specific value and its TG effective value. This
allows to:
1. ensure cgroup clamps are always used to restrict task specific requests,
i.e. boosted not more than its TG effective protection and capped at
least as its TG effective limit.
2. implement a "nice-like" policy, where tasks are still allowed to request
less than what enforced by their TG effective limits and protections
Do this by exploiting the concept of "effective" clamp, which is already
used by a TG to track parent enforced restrictions.
Apply task group clamp restrictions only to tasks belonging to a child
group. While, for tasks in the root group or in an autogroup, system
defaults are still enforced.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-5-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:09 +00:00
|
|
|
* - the task group effective clamp value, for tasks not either in the root
|
|
|
|
* group or in an autogroup
|
2019-06-21 08:42:05 +00:00
|
|
|
* - the system default clamp value, defined by the sysadmin
|
|
|
|
*/
|
|
|
|
static inline struct uclamp_se
|
2019-08-22 13:28:11 +00:00
|
|
|
uclamp_eff_get(struct task_struct *p, enum uclamp_id clamp_id)
|
2019-06-21 08:42:05 +00:00
|
|
|
{
|
sched/uclamp: Use TG's clamps to restrict TASK's clamps
When a task specific clamp value is configured via sched_setattr(2), this
value is accounted in the corresponding clamp bucket every time the task is
{en,de}qeued. However, when cgroups are also in use, the task specific
clamp values could be restricted by the task_group (TG) clamp values.
Update uclamp_cpu_inc() to aggregate task and TG clamp values. Every time a
task is enqueued, it's accounted in the clamp bucket tracking the smaller
clamp between the task specific value and its TG effective value. This
allows to:
1. ensure cgroup clamps are always used to restrict task specific requests,
i.e. boosted not more than its TG effective protection and capped at
least as its TG effective limit.
2. implement a "nice-like" policy, where tasks are still allowed to request
less than what enforced by their TG effective limits and protections
Do this by exploiting the concept of "effective" clamp, which is already
used by a TG to track parent enforced restrictions.
Apply task group clamp restrictions only to tasks belonging to a child
group. While, for tasks in the root group or in an autogroup, system
defaults are still enforced.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-5-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:09 +00:00
|
|
|
struct uclamp_se uc_req = uclamp_tg_restrict(p, clamp_id);
|
2019-06-21 08:42:05 +00:00
|
|
|
struct uclamp_se uc_max = uclamp_default[clamp_id];
|
|
|
|
|
|
|
|
/* System default restrictions always apply */
|
|
|
|
if (unlikely(uc_req.value > uc_max.value))
|
|
|
|
return uc_max;
|
|
|
|
|
|
|
|
return uc_req;
|
|
|
|
}
|
|
|
|
|
2019-12-11 11:38:48 +00:00
|
|
|
unsigned long uclamp_eff_value(struct task_struct *p, enum uclamp_id clamp_id)
|
2019-06-21 08:42:11 +00:00
|
|
|
{
|
|
|
|
struct uclamp_se uc_eff;
|
|
|
|
|
|
|
|
/* Task currently refcounted: use back-annotated (effective) value */
|
|
|
|
if (p->uclamp[clamp_id].active)
|
2019-12-11 11:38:48 +00:00
|
|
|
return (unsigned long)p->uclamp[clamp_id].value;
|
2019-06-21 08:42:11 +00:00
|
|
|
|
|
|
|
uc_eff = uclamp_eff_get(p, clamp_id);
|
|
|
|
|
2019-12-11 11:38:48 +00:00
|
|
|
return (unsigned long)uc_eff.value;
|
2019-06-21 08:42:11 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
/*
|
|
|
|
* When a task is enqueued on a rq, the clamp bucket currently defined by the
|
|
|
|
* task's uclamp::bucket_id is refcounted on that rq. This also immediately
|
|
|
|
* updates the rq's clamp value if required.
|
2019-06-21 08:42:03 +00:00
|
|
|
*
|
|
|
|
* Tasks can have a task-specific value requested from user-space, track
|
|
|
|
* within each bucket the maximum value for tasks refcounted in it.
|
|
|
|
* This "local max aggregation" allows to track the exact "requested" value
|
|
|
|
* for each bucket when all its RUNNABLE tasks require the same clamp.
|
2019-06-21 08:42:02 +00:00
|
|
|
*/
|
|
|
|
static inline void uclamp_rq_inc_id(struct rq *rq, struct task_struct *p,
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id)
|
2019-06-21 08:42:02 +00:00
|
|
|
{
|
|
|
|
struct uclamp_rq *uc_rq = &rq->uclamp[clamp_id];
|
|
|
|
struct uclamp_se *uc_se = &p->uclamp[clamp_id];
|
|
|
|
struct uclamp_bucket *bucket;
|
|
|
|
|
|
|
|
lockdep_assert_held(&rq->lock);
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
/* Update task effective clamp */
|
|
|
|
p->uclamp[clamp_id] = uclamp_eff_get(p, clamp_id);
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
bucket = &uc_rq->bucket[uc_se->bucket_id];
|
|
|
|
bucket->tasks++;
|
2019-06-21 08:42:05 +00:00
|
|
|
uc_se->active = true;
|
2019-06-21 08:42:02 +00:00
|
|
|
|
2019-06-21 08:42:04 +00:00
|
|
|
uclamp_idle_reset(rq, clamp_id, uc_se->value);
|
|
|
|
|
2019-06-21 08:42:03 +00:00
|
|
|
/*
|
|
|
|
* Local max aggregation: rq buckets always track the max
|
|
|
|
* "requested" clamp value of its RUNNABLE tasks.
|
|
|
|
*/
|
|
|
|
if (bucket->tasks == 1 || uc_se->value > bucket->value)
|
|
|
|
bucket->value = uc_se->value;
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
if (uc_se->value > READ_ONCE(uc_rq->value))
|
2019-06-21 08:42:03 +00:00
|
|
|
WRITE_ONCE(uc_rq->value, uc_se->value);
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a task is dequeued from a rq, the clamp bucket refcounted by the task
|
|
|
|
* is released. If this is the last task reference counting the rq's max
|
|
|
|
* active clamp value, then the rq's clamp value is updated.
|
|
|
|
*
|
|
|
|
* Both refcounted tasks and rq's cached clamp values are expected to be
|
|
|
|
* always valid. If it's detected they are not, as defensive programming,
|
|
|
|
* enforce the expected state and warn.
|
|
|
|
*/
|
|
|
|
static inline void uclamp_rq_dec_id(struct rq *rq, struct task_struct *p,
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id)
|
2019-06-21 08:42:02 +00:00
|
|
|
{
|
|
|
|
struct uclamp_rq *uc_rq = &rq->uclamp[clamp_id];
|
|
|
|
struct uclamp_se *uc_se = &p->uclamp[clamp_id];
|
|
|
|
struct uclamp_bucket *bucket;
|
2019-06-21 08:42:04 +00:00
|
|
|
unsigned int bkt_clamp;
|
2019-06-21 08:42:02 +00:00
|
|
|
unsigned int rq_clamp;
|
|
|
|
|
|
|
|
lockdep_assert_held(&rq->lock);
|
|
|
|
|
|
|
|
bucket = &uc_rq->bucket[uc_se->bucket_id];
|
|
|
|
SCHED_WARN_ON(!bucket->tasks);
|
|
|
|
if (likely(bucket->tasks))
|
|
|
|
bucket->tasks--;
|
2019-06-21 08:42:05 +00:00
|
|
|
uc_se->active = false;
|
2019-06-21 08:42:02 +00:00
|
|
|
|
2019-06-21 08:42:03 +00:00
|
|
|
/*
|
|
|
|
* Keep "local max aggregation" simple and accept to (possibly)
|
|
|
|
* overboost some RUNNABLE tasks in the same bucket.
|
|
|
|
* The rq clamp bucket value is reset to its base value whenever
|
|
|
|
* there are no more RUNNABLE tasks refcounting it.
|
|
|
|
*/
|
2019-06-21 08:42:02 +00:00
|
|
|
if (likely(bucket->tasks))
|
|
|
|
return;
|
|
|
|
|
|
|
|
rq_clamp = READ_ONCE(uc_rq->value);
|
|
|
|
/*
|
|
|
|
* Defensive programming: this should never happen. If it happens,
|
|
|
|
* e.g. due to future modification, warn and fixup the expected value.
|
|
|
|
*/
|
|
|
|
SCHED_WARN_ON(bucket->value > rq_clamp);
|
2019-06-21 08:42:04 +00:00
|
|
|
if (bucket->value >= rq_clamp) {
|
|
|
|
bkt_clamp = uclamp_rq_max_value(rq, clamp_id, uc_se->value);
|
|
|
|
WRITE_ONCE(uc_rq->value, bkt_clamp);
|
|
|
|
}
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p)
|
|
|
|
{
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-06-21 08:42:02 +00:00
|
|
|
|
|
|
|
if (unlikely(!p->sched_class->uclamp_enabled))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id)
|
|
|
|
uclamp_rq_inc_id(rq, p, clamp_id);
|
2019-06-21 08:42:04 +00:00
|
|
|
|
|
|
|
/* Reset clamp idle holding when there is one RUNNABLE task */
|
|
|
|
if (rq->uclamp_flags & UCLAMP_FLAG_IDLE)
|
|
|
|
rq->uclamp_flags &= ~UCLAMP_FLAG_IDLE;
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p)
|
|
|
|
{
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-06-21 08:42:02 +00:00
|
|
|
|
|
|
|
if (unlikely(!p->sched_class->uclamp_enabled))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id)
|
|
|
|
uclamp_rq_dec_id(rq, p, clamp_id);
|
|
|
|
}
|
|
|
|
|
2019-08-22 13:28:10 +00:00
|
|
|
static inline void
|
2019-08-22 13:28:11 +00:00
|
|
|
uclamp_update_active(struct task_struct *p, enum uclamp_id clamp_id)
|
2019-08-22 13:28:10 +00:00
|
|
|
{
|
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lock the task and the rq where the task is (or was) queued.
|
|
|
|
*
|
|
|
|
* We might lock the (previous) rq of a !RUNNABLE task, but that's the
|
|
|
|
* price to pay to safely serialize util_{min,max} updates with
|
|
|
|
* enqueues, dequeues and migration operations.
|
|
|
|
* This is the same locking schema used by __set_cpus_allowed_ptr().
|
|
|
|
*/
|
|
|
|
rq = task_rq_lock(p, &rf);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setting the clamp bucket is serialized by task_rq_lock().
|
|
|
|
* If the task is not yet RUNNABLE and its task_struct is not
|
|
|
|
* affecting a valid clamp bucket, the next time it's enqueued,
|
|
|
|
* it will already see the updated clamp bucket value.
|
|
|
|
*/
|
2019-11-14 21:10:52 +00:00
|
|
|
if (p->uclamp[clamp_id].active) {
|
2019-08-22 13:28:10 +00:00
|
|
|
uclamp_rq_dec_id(rq, p, clamp_id);
|
|
|
|
uclamp_rq_inc_id(rq, p, clamp_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
task_rq_unlock(rq, p, &rf);
|
|
|
|
}
|
|
|
|
|
2019-11-05 11:22:12 +00:00
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
2019-08-22 13:28:10 +00:00
|
|
|
static inline void
|
|
|
|
uclamp_update_active_tasks(struct cgroup_subsys_state *css,
|
|
|
|
unsigned int clamps)
|
|
|
|
{
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-08-22 13:28:10 +00:00
|
|
|
struct css_task_iter it;
|
|
|
|
struct task_struct *p;
|
|
|
|
|
|
|
|
css_task_iter_start(css, 0, &it);
|
|
|
|
while ((p = css_task_iter_next(&it))) {
|
|
|
|
for_each_clamp_id(clamp_id) {
|
|
|
|
if ((0x1 << clamp_id) & clamps)
|
|
|
|
uclamp_update_active(p, clamp_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
css_task_iter_end(&it);
|
|
|
|
}
|
|
|
|
|
2019-08-22 13:28:08 +00:00
|
|
|
static void cpu_util_update_eff(struct cgroup_subsys_state *css);
|
|
|
|
static void uclamp_update_root_tg(void)
|
|
|
|
{
|
|
|
|
struct task_group *tg = &root_task_group;
|
|
|
|
|
|
|
|
uclamp_se_set(&tg->uclamp_req[UCLAMP_MIN],
|
|
|
|
sysctl_sched_uclamp_util_min, false);
|
|
|
|
uclamp_se_set(&tg->uclamp_req[UCLAMP_MAX],
|
|
|
|
sysctl_sched_uclamp_util_max, false);
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
cpu_util_update_eff(&root_task_group.css);
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void uclamp_update_root_tg(void) { }
|
|
|
|
#endif
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
int sysctl_sched_uclamp_handler(struct ctl_table *table, int write,
|
|
|
|
void __user *buffer, size_t *lenp,
|
|
|
|
loff_t *ppos)
|
|
|
|
{
|
2019-08-22 13:28:08 +00:00
|
|
|
bool update_root_tg = false;
|
2019-06-21 08:42:05 +00:00
|
|
|
int old_min, old_max;
|
|
|
|
int result;
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
mutex_lock(&uclamp_mutex);
|
2019-06-21 08:42:05 +00:00
|
|
|
old_min = sysctl_sched_uclamp_util_min;
|
|
|
|
old_max = sysctl_sched_uclamp_util_max;
|
|
|
|
|
|
|
|
result = proc_dointvec(table, write, buffer, lenp, ppos);
|
|
|
|
if (result)
|
|
|
|
goto undo;
|
|
|
|
if (!write)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (sysctl_sched_uclamp_util_min > sysctl_sched_uclamp_util_max ||
|
|
|
|
sysctl_sched_uclamp_util_max > SCHED_CAPACITY_SCALE) {
|
|
|
|
result = -EINVAL;
|
|
|
|
goto undo;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_min != sysctl_sched_uclamp_util_min) {
|
|
|
|
uclamp_se_set(&uclamp_default[UCLAMP_MIN],
|
2019-06-21 08:42:07 +00:00
|
|
|
sysctl_sched_uclamp_util_min, false);
|
2019-08-22 13:28:08 +00:00
|
|
|
update_root_tg = true;
|
2019-06-21 08:42:05 +00:00
|
|
|
}
|
|
|
|
if (old_max != sysctl_sched_uclamp_util_max) {
|
|
|
|
uclamp_se_set(&uclamp_default[UCLAMP_MAX],
|
2019-06-21 08:42:07 +00:00
|
|
|
sysctl_sched_uclamp_util_max, false);
|
2019-08-22 13:28:08 +00:00
|
|
|
update_root_tg = true;
|
2019-06-21 08:42:05 +00:00
|
|
|
}
|
|
|
|
|
2019-08-22 13:28:08 +00:00
|
|
|
if (update_root_tg)
|
|
|
|
uclamp_update_root_tg();
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
/*
|
2019-08-22 13:28:08 +00:00
|
|
|
* We update all RUNNABLE tasks only when task groups are in use.
|
|
|
|
* Otherwise, keep it simple and do just a lazy update at each next
|
|
|
|
* task enqueue time.
|
2019-06-21 08:42:05 +00:00
|
|
|
*/
|
2019-08-22 13:28:08 +00:00
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
undo:
|
|
|
|
sysctl_sched_uclamp_util_min = old_min;
|
|
|
|
sysctl_sched_uclamp_util_max = old_max;
|
|
|
|
done:
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
mutex_unlock(&uclamp_mutex);
|
2019-06-21 08:42:05 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
static int uclamp_validate(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr)
|
|
|
|
{
|
|
|
|
unsigned int lower_bound = p->uclamp_req[UCLAMP_MIN].value;
|
|
|
|
unsigned int upper_bound = p->uclamp_req[UCLAMP_MAX].value;
|
|
|
|
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MIN)
|
|
|
|
lower_bound = attr->sched_util_min;
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MAX)
|
|
|
|
upper_bound = attr->sched_util_max;
|
|
|
|
|
|
|
|
if (lower_bound > upper_bound)
|
|
|
|
return -EINVAL;
|
|
|
|
if (upper_bound > SCHED_CAPACITY_SCALE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __setscheduler_uclamp(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr)
|
|
|
|
{
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-06-21 08:42:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* On scheduling class change, reset to default clamps for tasks
|
|
|
|
* without a task-specific value.
|
|
|
|
*/
|
|
|
|
for_each_clamp_id(clamp_id) {
|
|
|
|
struct uclamp_se *uc_se = &p->uclamp_req[clamp_id];
|
|
|
|
unsigned int clamp_value = uclamp_none(clamp_id);
|
|
|
|
|
|
|
|
/* Keep using defined clamps across class changes */
|
|
|
|
if (uc_se->user_defined)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* By default, RT tasks always get 100% boost */
|
|
|
|
if (unlikely(rt_task(p) && clamp_id == UCLAMP_MIN))
|
|
|
|
clamp_value = uclamp_none(UCLAMP_MAX);
|
|
|
|
|
|
|
|
uclamp_se_set(uc_se, clamp_value, false);
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
if (likely(!(attr->sched_flags & SCHED_FLAG_UTIL_CLAMP)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MIN) {
|
|
|
|
uclamp_se_set(&p->uclamp_req[UCLAMP_MIN],
|
|
|
|
attr->sched_util_min, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP_MAX) {
|
|
|
|
uclamp_se_set(&p->uclamp_req[UCLAMP_MAX],
|
|
|
|
attr->sched_util_max, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
static void uclamp_fork(struct task_struct *p)
|
|
|
|
{
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-06-21 08:42:05 +00:00
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id)
|
|
|
|
p->uclamp[clamp_id].active = false;
|
2019-06-21 08:42:08 +00:00
|
|
|
|
|
|
|
if (likely(!p->sched_reset_on_fork))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id) {
|
2020-04-16 08:59:56 +00:00
|
|
|
uclamp_se_set(&p->uclamp_req[clamp_id],
|
|
|
|
uclamp_none(clamp_id), false);
|
2019-06-21 08:42:08 +00:00
|
|
|
}
|
2019-06-21 08:42:05 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
static void __init init_uclamp(void)
|
|
|
|
{
|
2019-06-21 08:42:05 +00:00
|
|
|
struct uclamp_se uc_max = {};
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-06-21 08:42:02 +00:00
|
|
|
int cpu;
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
mutex_init(&uclamp_mutex);
|
|
|
|
|
2019-06-21 08:42:04 +00:00
|
|
|
for_each_possible_cpu(cpu) {
|
2019-12-25 07:44:04 +00:00
|
|
|
memset(&cpu_rq(cpu)->uclamp, 0,
|
|
|
|
sizeof(struct uclamp_rq)*UCLAMP_CNT);
|
2019-06-21 08:42:04 +00:00
|
|
|
cpu_rq(cpu)->uclamp_flags = 0;
|
|
|
|
}
|
2019-06-21 08:42:02 +00:00
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id) {
|
2019-06-21 08:42:05 +00:00
|
|
|
uclamp_se_set(&init_task.uclamp_req[clamp_id],
|
2019-06-21 08:42:07 +00:00
|
|
|
uclamp_none(clamp_id), false);
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
2019-06-21 08:42:05 +00:00
|
|
|
|
|
|
|
/* System defaults allow max clamp values for both indexes */
|
2019-06-21 08:42:07 +00:00
|
|
|
uclamp_se_set(&uc_max, uclamp_none(UCLAMP_MAX), false);
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
for_each_clamp_id(clamp_id) {
|
2019-06-21 08:42:05 +00:00
|
|
|
uclamp_default[clamp_id] = uc_max;
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
|
|
|
root_task_group.uclamp_req[clamp_id] = uc_max;
|
2019-08-22 13:28:07 +00:00
|
|
|
root_task_group.uclamp[clamp_id] = uc_max;
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
#endif
|
|
|
|
}
|
2019-06-21 08:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /* CONFIG_UCLAMP_TASK */
|
|
|
|
static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p) { }
|
|
|
|
static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p) { }
|
2019-06-21 08:42:07 +00:00
|
|
|
static inline int uclamp_validate(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr)
|
|
|
|
{
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
static void __setscheduler_uclamp(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr) { }
|
2019-06-21 08:42:05 +00:00
|
|
|
static inline void uclamp_fork(struct task_struct *p) { }
|
2019-06-21 08:42:02 +00:00
|
|
|
static inline void init_uclamp(void) { }
|
|
|
|
#endif /* CONFIG_UCLAMP_TASK */
|
|
|
|
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
|
2008-06-27 20:30:00 +00:00
|
|
|
{
|
2016-10-04 14:29:45 +00:00
|
|
|
if (!(flags & ENQUEUE_NOCLOCK))
|
|
|
|
update_rq_clock(rq);
|
|
|
|
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
if (!(flags & ENQUEUE_RESTORE)) {
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
sched_info_queued(rq, p);
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
psi_enqueue(p, flags & ENQUEUE_WAKEUP);
|
|
|
|
}
|
2016-10-04 14:29:45 +00:00
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
uclamp_rq_inc(rq, p);
|
2010-03-24 15:38:48 +00:00
|
|
|
p->sched_class->enqueue_task(rq, p, flags);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2016-10-04 14:29:45 +00:00
|
|
|
if (!(flags & DEQUEUE_NOCLOCK))
|
|
|
|
update_rq_clock(rq);
|
|
|
|
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
if (!(flags & DEQUEUE_SAVE)) {
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
sched_info_dequeued(rq, p);
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
psi_dequeue(p, flags & DEQUEUE_SLEEP);
|
|
|
|
}
|
2016-10-04 14:29:45 +00:00
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
uclamp_rq_dec(rq, p);
|
2010-03-24 15:38:48 +00:00
|
|
|
p->sched_class->dequeue_task(rq, p, flags);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
void activate_task(struct rq *rq, struct task_struct *p, int flags)
|
2009-12-17 16:00:43 +00:00
|
|
|
{
|
|
|
|
if (task_contributes_to_load(p))
|
|
|
|
rq->nr_uninterruptible--;
|
|
|
|
|
2010-03-24 15:38:48 +00:00
|
|
|
enqueue_task(rq, p, flags);
|
2019-04-09 07:59:05 +00:00
|
|
|
|
|
|
|
p->on_rq = TASK_ON_RQ_QUEUED;
|
2009-12-17 16:00:43 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
|
2009-12-17 16:00:43 +00:00
|
|
|
{
|
2019-04-09 07:59:05 +00:00
|
|
|
p->on_rq = (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING;
|
|
|
|
|
2009-12-17 16:00:43 +00:00
|
|
|
if (task_contributes_to_load(p))
|
|
|
|
rq->nr_uninterruptible++;
|
|
|
|
|
2010-03-24 15:38:48 +00:00
|
|
|
dequeue_task(rq, p, flags);
|
2009-12-17 16:00:43 +00:00
|
|
|
}
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
2007-07-09 16:51:59 +00:00
|
|
|
* __normal_prio - return the priority that is based on the static prio
|
2007-07-09 16:51:59 +00:00
|
|
|
*/
|
|
|
|
static inline int __normal_prio(struct task_struct *p)
|
|
|
|
{
|
2007-07-09 16:51:59 +00:00
|
|
|
return p->static_prio;
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2006-06-27 09:54:51 +00:00
|
|
|
/*
|
|
|
|
* Calculate the expected normal priority: i.e. priority
|
|
|
|
* without taking RT-inheritance into account. Might be
|
|
|
|
* boosted by interactivity modifiers. Changes upon fork,
|
|
|
|
* setprio syscalls, and whenever the interactivity
|
|
|
|
* estimator recalculates.
|
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
static inline int normal_prio(struct task_struct *p)
|
2006-06-27 09:54:51 +00:00
|
|
|
{
|
|
|
|
int prio;
|
|
|
|
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (task_has_dl_policy(p))
|
|
|
|
prio = MAX_DL_PRIO-1;
|
|
|
|
else if (task_has_rt_policy(p))
|
2006-06-27 09:54:51 +00:00
|
|
|
prio = MAX_RT_PRIO-1 - p->rt_priority;
|
|
|
|
else
|
|
|
|
prio = __normal_prio(p);
|
|
|
|
return prio;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate the current priority, i.e. the priority
|
|
|
|
* taken into account by the scheduler. This value might
|
|
|
|
* be boosted by RT tasks, or might be boosted by
|
|
|
|
* interactivity modifiers. Will be RT if the task got
|
|
|
|
* RT-boosted. If not then it returns p->normal_prio.
|
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
static int effective_prio(struct task_struct *p)
|
2006-06-27 09:54:51 +00:00
|
|
|
{
|
|
|
|
p->normal_prio = normal_prio(p);
|
|
|
|
/*
|
|
|
|
* If we are RT tasks or we were boosted to RT priority,
|
|
|
|
* keep the priority unchanged. Otherwise, update priority
|
|
|
|
* to the normal priority:
|
|
|
|
*/
|
|
|
|
if (!rt_prio(p->prio))
|
|
|
|
return p->normal_prio;
|
|
|
|
return p->prio;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* task_curr - is this task currently executing on a CPU?
|
|
|
|
* @p: the task in question.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 1 if the task is currently executing. 0 otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
inline int task_curr(const struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
return cpu_curr(task_cpu(p)) == p;
|
|
|
|
}
|
|
|
|
|
2014-10-27 14:40:52 +00:00
|
|
|
/*
|
2015-06-11 12:46:39 +00:00
|
|
|
* switched_from, switched_to and prio_changed must _NOT_ drop rq->lock,
|
|
|
|
* use the balance_callback list if you want balancing.
|
|
|
|
*
|
|
|
|
* this means any call to check_class_changed() must be followed by a call to
|
|
|
|
* balance_callback().
|
2014-10-27 14:40:52 +00:00
|
|
|
*/
|
2008-01-25 20:08:22 +00:00
|
|
|
static inline void check_class_changed(struct rq *rq, struct task_struct *p,
|
|
|
|
const struct sched_class *prev_class,
|
2011-01-17 16:03:27 +00:00
|
|
|
int oldprio)
|
2008-01-25 20:08:22 +00:00
|
|
|
{
|
|
|
|
if (prev_class != p->sched_class) {
|
|
|
|
if (prev_class->switched_from)
|
2011-01-17 16:03:27 +00:00
|
|
|
prev_class->switched_from(rq, p);
|
2015-06-11 12:46:39 +00:00
|
|
|
|
2011-01-17 16:03:27 +00:00
|
|
|
p->sched_class->switched_to(rq, p);
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
} else if (oldprio != p->prio || dl_task(p))
|
2011-01-17 16:03:27 +00:00
|
|
|
p->sched_class->prio_changed(rq, p, oldprio);
|
2008-01-25 20:08:22 +00:00
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
|
2010-10-31 11:37:04 +00:00
|
|
|
{
|
|
|
|
const struct sched_class *class;
|
|
|
|
|
|
|
|
if (p->sched_class == rq->curr->sched_class) {
|
|
|
|
rq->curr->sched_class->check_preempt_curr(rq, p, flags);
|
|
|
|
} else {
|
|
|
|
for_each_class(class) {
|
|
|
|
if (class == rq->curr->sched_class)
|
|
|
|
break;
|
|
|
|
if (class == p->sched_class) {
|
2014-06-28 20:03:57 +00:00
|
|
|
resched_curr(rq);
|
2010-10-31 11:37:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A queue event has occurred, and we're going to schedule. In
|
|
|
|
* this case, we can save a useless back to back clock update.
|
|
|
|
*/
|
2014-08-20 09:47:32 +00:00
|
|
|
if (task_on_rq_queued(rq->curr) && test_tsk_need_resched(rq->curr))
|
2018-04-04 16:15:39 +00:00
|
|
|
rq_clock_skip_update(rq);
|
2010-10-31 11:37:04 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2017-07-25 16:58:21 +00:00
|
|
|
|
|
|
|
/*
|
2019-03-07 01:13:33 +00:00
|
|
|
* Per-CPU kthreads are allowed to run on !active && online CPUs, see
|
2017-07-25 16:58:21 +00:00
|
|
|
* __set_cpus_allowed_ptr() and select_fallback_rq().
|
|
|
|
*/
|
|
|
|
static inline bool is_cpu_allowed(struct task_struct *p, int cpu)
|
|
|
|
{
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(cpu, p->cpus_ptr))
|
2017-07-25 16:58:21 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (is_per_cpu_kthread(p))
|
|
|
|
return cpu_online(cpu);
|
|
|
|
|
|
|
|
return cpu_active(cpu);
|
|
|
|
}
|
|
|
|
|
2015-06-11 12:46:50 +00:00
|
|
|
/*
|
|
|
|
* This is how migration works:
|
|
|
|
*
|
|
|
|
* 1) we invoke migration_cpu_stop() on the target CPU using
|
|
|
|
* stop_one_cpu().
|
|
|
|
* 2) stopper starts to run (implicitly forcing the migrated thread
|
|
|
|
* off the CPU)
|
|
|
|
* 3) it checks whether the migrated task is still in the wrong runqueue.
|
|
|
|
* 4) if it's in the wrong runqueue then the migration thread removes
|
|
|
|
* it and puts it into the right queue.
|
|
|
|
* 5) stopper completes and stop_one_cpu() returns and the migration
|
|
|
|
* is done.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* move_queued_task - move a queued task to new rq.
|
|
|
|
*
|
|
|
|
* Returns (locked) new rq. Old rq's lock is released.
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
|
|
|
|
struct task_struct *p, int new_cpu)
|
2015-06-11 12:46:50 +00:00
|
|
|
{
|
|
|
|
lockdep_assert_held(&rq->lock);
|
|
|
|
|
2019-01-21 15:52:40 +00:00
|
|
|
WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
|
2016-10-05 15:59:32 +00:00
|
|
|
dequeue_task(rq, p, DEQUEUE_NOCLOCK);
|
2015-06-11 12:46:50 +00:00
|
|
|
set_task_cpu(p, new_cpu);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, rf);
|
2015-06-11 12:46:50 +00:00
|
|
|
|
|
|
|
rq = cpu_rq(new_cpu);
|
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, rf);
|
2015-06-11 12:46:50 +00:00
|
|
|
BUG_ON(task_cpu(p) != new_cpu);
|
|
|
|
enqueue_task(rq, p, 0);
|
2015-11-13 03:38:54 +00:00
|
|
|
p->on_rq = TASK_ON_RQ_QUEUED;
|
2015-06-11 12:46:50 +00:00
|
|
|
check_preempt_curr(rq, p, 0);
|
|
|
|
|
|
|
|
return rq;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct migration_arg {
|
|
|
|
struct task_struct *task;
|
|
|
|
int dest_cpu;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Move (not current) task off this CPU, onto the destination CPU. We're doing
|
2015-06-11 12:46:50 +00:00
|
|
|
* this because either it can't run here any more (set_cpus_allowed()
|
|
|
|
* away from this CPU, or CPU going down), or because we're
|
|
|
|
* attempting to rebalance this task on exec (sched_exec).
|
|
|
|
*
|
|
|
|
* So we race with normal scheduler movements, but that's OK, as long
|
|
|
|
* as the task is no longer on this CPU.
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
static struct rq *__migrate_task(struct rq *rq, struct rq_flags *rf,
|
|
|
|
struct task_struct *p, int dest_cpu)
|
2015-06-11 12:46:50 +00:00
|
|
|
{
|
|
|
|
/* Affinity changed (again). */
|
2017-07-25 16:58:21 +00:00
|
|
|
if (!is_cpu_allowed(p, dest_cpu))
|
2015-06-11 12:46:51 +00:00
|
|
|
return rq;
|
2015-06-11 12:46:50 +00:00
|
|
|
|
2016-10-05 15:59:32 +00:00
|
|
|
update_rq_clock(rq);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq = move_queued_task(rq, rf, p, dest_cpu);
|
2015-06-11 12:46:51 +00:00
|
|
|
|
|
|
|
return rq;
|
2015-06-11 12:46:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* migration_cpu_stop - this will be executed by a highprio stopper thread
|
|
|
|
* and performs thread migration by bumping thread off CPU then
|
|
|
|
* 'pushing' onto another runqueue.
|
|
|
|
*/
|
|
|
|
static int migration_cpu_stop(void *data)
|
|
|
|
{
|
|
|
|
struct migration_arg *arg = data;
|
2015-06-11 12:46:51 +00:00
|
|
|
struct task_struct *p = arg->task;
|
|
|
|
struct rq *rq = this_rq();
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2015-06-11 12:46:50 +00:00
|
|
|
|
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* The original target CPU might have gone down and we might
|
|
|
|
* be on another CPU but it doesn't matter.
|
2015-06-11 12:46:50 +00:00
|
|
|
*/
|
|
|
|
local_irq_disable();
|
|
|
|
/*
|
|
|
|
* We need to explicitly wake pending tasks before running
|
2019-04-23 14:26:36 +00:00
|
|
|
* __migrate_task() such that we will not miss enforcing cpus_ptr
|
2015-06-11 12:46:50 +00:00
|
|
|
* during wakeups, see set_cpus_allowed_ptr()'s TASK_WAKING test.
|
|
|
|
*/
|
|
|
|
sched_ttwu_pending();
|
2015-06-11 12:46:51 +00:00
|
|
|
|
|
|
|
raw_spin_lock(&p->pi_lock);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
2015-06-11 12:46:51 +00:00
|
|
|
/*
|
|
|
|
* If task_rq(p) != rq, it cannot be migrated here, because we're
|
|
|
|
* holding rq->lock, if p->on_rq == 0 it cannot get enqueued because
|
|
|
|
* we're holding p->pi_lock.
|
|
|
|
*/
|
2016-09-14 02:01:50 +00:00
|
|
|
if (task_rq(p) == rq) {
|
|
|
|
if (task_on_rq_queued(p))
|
2016-10-04 14:04:35 +00:00
|
|
|
rq = __migrate_task(rq, &rf, p, arg->dest_cpu);
|
2016-09-14 02:01:50 +00:00
|
|
|
else
|
|
|
|
p->wake_cpu = arg->dest_cpu;
|
|
|
|
}
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, &rf);
|
2015-06-11 12:46:51 +00:00
|
|
|
raw_spin_unlock(&p->pi_lock);
|
|
|
|
|
2015-06-11 12:46:50 +00:00
|
|
|
local_irq_enable();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 15:43:35 +00:00
|
|
|
/*
|
|
|
|
* sched_class::set_cpus_allowed must do the below, but is not required to
|
|
|
|
* actually call this function.
|
|
|
|
*/
|
|
|
|
void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask)
|
2015-06-11 12:46:50 +00:00
|
|
|
{
|
2019-04-23 14:26:36 +00:00
|
|
|
cpumask_copy(&p->cpus_mask, new_mask);
|
2015-06-11 12:46:50 +00:00
|
|
|
p->nr_cpus_allowed = cpumask_weight(new_mask);
|
|
|
|
}
|
|
|
|
|
2015-05-15 15:43:35 +00:00
|
|
|
void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask)
|
|
|
|
{
|
2015-05-15 15:43:36 +00:00
|
|
|
struct rq *rq = task_rq(p);
|
|
|
|
bool queued, running;
|
|
|
|
|
2015-05-15 15:43:35 +00:00
|
|
|
lockdep_assert_held(&p->pi_lock);
|
2015-05-15 15:43:36 +00:00
|
|
|
|
|
|
|
queued = task_on_rq_queued(p);
|
|
|
|
running = task_current(rq, p);
|
|
|
|
|
|
|
|
if (queued) {
|
|
|
|
/*
|
|
|
|
* Because __kthread_bind() calls this on blocked tasks without
|
|
|
|
* holding rq->lock.
|
|
|
|
*/
|
|
|
|
lockdep_assert_held(&rq->lock);
|
2017-02-21 13:47:02 +00:00
|
|
|
dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);
|
2015-05-15 15:43:36 +00:00
|
|
|
}
|
|
|
|
if (running)
|
|
|
|
put_prev_task(rq, p);
|
|
|
|
|
2015-05-15 15:43:35 +00:00
|
|
|
p->sched_class->set_cpus_allowed(p, new_mask);
|
2015-05-15 15:43:36 +00:00
|
|
|
|
|
|
|
if (queued)
|
2017-02-21 13:23:38 +00:00
|
|
|
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
|
2016-09-12 07:47:52 +00:00
|
|
|
if (running)
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, p);
|
2015-05-15 15:43:35 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 12:46:50 +00:00
|
|
|
/*
|
|
|
|
* Change a given task's CPU affinity. Migrate the thread to a
|
|
|
|
* proper CPU and schedule it away if the CPU it's executing on
|
|
|
|
* is removed from the allowed bitmask.
|
|
|
|
*
|
|
|
|
* NOTE: the caller must have a valid reference to the task, the
|
|
|
|
* task must not exit() & deallocate itself prematurely. The
|
|
|
|
* call is not atomic; no spinlocks may be held.
|
|
|
|
*/
|
2015-05-15 15:43:34 +00:00
|
|
|
static int __set_cpus_allowed_ptr(struct task_struct *p,
|
|
|
|
const struct cpumask *new_mask, bool check)
|
2015-06-11 12:46:50 +00:00
|
|
|
{
|
2016-03-10 11:54:08 +00:00
|
|
|
const struct cpumask *cpu_valid_mask = cpu_active_mask;
|
2015-06-11 12:46:50 +00:00
|
|
|
unsigned int dest_cpu;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
2015-06-11 12:46:50 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2017-02-22 07:52:55 +00:00
|
|
|
update_rq_clock(rq);
|
2015-06-11 12:46:50 +00:00
|
|
|
|
2016-03-10 11:54:08 +00:00
|
|
|
if (p->flags & PF_KTHREAD) {
|
|
|
|
/*
|
|
|
|
* Kernel threads are allowed on online && !active CPUs
|
|
|
|
*/
|
|
|
|
cpu_valid_mask = cpu_online_mask;
|
|
|
|
}
|
|
|
|
|
2015-05-15 15:43:34 +00:00
|
|
|
/*
|
|
|
|
* Must re-check here, to close a race against __kthread_bind(),
|
|
|
|
* sched_setaffinity() is not guaranteed to observe the flag.
|
|
|
|
*/
|
|
|
|
if (check && (p->flags & PF_NO_SETAFFINITY)) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (cpumask_equal(p->cpus_ptr, new_mask))
|
2015-06-11 12:46:50 +00:00
|
|
|
goto out;
|
|
|
|
|
2020-03-11 01:01:13 +00:00
|
|
|
/*
|
|
|
|
* Picking a ~random cpu helps in cases where we are changing affinity
|
|
|
|
* for groups of tasks (ie. cpuset), so that load balancing is not
|
|
|
|
* immediately required to distribute the tasks within their new mask.
|
|
|
|
*/
|
|
|
|
dest_cpu = cpumask_any_and_distribute(cpu_valid_mask, new_mask);
|
2019-09-16 06:53:28 +00:00
|
|
|
if (dest_cpu >= nr_cpu_ids) {
|
2015-06-11 12:46:50 +00:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
do_set_cpus_allowed(p, new_mask);
|
|
|
|
|
2016-03-10 11:54:08 +00:00
|
|
|
if (p->flags & PF_KTHREAD) {
|
|
|
|
/*
|
|
|
|
* For kernel threads that do indeed end up on online &&
|
2017-02-01 10:46:42 +00:00
|
|
|
* !active we want to ensure they are strict per-CPU threads.
|
2016-03-10 11:54:08 +00:00
|
|
|
*/
|
|
|
|
WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) &&
|
|
|
|
!cpumask_intersects(new_mask, cpu_active_mask) &&
|
|
|
|
p->nr_cpus_allowed != 1);
|
|
|
|
}
|
|
|
|
|
2015-06-11 12:46:50 +00:00
|
|
|
/* Can the task run on the task's current CPU? If so, we're done */
|
|
|
|
if (cpumask_test_cpu(task_cpu(p), new_mask))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (task_running(rq, p) || p->state == TASK_WAKING) {
|
|
|
|
struct migration_arg arg = { p, dest_cpu };
|
|
|
|
/* Need help from migration thread: drop lock and wait. */
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2015-06-11 12:46:50 +00:00
|
|
|
stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg);
|
|
|
|
return 0;
|
2015-06-11 12:46:54 +00:00
|
|
|
} else if (task_on_rq_queued(p)) {
|
|
|
|
/*
|
|
|
|
* OK, since we're going to drop the lock immediately
|
|
|
|
* afterwards anyway.
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
rq = move_queued_task(rq, &rf, p, dest_cpu);
|
2015-06-11 12:46:54 +00:00
|
|
|
}
|
2015-06-11 12:46:50 +00:00
|
|
|
out:
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2015-06-11 12:46:50 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2015-05-15 15:43:34 +00:00
|
|
|
|
|
|
|
int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
|
|
|
|
{
|
|
|
|
return __set_cpus_allowed_ptr(p, new_mask, false);
|
|
|
|
}
|
2015-06-11 12:46:50 +00:00
|
|
|
EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr);
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
|
2007-07-09 16:51:58 +00:00
|
|
|
{
|
2009-12-16 17:04:36 +00:00
|
|
|
#ifdef CONFIG_SCHED_DEBUG
|
|
|
|
/*
|
|
|
|
* We should never call set_task_cpu() on a blocked task,
|
|
|
|
* ttwu() will sort out the placement.
|
|
|
|
*/
|
2009-12-17 12:16:31 +00:00
|
|
|
WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
|
2014-10-08 18:33:48 +00:00
|
|
|
!p->on_rq);
|
2011-04-05 15:23:51 +00:00
|
|
|
|
2015-11-13 03:38:54 +00:00
|
|
|
/*
|
|
|
|
* Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING,
|
|
|
|
* because schedstat_wait_{start,end} rebase migrating task's wait_start
|
|
|
|
* time relying on p->on_rq.
|
|
|
|
*/
|
|
|
|
WARN_ON_ONCE(p->state == TASK_RUNNING &&
|
|
|
|
p->sched_class == &fair_sched_class &&
|
|
|
|
(p->on_rq && !task_on_rq_migrating(p)));
|
|
|
|
|
2011-04-05 15:23:51 +00:00
|
|
|
#ifdef CONFIG_LOCKDEP
|
2011-06-03 15:37:07 +00:00
|
|
|
/*
|
|
|
|
* The caller should hold either p->pi_lock or rq->lock, when changing
|
|
|
|
* a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks.
|
|
|
|
*
|
|
|
|
* sched_move_task() holds both and thus holding either pins the cgroup,
|
2012-06-22 11:36:05 +00:00
|
|
|
* see task_group().
|
2011-06-03 15:37:07 +00:00
|
|
|
*
|
|
|
|
* Furthermore, all task_rq users should acquire both locks, see
|
|
|
|
* task_rq_lock().
|
|
|
|
*/
|
2011-04-05 15:23:51 +00:00
|
|
|
WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) ||
|
|
|
|
lockdep_is_held(&task_rq(p)->lock)));
|
|
|
|
#endif
|
2017-09-07 15:03:52 +00:00
|
|
|
/*
|
|
|
|
* Clearly, migrating tasks to offline CPUs is a fairly daft thing.
|
|
|
|
*/
|
|
|
|
WARN_ON_ONCE(!cpu_online(new_cpu));
|
2009-12-16 17:04:36 +00:00
|
|
|
#endif
|
|
|
|
|
2009-05-05 08:49:59 +00:00
|
|
|
trace_sched_migrate_task(p, new_cpu);
|
2008-12-10 07:08:22 +00:00
|
|
|
|
2009-12-22 14:43:19 +00:00
|
|
|
if (task_cpu(p) != new_cpu) {
|
2012-10-04 11:18:30 +00:00
|
|
|
if (p->sched_class->migrate_task_rq)
|
sched/numa: Pass destination CPU as a parameter to migrate_task_rq
This additional parameter (new_cpu) is used later for identifying if
task migration is across nodes.
No functional change.
Specjbb2005 results (8 warehouses)
Higher bops are better
2 Socket - 2 Node Haswell - X86
JVMS Prev Current %Change
4 203353 200668 -1.32036
1 328205 321791 -1.95427
2 Socket - 4 Node Power8 - PowerNV
JVMS Prev Current %Change
1 214384 204848 -4.44809
2 Socket - 2 Node Power9 - PowerNV
JVMS Prev Current %Change
4 188553 188098 -0.241311
1 196273 200351 2.07772
4 Socket - 4 Node Power7 - PowerVM
JVMS Prev Current %Change
8 57581.2 58145.9 0.980702
1 103468 103798 0.318939
Brings out the variance between different specjbb2005 runs.
Some events stats before and after applying the patch.
perf stats 8th warehouse Multi JVM 2 Socket - 2 Node Haswell - X86
Event Before After
cs 13,941,377 13,912,183
migrations 1,157,323 1,155,931
faults 382,175 367,139
cache-misses 54,993,823,500 54,240,196,814
sched:sched_move_numa 2,005 1,571
sched:sched_stick_numa 14 9
sched:sched_swap_numa 529 463
migrate:mm_migrate_pages 1,573 703
vmstat 8th warehouse Multi JVM 2 Socket - 2 Node Haswell - X86
Event Before After
numa_hint_faults 67099 50155
numa_hint_faults_local 58456 45264
numa_hit 240416 239652
numa_huge_pte_updates 18 36
numa_interleave 65 68
numa_local 240339 239576
numa_other 77 76
numa_pages_migrated 1574 680
numa_pte_updates 77182 71146
perf stats 8th warehouse Single JVM 2 Socket - 2 Node Haswell - X86
Event Before After
cs 3,176,453 3,156,720
migrations 30,238 30,354
faults 87,869 97,261
cache-misses 12,544,479,391 12,400,026,826
sched:sched_move_numa 23 4
sched:sched_stick_numa 0 0
sched:sched_swap_numa 6 1
migrate:mm_migrate_pages 10 20
vmstat 8th warehouse Single JVM 2 Socket - 2 Node Haswell - X86
Event Before After
numa_hint_faults 236 272
numa_hint_faults_local 201 186
numa_hit 72293 71362
numa_huge_pte_updates 0 0
numa_interleave 26 23
numa_local 72233 71299
numa_other 60 63
numa_pages_migrated 8 2
numa_pte_updates 0 0
perf stats 8th warehouse Multi JVM 2 Socket - 2 Node Power9 - PowerNV
Event Before After
cs 8,478,820 8,606,824
migrations 171,323 155,352
faults 307,499 301,409
cache-misses 240,353,599 157,759,224
sched:sched_move_numa 214 168
sched:sched_stick_numa 0 0
sched:sched_swap_numa 4 3
migrate:mm_migrate_pages 89 125
vmstat 8th warehouse Multi JVM 2 Socket - 2 Node Power9 - PowerNV
Event Before After
numa_hint_faults 5301 4650
numa_hint_faults_local 4745 3946
numa_hit 92943 90489
numa_huge_pte_updates 0 0
numa_interleave 899 892
numa_local 92345 90034
numa_other 598 455
numa_pages_migrated 88 124
numa_pte_updates 5505 4818
perf stats 8th warehouse Single JVM 2 Socket - 2 Node Power9 - PowerNV
Event Before After
cs 2,066,172 2,113,167
migrations 11,076 10,533
faults 149,544 142,727
cache-misses 10,398,067 5,594,192
sched:sched_move_numa 43 10
sched:sched_stick_numa 0 0
sched:sched_swap_numa 0 0
migrate:mm_migrate_pages 6 6
vmstat 8th warehouse Single JVM 2 Socket - 2 Node Power9 - PowerNV
Event Before After
numa_hint_faults 3552 744
numa_hint_faults_local 3347 584
numa_hit 25611 25551
numa_huge_pte_updates 0 0
numa_interleave 213 263
numa_local 25583 25302
numa_other 28 249
numa_pages_migrated 6 6
numa_pte_updates 3535 744
perf stats 8th warehouse Multi JVM 4 Socket - 4 Node Power7 - PowerVM
Event Before After
cs 99,358,136 101,227,352
migrations 4,041,607 4,151,829
faults 749,653 745,233
cache-misses 225,562,543,251 224,669,561,766
sched:sched_move_numa 771 617
sched:sched_stick_numa 14 2
sched:sched_swap_numa 204 187
migrate:mm_migrate_pages 1,180 316
vmstat 8th warehouse Multi JVM 4 Socket - 4 Node Power7 - PowerVM
Event Before After
numa_hint_faults 27409 24195
numa_hint_faults_local 20677 21639
numa_hit 239988 238331
numa_huge_pte_updates 0 0
numa_interleave 0 0
numa_local 239983 238331
numa_other 5 0
numa_pages_migrated 1016 204
numa_pte_updates 27916 24561
perf stats 8th warehouse Single JVM 4 Socket - 4 Node Power7 - PowerVM
Event Before After
cs 60,899,307 62,738,978
migrations 544,668 562,702
faults 270,834 228,465
cache-misses 74,543,455,635 75,778,067,952
sched:sched_move_numa 735 648
sched:sched_stick_numa 25 13
sched:sched_swap_numa 174 137
migrate:mm_migrate_pages 816 733
vmstat 8th warehouse Single JVM 4 Socket - 4 Node Power7 - PowerVM
Event Before After
numa_hint_faults 11059 10281
numa_hint_faults_local 4733 3242
numa_hit 41384 36338
numa_huge_pte_updates 0 0
numa_interleave 0 0
numa_local 41383 36338
numa_other 1 0
numa_pages_migrated 815 706
numa_pte_updates 11323 10176
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Jirka Hladky <jhladky@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rik van Riel <riel@surriel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1537552141-27815-3-git-send-email-srikar@linux.vnet.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-09-21 17:48:57 +00:00
|
|
|
p->sched_class->migrate_task_rq(p, new_cpu);
|
2009-12-22 14:43:19 +00:00
|
|
|
p->se.nr_migrations++;
|
rseq: Introduce restartable sequences system call
Expose a new system call allowing each thread to register one userspace
memory area to be used as an ABI between kernel and user-space for two
purposes: user-space restartable sequences and quick access to read the
current CPU number value from user-space.
* Restartable sequences (per-cpu atomics)
Restartables sequences allow user-space to perform update operations on
per-cpu data without requiring heavy-weight atomic operations.
The restartable critical sections (percpu atomics) work has been started
by Paul Turner and Andrew Hunter. It lets the kernel handle restart of
critical sections. [1] [2] The re-implementation proposed here brings a
few simplifications to the ABI which facilitates porting to other
architectures and speeds up the user-space fast path.
Here are benchmarks of various rseq use-cases.
Test hardware:
arm32: ARMv7 Processor rev 4 (v7l) "Cubietruck", 2-core
x86-64: Intel E5-2630 v3@2.40GHz, 16-core, hyperthreading
The following benchmarks were all performed on a single thread.
* Per-CPU statistic counter increment
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 344.0 31.4 11.0
x86-64: 15.3 2.0 7.7
* LTTng-UST: write event 32-bit header, 32-bit payload into tracer
per-cpu buffer
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 2502.0 2250.0 1.1
x86-64: 117.4 98.0 1.2
* liburcu percpu: lock-unlock pair, dereference, read/compare word
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 751.0 128.5 5.8
x86-64: 53.4 28.6 1.9
* jemalloc memory allocator adapted to use rseq
Using rseq with per-cpu memory pools in jemalloc at Facebook (based on
rseq 2016 implementation):
The production workload response-time has 1-2% gain avg. latency, and
the P99 overall latency drops by 2-3%.
* Reading the current CPU number
Speeding up reading the current CPU number on which the caller thread is
running is done by keeping the current CPU number up do date within the
cpu_id field of the memory area registered by the thread. This is done
by making scheduler preemption set the TIF_NOTIFY_RESUME flag on the
current thread. Upon return to user-space, a notify-resume handler
updates the current CPU value within the registered user-space memory
area. User-space can then read the current CPU number directly from
memory.
Keeping the current cpu id in a memory area shared between kernel and
user-space is an improvement over current mechanisms available to read
the current CPU number, which has the following benefits over
alternative approaches:
- 35x speedup on ARM vs system call through glibc
- 20x speedup on x86 compared to calling glibc, which calls vdso
executing a "lsl" instruction,
- 14x speedup on x86 compared to inlined "lsl" instruction,
- Unlike vdso approaches, this cpu_id value can be read from an inline
assembly, which makes it a useful building block for restartable
sequences.
- The approach of reading the cpu id through memory mapping shared
between kernel and user-space is portable (e.g. ARM), which is not the
case for the lsl-based x86 vdso.
On x86, yet another possible approach would be to use the gs segment
selector to point to user-space per-cpu data. This approach performs
similarly to the cpu id cache, but it has two disadvantages: it is
not portable, and it is incompatible with existing applications already
using the gs segment selector for other purposes.
Benchmarking various approaches for reading the current CPU number:
ARMv7 Processor rev 4 (v7l)
Machine model: Cubietruck
- Baseline (empty loop): 8.4 ns
- Read CPU from rseq cpu_id: 16.7 ns
- Read CPU from rseq cpu_id (lazy register): 19.8 ns
- glibc 2.19-0ubuntu6.6 getcpu: 301.8 ns
- getcpu system call: 234.9 ns
x86-64 Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz:
- Baseline (empty loop): 0.8 ns
- Read CPU from rseq cpu_id: 0.8 ns
- Read CPU from rseq cpu_id (lazy register): 0.8 ns
- Read using gs segment selector: 0.8 ns
- "lsl" inline assembly: 13.0 ns
- glibc 2.19-0ubuntu6 getcpu: 16.6 ns
- getcpu system call: 53.9 ns
- Speed (benchmark taken on v8 of patchset)
Running 10 runs of hackbench -l 100000 seems to indicate, contrary to
expectations, that enabling CONFIG_RSEQ slightly accelerates the
scheduler:
Configuration: 2 sockets * 8-core Intel(R) Xeon(R) CPU E5-2630 v3 @
2.40GHz (directly on hardware, hyperthreading disabled in BIOS, energy
saving disabled in BIOS, turboboost disabled in BIOS, cpuidle.off=1
kernel parameter), with a Linux v4.6 defconfig+localyesconfig,
restartable sequences series applied.
* CONFIG_RSEQ=n
avg.: 41.37 s
std.dev.: 0.36 s
* CONFIG_RSEQ=y
avg.: 40.46 s
std.dev.: 0.33 s
- Size
On x86-64, between CONFIG_RSEQ=n/y, the text size increase of vmlinux is
567 bytes, and the data size increase of vmlinux is 5696 bytes.
[1] https://lwn.net/Articles/650333/
[2] http://www.linuxplumbersconf.org/2013/ocw/system/presentations/1695/original/LPC%20-%20PerCpu%20Atomics.pdf
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Watson <davejwatson@fb.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: "H . Peter Anvin" <hpa@zytor.com>
Cc: Chris Lameter <cl@linux.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Andrew Hunter <ahh@google.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: "Paul E . McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ben Maurer <bmaurer@fb.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-api@vger.kernel.org
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20151027235635.16059.11630.stgit@pjt-glaptop.roam.corp.google.com
Link: http://lkml.kernel.org/r/20150624222609.6116.86035.stgit@kitami.mtv.corp.google.com
Link: https://lkml.kernel.org/r/20180602124408.8430-3-mathieu.desnoyers@efficios.com
2018-06-02 12:43:54 +00:00
|
|
|
rseq_migrate(p);
|
2015-04-17 18:05:30 +00:00
|
|
|
perf_event_task_migrate(p);
|
2009-12-22 14:43:19 +00:00
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
|
|
|
|
__set_task_cpu(p, new_cpu);
|
2007-07-09 16:51:58 +00:00
|
|
|
}
|
|
|
|
|
2018-06-20 17:02:50 +00:00
|
|
|
#ifdef CONFIG_NUMA_BALANCING
|
2013-10-07 10:29:16 +00:00
|
|
|
static void __migrate_swap_task(struct task_struct *p, int cpu)
|
|
|
|
{
|
2014-08-20 09:47:32 +00:00
|
|
|
if (task_on_rq_queued(p)) {
|
2013-10-07 10:29:16 +00:00
|
|
|
struct rq *src_rq, *dst_rq;
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags srf, drf;
|
2013-10-07 10:29:16 +00:00
|
|
|
|
|
|
|
src_rq = task_rq(p);
|
|
|
|
dst_rq = cpu_rq(cpu);
|
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_pin_lock(src_rq, &srf);
|
|
|
|
rq_pin_lock(dst_rq, &drf);
|
|
|
|
|
2013-10-07 10:29:16 +00:00
|
|
|
deactivate_task(src_rq, p, 0);
|
|
|
|
set_task_cpu(p, cpu);
|
|
|
|
activate_task(dst_rq, p, 0);
|
|
|
|
check_preempt_curr(dst_rq, p, 0);
|
2016-10-04 14:04:35 +00:00
|
|
|
|
|
|
|
rq_unpin_lock(dst_rq, &drf);
|
|
|
|
rq_unpin_lock(src_rq, &srf);
|
|
|
|
|
2013-10-07 10:29:16 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Task isn't running anymore; make it appear like we migrated
|
|
|
|
* it before it went to sleep. This means on wakeup we make the
|
2017-02-01 10:46:42 +00:00
|
|
|
* previous CPU our target instead of where it really is.
|
2013-10-07 10:29:16 +00:00
|
|
|
*/
|
|
|
|
p->wake_cpu = cpu;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct migration_swap_arg {
|
|
|
|
struct task_struct *src_task, *dst_task;
|
|
|
|
int src_cpu, dst_cpu;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int migrate_swap_stop(void *data)
|
|
|
|
{
|
|
|
|
struct migration_swap_arg *arg = data;
|
|
|
|
struct rq *src_rq, *dst_rq;
|
|
|
|
int ret = -EAGAIN;
|
|
|
|
|
2015-10-09 16:36:29 +00:00
|
|
|
if (!cpu_active(arg->src_cpu) || !cpu_active(arg->dst_cpu))
|
|
|
|
return -EAGAIN;
|
|
|
|
|
2013-10-07 10:29:16 +00:00
|
|
|
src_rq = cpu_rq(arg->src_cpu);
|
|
|
|
dst_rq = cpu_rq(arg->dst_cpu);
|
|
|
|
|
sched: Fix race in migrate_swap_stop()
There is a subtle race in migrate_swap, when task P, on CPU A, decides to swap
places with task T, on CPU B.
Task P:
- call migrate_swap
Task T:
- go to sleep, removing itself from the runqueue
Task P:
- double lock the runqueues on CPU A & B
Task T:
- get woken up, place itself on the runqueue of CPU C
Task P:
- see that task T is on a runqueue, and pretend to remove it
from the runqueue on CPU B
Now CPUs B & C both have corrupted scheduler data structures.
This patch fixes it, by holding the pi_lock for both of the tasks
involved in the migrate swap. This prevents task T from waking up,
and placing itself onto another runqueue, until after migrate_swap
has released all locks.
This means that, when migrate_swap checks, task T will be either
on the runqueue where it was originally seen, or not on any
runqueue at all. Migrate_swap deals correctly with of those cases.
Tested-by: Joe Mario <jmario@redhat.com>
Acked-by: Mel Gorman <mgorman@suse.de>
Reviewed-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Cc: hannes@cmpxchg.org
Cc: aarcange@redhat.com
Cc: srikar@linux.vnet.ibm.com
Cc: tglx@linutronix.de
Cc: hpa@zytor.com
Link: http://lkml.kernel.org/r/20131010181722.GO13848@laptop.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-10-10 18:17:22 +00:00
|
|
|
double_raw_lock(&arg->src_task->pi_lock,
|
|
|
|
&arg->dst_task->pi_lock);
|
2013-10-07 10:29:16 +00:00
|
|
|
double_rq_lock(src_rq, dst_rq);
|
2015-10-09 16:36:29 +00:00
|
|
|
|
2013-10-07 10:29:16 +00:00
|
|
|
if (task_cpu(arg->dst_task) != arg->dst_cpu)
|
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
if (task_cpu(arg->src_task) != arg->src_cpu)
|
|
|
|
goto unlock;
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(arg->dst_cpu, arg->src_task->cpus_ptr))
|
2013-10-07 10:29:16 +00:00
|
|
|
goto unlock;
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(arg->src_cpu, arg->dst_task->cpus_ptr))
|
2013-10-07 10:29:16 +00:00
|
|
|
goto unlock;
|
|
|
|
|
|
|
|
__migrate_swap_task(arg->src_task, arg->dst_cpu);
|
|
|
|
__migrate_swap_task(arg->dst_task, arg->src_cpu);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
unlock:
|
|
|
|
double_rq_unlock(src_rq, dst_rq);
|
sched: Fix race in migrate_swap_stop()
There is a subtle race in migrate_swap, when task P, on CPU A, decides to swap
places with task T, on CPU B.
Task P:
- call migrate_swap
Task T:
- go to sleep, removing itself from the runqueue
Task P:
- double lock the runqueues on CPU A & B
Task T:
- get woken up, place itself on the runqueue of CPU C
Task P:
- see that task T is on a runqueue, and pretend to remove it
from the runqueue on CPU B
Now CPUs B & C both have corrupted scheduler data structures.
This patch fixes it, by holding the pi_lock for both of the tasks
involved in the migrate swap. This prevents task T from waking up,
and placing itself onto another runqueue, until after migrate_swap
has released all locks.
This means that, when migrate_swap checks, task T will be either
on the runqueue where it was originally seen, or not on any
runqueue at all. Migrate_swap deals correctly with of those cases.
Tested-by: Joe Mario <jmario@redhat.com>
Acked-by: Mel Gorman <mgorman@suse.de>
Reviewed-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Cc: hannes@cmpxchg.org
Cc: aarcange@redhat.com
Cc: srikar@linux.vnet.ibm.com
Cc: tglx@linutronix.de
Cc: hpa@zytor.com
Link: http://lkml.kernel.org/r/20131010181722.GO13848@laptop.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-10-10 18:17:22 +00:00
|
|
|
raw_spin_unlock(&arg->dst_task->pi_lock);
|
|
|
|
raw_spin_unlock(&arg->src_task->pi_lock);
|
2013-10-07 10:29:16 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cross migrate two tasks
|
|
|
|
*/
|
2018-06-20 17:02:50 +00:00
|
|
|
int migrate_swap(struct task_struct *cur, struct task_struct *p,
|
|
|
|
int target_cpu, int curr_cpu)
|
2013-10-07 10:29:16 +00:00
|
|
|
{
|
|
|
|
struct migration_swap_arg arg;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
arg = (struct migration_swap_arg){
|
|
|
|
.src_task = cur,
|
2018-06-20 17:02:50 +00:00
|
|
|
.src_cpu = curr_cpu,
|
2013-10-07 10:29:16 +00:00
|
|
|
.dst_task = p,
|
2018-06-20 17:02:50 +00:00
|
|
|
.dst_cpu = target_cpu,
|
2013-10-07 10:29:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if (arg.src_cpu == arg.dst_cpu)
|
|
|
|
goto out;
|
|
|
|
|
2013-10-11 12:38:20 +00:00
|
|
|
/*
|
|
|
|
* These three tests are all lockless; this is OK since all of them
|
|
|
|
* will be re-checked with proper locks held further down the line.
|
|
|
|
*/
|
2013-10-07 10:29:16 +00:00
|
|
|
if (!cpu_active(arg.src_cpu) || !cpu_active(arg.dst_cpu))
|
|
|
|
goto out;
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(arg.dst_cpu, arg.src_task->cpus_ptr))
|
2013-10-07 10:29:16 +00:00
|
|
|
goto out;
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(arg.src_cpu, arg.dst_task->cpus_ptr))
|
2013-10-07 10:29:16 +00:00
|
|
|
goto out;
|
|
|
|
|
2014-01-21 23:51:03 +00:00
|
|
|
trace_sched_swap_numa(cur, arg.src_cpu, p, arg.dst_cpu);
|
2013-10-07 10:29:16 +00:00
|
|
|
ret = stop_two_cpus(arg.dst_cpu, arg.src_cpu, migrate_swap_stop, &arg);
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
2018-06-20 17:02:50 +00:00
|
|
|
#endif /* CONFIG_NUMA_BALANCING */
|
2013-10-07 10:29:16 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* wait_task_inactive - wait for a thread to unschedule.
|
|
|
|
*
|
2008-07-26 02:45:58 +00:00
|
|
|
* If @match_state is nonzero, it's the @p->state value just checked and
|
|
|
|
* not expected to change. If it changes, i.e. @p might have woken up,
|
|
|
|
* then return zero. When we succeed in waiting for @p to be off its CPU,
|
|
|
|
* we return a positive number (its total switch count). If a second call
|
|
|
|
* a short while later returns the same number, the caller can be sure that
|
|
|
|
* @p has remained unscheduled the whole time.
|
|
|
|
*
|
2005-04-16 22:20:36 +00:00
|
|
|
* The caller must ensure that the task *will* unschedule sometime soon,
|
|
|
|
* else this function might spin for a *long* time. This function can't
|
|
|
|
* be called with interrupts off, or it may introduce deadlock with
|
|
|
|
* smp_call_function() if an IPI is sent by the same process we are
|
|
|
|
* waiting to become inactive.
|
|
|
|
*/
|
2008-07-26 02:45:58 +00:00
|
|
|
unsigned long wait_task_inactive(struct task_struct *p, long match_state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2014-08-20 09:47:32 +00:00
|
|
|
int running, queued;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2008-07-26 02:45:58 +00:00
|
|
|
unsigned long ncsw;
|
2006-07-03 07:25:42 +00:00
|
|
|
struct rq *rq;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
for (;;) {
|
|
|
|
/*
|
|
|
|
* We do the initial early heuristics without holding
|
|
|
|
* any task-queue locks at all. We'll only try to get
|
|
|
|
* the runqueue lock when things look like they will
|
|
|
|
* work out!
|
|
|
|
*/
|
|
|
|
rq = task_rq(p);
|
Fix possible runqueue lock starvation in wait_task_inactive()
Miklos Szeredi reported very long pauses (several seconds, sometimes
more) on his T60 (with a Core2Duo) which he managed to track down to
wait_task_inactive()'s open-coded busy-loop.
He observed that an interrupt on one core tries to acquire the
runqueue-lock but does not succeed in doing so for a very long time -
while wait_task_inactive() on the other core loops waiting for the first
core to deschedule a task (which it wont do while spinning in an
interrupt handler).
This rewrites wait_task_inactive() to do all its waiting optimistically
without any locks taken at all, and then just double-check the end
result with the proper runqueue lock held over just a very short
section. If there were races in the optimistic wait, of a preemption
event scheduled the process away, we simply re-synchronize, and start
over.
So the code now looks like this:
repeat:
/* Unlocked, optimistic looping! */
rq = task_rq(p);
while (task_running(rq, p))
cpu_relax();
/* Get the *real* values */
rq = task_rq_lock(p, &flags);
running = task_running(rq, p);
array = p->array;
task_rq_unlock(rq, &flags);
/* Check them.. */
if (unlikely(running)) {
cpu_relax();
goto repeat;
}
/* Preempted away? Yield if so.. */
if (unlikely(array)) {
yield();
goto repeat;
}
Basically, that first "while()" loop is done entirely without any
locking at all (and doesn't check for the case where the target process
might have been preempted away), and so it's possibly "incorrect", but
we don't really care. Both the runqueue used, and the "task_running()"
check might be the wrong tests, but they won't oops - they just mean
that we could possibly get the wrong results due to lack of locking and
exit the loop early in the case of a race condition.
So once we've exited the loop, we then get the proper (and careful) rq
lock, and check the running/runnable state _safely_. And if it turns
out that our quick-and-dirty and unsafe loop was wrong after all, we
just go back and try it all again.
(The patch also adds a lot of comments, which is the actual bulk of it
all, to make it more obvious why we can do these things without holding
the locks).
Thanks to Miklos for all the testing and tracking it down.
Tested-by: Miklos Szeredi <miklos@szeredi.hu>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-18 16:34:40 +00:00
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
/*
|
|
|
|
* If the task is actively running on another CPU
|
|
|
|
* still, just relax and busy-wait without holding
|
|
|
|
* any locks.
|
|
|
|
*
|
|
|
|
* NOTE! Since we don't hold any locks, it's not
|
|
|
|
* even sure that "rq" stays as the right runqueue!
|
|
|
|
* But we don't care, since "task_running()" will
|
|
|
|
* return false if the runqueue has changed and p
|
|
|
|
* is actually now running somewhere else!
|
|
|
|
*/
|
2008-07-26 02:45:58 +00:00
|
|
|
while (task_running(rq, p)) {
|
|
|
|
if (match_state && unlikely(p->state != match_state))
|
|
|
|
return 0;
|
2007-10-15 15:00:14 +00:00
|
|
|
cpu_relax();
|
2008-07-26 02:45:58 +00:00
|
|
|
}
|
Fix possible runqueue lock starvation in wait_task_inactive()
Miklos Szeredi reported very long pauses (several seconds, sometimes
more) on his T60 (with a Core2Duo) which he managed to track down to
wait_task_inactive()'s open-coded busy-loop.
He observed that an interrupt on one core tries to acquire the
runqueue-lock but does not succeed in doing so for a very long time -
while wait_task_inactive() on the other core loops waiting for the first
core to deschedule a task (which it wont do while spinning in an
interrupt handler).
This rewrites wait_task_inactive() to do all its waiting optimistically
without any locks taken at all, and then just double-check the end
result with the proper runqueue lock held over just a very short
section. If there were races in the optimistic wait, of a preemption
event scheduled the process away, we simply re-synchronize, and start
over.
So the code now looks like this:
repeat:
/* Unlocked, optimistic looping! */
rq = task_rq(p);
while (task_running(rq, p))
cpu_relax();
/* Get the *real* values */
rq = task_rq_lock(p, &flags);
running = task_running(rq, p);
array = p->array;
task_rq_unlock(rq, &flags);
/* Check them.. */
if (unlikely(running)) {
cpu_relax();
goto repeat;
}
/* Preempted away? Yield if so.. */
if (unlikely(array)) {
yield();
goto repeat;
}
Basically, that first "while()" loop is done entirely without any
locking at all (and doesn't check for the case where the target process
might have been preempted away), and so it's possibly "incorrect", but
we don't really care. Both the runqueue used, and the "task_running()"
check might be the wrong tests, but they won't oops - they just mean
that we could possibly get the wrong results due to lack of locking and
exit the loop early in the case of a race condition.
So once we've exited the loop, we then get the proper (and careful) rq
lock, and check the running/runnable state _safely_. And if it turns
out that our quick-and-dirty and unsafe loop was wrong after all, we
just go back and try it all again.
(The patch also adds a lot of comments, which is the actual bulk of it
all, to make it more obvious why we can do these things without holding
the locks).
Thanks to Miklos for all the testing and tracking it down.
Tested-by: Miklos Szeredi <miklos@szeredi.hu>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-18 16:34:40 +00:00
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
/*
|
|
|
|
* Ok, time to look more closely! We need the rq
|
|
|
|
* lock now, to be *sure*. If we're wrong, we'll
|
|
|
|
* just go back and repeat.
|
|
|
|
*/
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2010-05-04 18:36:56 +00:00
|
|
|
trace_sched_wait_task(p);
|
2007-10-15 15:00:14 +00:00
|
|
|
running = task_running(rq, p);
|
2014-08-20 09:47:32 +00:00
|
|
|
queued = task_on_rq_queued(p);
|
2008-07-26 02:45:58 +00:00
|
|
|
ncsw = 0;
|
2008-08-20 23:54:44 +00:00
|
|
|
if (!match_state || p->state == match_state)
|
2008-08-20 23:54:44 +00:00
|
|
|
ncsw = p->nvcsw | LONG_MIN; /* sets MSB */
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
Fix possible runqueue lock starvation in wait_task_inactive()
Miklos Szeredi reported very long pauses (several seconds, sometimes
more) on his T60 (with a Core2Duo) which he managed to track down to
wait_task_inactive()'s open-coded busy-loop.
He observed that an interrupt on one core tries to acquire the
runqueue-lock but does not succeed in doing so for a very long time -
while wait_task_inactive() on the other core loops waiting for the first
core to deschedule a task (which it wont do while spinning in an
interrupt handler).
This rewrites wait_task_inactive() to do all its waiting optimistically
without any locks taken at all, and then just double-check the end
result with the proper runqueue lock held over just a very short
section. If there were races in the optimistic wait, of a preemption
event scheduled the process away, we simply re-synchronize, and start
over.
So the code now looks like this:
repeat:
/* Unlocked, optimistic looping! */
rq = task_rq(p);
while (task_running(rq, p))
cpu_relax();
/* Get the *real* values */
rq = task_rq_lock(p, &flags);
running = task_running(rq, p);
array = p->array;
task_rq_unlock(rq, &flags);
/* Check them.. */
if (unlikely(running)) {
cpu_relax();
goto repeat;
}
/* Preempted away? Yield if so.. */
if (unlikely(array)) {
yield();
goto repeat;
}
Basically, that first "while()" loop is done entirely without any
locking at all (and doesn't check for the case where the target process
might have been preempted away), and so it's possibly "incorrect", but
we don't really care. Both the runqueue used, and the "task_running()"
check might be the wrong tests, but they won't oops - they just mean
that we could possibly get the wrong results due to lack of locking and
exit the loop early in the case of a race condition.
So once we've exited the loop, we then get the proper (and careful) rq
lock, and check the running/runnable state _safely_. And if it turns
out that our quick-and-dirty and unsafe loop was wrong after all, we
just go back and try it all again.
(The patch also adds a lot of comments, which is the actual bulk of it
all, to make it more obvious why we can do these things without holding
the locks).
Thanks to Miklos for all the testing and tracking it down.
Tested-by: Miklos Szeredi <miklos@szeredi.hu>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-18 16:34:40 +00:00
|
|
|
|
2008-07-26 02:45:58 +00:00
|
|
|
/*
|
|
|
|
* If it changed from the expected state, bail out now.
|
|
|
|
*/
|
|
|
|
if (unlikely(!ncsw))
|
|
|
|
break;
|
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
/*
|
|
|
|
* Was it really running after all now that we
|
|
|
|
* checked with the proper locks actually held?
|
|
|
|
*
|
|
|
|
* Oops. Go back and try again..
|
|
|
|
*/
|
|
|
|
if (unlikely(running)) {
|
|
|
|
cpu_relax();
|
|
|
|
continue;
|
|
|
|
}
|
Fix possible runqueue lock starvation in wait_task_inactive()
Miklos Szeredi reported very long pauses (several seconds, sometimes
more) on his T60 (with a Core2Duo) which he managed to track down to
wait_task_inactive()'s open-coded busy-loop.
He observed that an interrupt on one core tries to acquire the
runqueue-lock but does not succeed in doing so for a very long time -
while wait_task_inactive() on the other core loops waiting for the first
core to deschedule a task (which it wont do while spinning in an
interrupt handler).
This rewrites wait_task_inactive() to do all its waiting optimistically
without any locks taken at all, and then just double-check the end
result with the proper runqueue lock held over just a very short
section. If there were races in the optimistic wait, of a preemption
event scheduled the process away, we simply re-synchronize, and start
over.
So the code now looks like this:
repeat:
/* Unlocked, optimistic looping! */
rq = task_rq(p);
while (task_running(rq, p))
cpu_relax();
/* Get the *real* values */
rq = task_rq_lock(p, &flags);
running = task_running(rq, p);
array = p->array;
task_rq_unlock(rq, &flags);
/* Check them.. */
if (unlikely(running)) {
cpu_relax();
goto repeat;
}
/* Preempted away? Yield if so.. */
if (unlikely(array)) {
yield();
goto repeat;
}
Basically, that first "while()" loop is done entirely without any
locking at all (and doesn't check for the case where the target process
might have been preempted away), and so it's possibly "incorrect", but
we don't really care. Both the runqueue used, and the "task_running()"
check might be the wrong tests, but they won't oops - they just mean
that we could possibly get the wrong results due to lack of locking and
exit the loop early in the case of a race condition.
So once we've exited the loop, we then get the proper (and careful) rq
lock, and check the running/runnable state _safely_. And if it turns
out that our quick-and-dirty and unsafe loop was wrong after all, we
just go back and try it all again.
(The patch also adds a lot of comments, which is the actual bulk of it
all, to make it more obvious why we can do these things without holding
the locks).
Thanks to Miklos for all the testing and tracking it down.
Tested-by: Miklos Szeredi <miklos@szeredi.hu>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-18 16:34:40 +00:00
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
/*
|
|
|
|
* It's not enough that it's not actively running,
|
|
|
|
* it must be off the runqueue _entirely_, and not
|
|
|
|
* preempted!
|
|
|
|
*
|
2009-03-16 19:58:09 +00:00
|
|
|
* So if it was still runnable (but just not actively
|
2007-10-15 15:00:14 +00:00
|
|
|
* running right now), it's preempted, and we should
|
|
|
|
* yield - it could be a while.
|
|
|
|
*/
|
2014-08-20 09:47:32 +00:00
|
|
|
if (unlikely(queued)) {
|
2016-12-25 11:30:41 +00:00
|
|
|
ktime_t to = NSEC_PER_SEC / HZ;
|
2011-02-23 23:52:21 +00:00
|
|
|
|
|
|
|
set_current_state(TASK_UNINTERRUPTIBLE);
|
|
|
|
schedule_hrtimeout(&to, HRTIMER_MODE_REL);
|
2007-10-15 15:00:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
Fix possible runqueue lock starvation in wait_task_inactive()
Miklos Szeredi reported very long pauses (several seconds, sometimes
more) on his T60 (with a Core2Duo) which he managed to track down to
wait_task_inactive()'s open-coded busy-loop.
He observed that an interrupt on one core tries to acquire the
runqueue-lock but does not succeed in doing so for a very long time -
while wait_task_inactive() on the other core loops waiting for the first
core to deschedule a task (which it wont do while spinning in an
interrupt handler).
This rewrites wait_task_inactive() to do all its waiting optimistically
without any locks taken at all, and then just double-check the end
result with the proper runqueue lock held over just a very short
section. If there were races in the optimistic wait, of a preemption
event scheduled the process away, we simply re-synchronize, and start
over.
So the code now looks like this:
repeat:
/* Unlocked, optimistic looping! */
rq = task_rq(p);
while (task_running(rq, p))
cpu_relax();
/* Get the *real* values */
rq = task_rq_lock(p, &flags);
running = task_running(rq, p);
array = p->array;
task_rq_unlock(rq, &flags);
/* Check them.. */
if (unlikely(running)) {
cpu_relax();
goto repeat;
}
/* Preempted away? Yield if so.. */
if (unlikely(array)) {
yield();
goto repeat;
}
Basically, that first "while()" loop is done entirely without any
locking at all (and doesn't check for the case where the target process
might have been preempted away), and so it's possibly "incorrect", but
we don't really care. Both the runqueue used, and the "task_running()"
check might be the wrong tests, but they won't oops - they just mean
that we could possibly get the wrong results due to lack of locking and
exit the loop early in the case of a race condition.
So once we've exited the loop, we then get the proper (and careful) rq
lock, and check the running/runnable state _safely_. And if it turns
out that our quick-and-dirty and unsafe loop was wrong after all, we
just go back and try it all again.
(The patch also adds a lot of comments, which is the actual bulk of it
all, to make it more obvious why we can do these things without holding
the locks).
Thanks to Miklos for all the testing and tracking it down.
Tested-by: Miklos Szeredi <miklos@szeredi.hu>
Acked-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-06-18 16:34:40 +00:00
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
/*
|
|
|
|
* Ahh, all good. It wasn't running, and it wasn't
|
|
|
|
* runnable, which means that it will never become
|
|
|
|
* running in the future either. We're all done!
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
2008-07-26 02:45:58 +00:00
|
|
|
|
|
|
|
return ncsw;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/***
|
|
|
|
* kick_process - kick a running thread to enter/exit the kernel
|
|
|
|
* @p: the to-be-kicked thread
|
|
|
|
*
|
|
|
|
* Cause a process which is running on another CPU to enter
|
|
|
|
* kernel-mode, without any delay. (to get signals handled.)
|
|
|
|
*
|
2011-03-31 01:57:33 +00:00
|
|
|
* NOTE: this function doesn't have to take the runqueue lock,
|
2005-04-16 22:20:36 +00:00
|
|
|
* because all it wants to ensure is that the remote task enters
|
|
|
|
* the kernel. If the IPI races and the task has been migrated
|
|
|
|
* to another CPU then no harm is done and the purpose has been
|
|
|
|
* achieved as well.
|
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
void kick_process(struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
preempt_disable();
|
|
|
|
cpu = task_cpu(p);
|
|
|
|
if ((cpu != smp_processor_id()) && task_curr(p))
|
|
|
|
smp_send_reschedule(cpu);
|
|
|
|
preempt_enable();
|
|
|
|
}
|
2009-06-13 04:27:00 +00:00
|
|
|
EXPORT_SYMBOL_GPL(kick_process);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-03-15 09:10:19 +00:00
|
|
|
/*
|
2019-04-23 14:26:36 +00:00
|
|
|
* ->cpus_ptr is protected by both rq->lock and p->pi_lock
|
2016-03-10 11:54:08 +00:00
|
|
|
*
|
|
|
|
* A few notes on cpu_active vs cpu_online:
|
|
|
|
*
|
|
|
|
* - cpu_active must be a subset of cpu_online
|
|
|
|
*
|
sched: Clean up and harmonize the coding style of the scheduler code base
A good number of small style inconsistencies have accumulated
in the scheduler core, so do a pass over them to harmonize
all these details:
- fix speling in comments,
- use curly braces for multi-line statements,
- remove unnecessary parentheses from integer literals,
- capitalize consistently,
- remove stray newlines,
- add comments where necessary,
- remove invalid/unnecessary comments,
- align structure definitions and other data types vertically,
- add missing newlines for increased readability,
- fix vertical tabulation where it's misaligned,
- harmonize preprocessor conditional block labeling
and vertical alignment,
- remove line-breaks where they uglify the code,
- add newline after local variable definitions,
No change in functionality:
md5:
1191fa0a890cfa8132156d2959d7e9e2 built-in.o.before.asm
1191fa0a890cfa8132156d2959d7e9e2 built-in.o.after.asm
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-03-03 13:01:12 +00:00
|
|
|
* - on CPU-up we allow per-CPU kthreads on the online && !active CPU,
|
2016-03-10 11:54:08 +00:00
|
|
|
* see __set_cpus_allowed_ptr(). At this point the newly online
|
2017-02-01 10:46:42 +00:00
|
|
|
* CPU isn't yet part of the sched domains, and balancing will not
|
2016-03-10 11:54:08 +00:00
|
|
|
* see it.
|
|
|
|
*
|
2017-02-01 10:46:42 +00:00
|
|
|
* - on CPU-down we clear cpu_active() to mask the sched domains and
|
2016-03-10 11:54:08 +00:00
|
|
|
* avoid the load balancer to place new tasks on the to be removed
|
2017-02-01 10:46:42 +00:00
|
|
|
* CPU. Existing tasks will remain running there and will be taken
|
2016-03-10 11:54:08 +00:00
|
|
|
* off.
|
|
|
|
*
|
|
|
|
* This means that fallback selection must not select !active CPUs.
|
|
|
|
* And can assume that any active CPU must be online. Conversely
|
|
|
|
* select_task_rq() below may allow selection of !active CPUs in order
|
|
|
|
* to satisfy the above rules.
|
2010-03-15 09:10:19 +00:00
|
|
|
*/
|
2009-12-16 17:04:38 +00:00
|
|
|
static int select_fallback_rq(int cpu, struct task_struct *p)
|
|
|
|
{
|
sched: do not use cpu_to_node() to find an offlined cpu's node.
If a cpu is offline, its nid will be set to -1, and cpu_to_node(cpu)
will return -1. As a result, cpumask_of_node(nid) will return NULL. In
this case, find_next_bit() in for_each_cpu will get a NULL pointer and
cause panic.
Here is a call trace:
Call Trace:
<IRQ>
select_fallback_rq+0x71/0x190
try_to_wake_up+0x2cb/0x2f0
wake_up_process+0x15/0x20
hrtimer_wakeup+0x22/0x30
__run_hrtimer+0x83/0x320
hrtimer_interrupt+0x106/0x280
smp_apic_timer_interrupt+0x69/0x99
apic_timer_interrupt+0x6f/0x80
There is a hrtimer process sleeping, whose cpu has already been
offlined. When it is waken up, it tries to find another cpu to run, and
get a -1 nid. As a result, cpumask_of_node(-1) returns NULL, and causes
ernel panic.
This patch fixes this problem by judging if the nid is -1. If nid is
not -1, a cpu on the same node will be picked. Else, a online cpu on
another node will be picked.
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jiang Liu <liuj97@gmail.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-23 00:33:33 +00:00
|
|
|
int nid = cpu_to_node(cpu);
|
|
|
|
const struct cpumask *nodemask = NULL;
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
enum { cpuset, possible, fail } state = cpuset;
|
|
|
|
int dest_cpu;
|
2009-12-16 17:04:38 +00:00
|
|
|
|
sched: do not use cpu_to_node() to find an offlined cpu's node.
If a cpu is offline, its nid will be set to -1, and cpu_to_node(cpu)
will return -1. As a result, cpumask_of_node(nid) will return NULL. In
this case, find_next_bit() in for_each_cpu will get a NULL pointer and
cause panic.
Here is a call trace:
Call Trace:
<IRQ>
select_fallback_rq+0x71/0x190
try_to_wake_up+0x2cb/0x2f0
wake_up_process+0x15/0x20
hrtimer_wakeup+0x22/0x30
__run_hrtimer+0x83/0x320
hrtimer_interrupt+0x106/0x280
smp_apic_timer_interrupt+0x69/0x99
apic_timer_interrupt+0x6f/0x80
There is a hrtimer process sleeping, whose cpu has already been
offlined. When it is waken up, it tries to find another cpu to run, and
get a -1 nid. As a result, cpumask_of_node(-1) returns NULL, and causes
ernel panic.
This patch fixes this problem by judging if the nid is -1. If nid is
not -1, a cpu on the same node will be picked. Else, a online cpu on
another node will be picked.
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jiang Liu <liuj97@gmail.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-23 00:33:33 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* If the node that the CPU is on has been offlined, cpu_to_node()
|
|
|
|
* will return -1. There is no CPU on the node, and we should
|
|
|
|
* select the CPU on the other node.
|
sched: do not use cpu_to_node() to find an offlined cpu's node.
If a cpu is offline, its nid will be set to -1, and cpu_to_node(cpu)
will return -1. As a result, cpumask_of_node(nid) will return NULL. In
this case, find_next_bit() in for_each_cpu will get a NULL pointer and
cause panic.
Here is a call trace:
Call Trace:
<IRQ>
select_fallback_rq+0x71/0x190
try_to_wake_up+0x2cb/0x2f0
wake_up_process+0x15/0x20
hrtimer_wakeup+0x22/0x30
__run_hrtimer+0x83/0x320
hrtimer_interrupt+0x106/0x280
smp_apic_timer_interrupt+0x69/0x99
apic_timer_interrupt+0x6f/0x80
There is a hrtimer process sleeping, whose cpu has already been
offlined. When it is waken up, it tries to find another cpu to run, and
get a -1 nid. As a result, cpumask_of_node(-1) returns NULL, and causes
ernel panic.
This patch fixes this problem by judging if the nid is -1. If nid is
not -1, a cpu on the same node will be picked. Else, a online cpu on
another node will be picked.
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jiang Liu <liuj97@gmail.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-23 00:33:33 +00:00
|
|
|
*/
|
|
|
|
if (nid != -1) {
|
|
|
|
nodemask = cpumask_of_node(nid);
|
|
|
|
|
|
|
|
/* Look for allowed, online CPU in same node. */
|
|
|
|
for_each_cpu(dest_cpu, nodemask) {
|
|
|
|
if (!cpu_active(dest_cpu))
|
|
|
|
continue;
|
2019-04-23 14:26:36 +00:00
|
|
|
if (cpumask_test_cpu(dest_cpu, p->cpus_ptr))
|
sched: do not use cpu_to_node() to find an offlined cpu's node.
If a cpu is offline, its nid will be set to -1, and cpu_to_node(cpu)
will return -1. As a result, cpumask_of_node(nid) will return NULL. In
this case, find_next_bit() in for_each_cpu will get a NULL pointer and
cause panic.
Here is a call trace:
Call Trace:
<IRQ>
select_fallback_rq+0x71/0x190
try_to_wake_up+0x2cb/0x2f0
wake_up_process+0x15/0x20
hrtimer_wakeup+0x22/0x30
__run_hrtimer+0x83/0x320
hrtimer_interrupt+0x106/0x280
smp_apic_timer_interrupt+0x69/0x99
apic_timer_interrupt+0x6f/0x80
There is a hrtimer process sleeping, whose cpu has already been
offlined. When it is waken up, it tries to find another cpu to run, and
get a -1 nid. As a result, cpumask_of_node(-1) returns NULL, and causes
ernel panic.
This patch fixes this problem by judging if the nid is -1. If nid is
not -1, a cpu on the same node will be picked. Else, a online cpu on
another node will be picked.
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jiang Liu <liuj97@gmail.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-23 00:33:33 +00:00
|
|
|
return dest_cpu;
|
|
|
|
}
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
}
|
2009-12-16 17:04:38 +00:00
|
|
|
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
for (;;) {
|
|
|
|
/* Any allowed, online CPU? */
|
2019-04-23 14:26:36 +00:00
|
|
|
for_each_cpu(dest_cpu, p->cpus_ptr) {
|
2017-07-25 16:58:21 +00:00
|
|
|
if (!is_cpu_allowed(p, dest_cpu))
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
continue;
|
2017-07-25 16:58:21 +00:00
|
|
|
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2009-12-16 17:04:38 +00:00
|
|
|
|
2015-10-10 18:53:15 +00:00
|
|
|
/* No more Mr. Nice Guy. */
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
switch (state) {
|
|
|
|
case cpuset:
|
2015-10-10 18:53:15 +00:00
|
|
|
if (IS_ENABLED(CONFIG_CPUSETS)) {
|
|
|
|
cpuset_cpus_allowed_fallback(p);
|
|
|
|
state = possible;
|
|
|
|
break;
|
|
|
|
}
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Fall-through */
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
case possible:
|
|
|
|
do_set_cpus_allowed(p, cpu_possible_mask);
|
|
|
|
state = fail;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fail:
|
|
|
|
BUG();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (state != cpuset) {
|
|
|
|
/*
|
|
|
|
* Don't tell them about moving exiting tasks or
|
|
|
|
* kernel threads (both mm NULL), since they never
|
|
|
|
* leave kernel.
|
|
|
|
*/
|
|
|
|
if (p->mm && printk_ratelimit()) {
|
2014-06-04 23:11:40 +00:00
|
|
|
printk_deferred("process %d (%s) no longer affine to cpu%d\n",
|
sched: Fix select_fallback_rq() vs cpu_active/cpu_online
Commit 5fbd036b55 ("sched: Cleanup cpu_active madness"), which was
supposed to finally sort the cpu_active mess, instead uncovered more.
Since CPU_STARTING is ran before setting the cpu online, there's a
(small) window where the cpu has active,!online.
If during this time there's a wakeup of a task that used to reside on
that cpu select_task_rq() will use select_fallback_rq() to compute an
alternative cpu to run on since we find !online.
select_fallback_rq() however will compute the new cpu against
cpu_active, this means that it can return the same cpu it started out
with, the !online one, since that cpu is in fact marked active.
This results in us trying to scheduling a task on an offline cpu and
triggering a WARN in the IPI code.
The solution proposed by Chuansheng Liu of setting cpu_active in
set_cpu_online() is buggy, firstly not all archs actually use
set_cpu_online(), secondly, not all archs call set_cpu_online() with
IRQs disabled, this means we would introduce either the same race or
the race from fd8a7de17 ("x86: cpu-hotplug: Prevent softirq wakeup on
wrong CPU") -- albeit much narrower.
[ By setting online first and active later we have a window of
online,!active, fresh and bound kthreads have task_cpu() of 0 and
since cpu0 isn't in tsk_cpus_allowed() we end up in
select_fallback_rq() which excludes !active, resulting in a reset
of ->cpus_allowed and the thread running all over the place. ]
The solution is to re-work select_fallback_rq() to require active
_and_ online. This makes the active,!online case work as expected,
OTOH archs running CPU_STARTING after setting online are now
vulnerable to the issue from fd8a7de17 -- these are alpha and
blackfin.
Reported-by: Chuansheng Liu <chuansheng.liu@intel.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: linux-alpha@vger.kernel.org
Link: http://lkml.kernel.org/n/tip-hubqk1i10o4dpvlm06gq7v6j@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-03-20 14:57:01 +00:00
|
|
|
task_pid_nr(p), p->comm, cpu);
|
|
|
|
}
|
2009-12-16 17:04:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return dest_cpu;
|
|
|
|
}
|
|
|
|
|
2009-12-16 17:04:36 +00:00
|
|
|
/*
|
2019-04-23 14:26:36 +00:00
|
|
|
* The caller (fork, wakeup) owns p->pi_lock, ->cpus_ptr is stable.
|
2009-12-16 17:04:36 +00:00
|
|
|
*/
|
2009-11-25 12:31:39 +00:00
|
|
|
static inline
|
2013-10-07 10:29:16 +00:00
|
|
|
int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags)
|
2009-11-25 12:31:39 +00:00
|
|
|
{
|
2015-06-11 12:46:54 +00:00
|
|
|
lockdep_assert_held(&p->pi_lock);
|
|
|
|
|
2017-02-05 14:41:03 +00:00
|
|
|
if (p->nr_cpus_allowed > 1)
|
2014-11-05 01:14:37 +00:00
|
|
|
cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags);
|
2016-03-10 11:54:08 +00:00
|
|
|
else
|
2019-04-23 14:26:36 +00:00
|
|
|
cpu = cpumask_any(p->cpus_ptr);
|
2009-12-16 17:04:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* In order not to call set_task_cpu() on a blocking task we need
|
2019-04-23 14:26:36 +00:00
|
|
|
* to rely on ttwu() to place the task on a valid ->cpus_ptr
|
2017-02-01 10:46:42 +00:00
|
|
|
* CPU.
|
2009-12-16 17:04:36 +00:00
|
|
|
*
|
|
|
|
* Since this is common to all placement strategies, this lives here.
|
|
|
|
*
|
|
|
|
* [ this allows ->select_task() to simply return task_cpu(p) and
|
|
|
|
* not worry about this generic constraint ]
|
|
|
|
*/
|
sched/core: Require cpu_active() in select_task_rq(), for user tasks
select_task_rq() is used in a few paths to select the CPU upon which a
thread should be run - for example it is used by try_to_wake_up() & by
fork or exec balancing. As-is it allows use of any online CPU that is
present in the task's cpus_allowed mask.
This presents a problem because there is a period whilst CPUs are
brought online where a CPU is marked online, but is not yet fully
initialized - ie. the period where CPUHP_AP_ONLINE_IDLE <= state <
CPUHP_ONLINE. Usually we don't run any user tasks during this window,
but there are corner cases where this can happen. An example observed
is:
- Some user task A, running on CPU X, forks to create task B.
- sched_fork() calls __set_task_cpu() with cpu=X, setting task B's
task_struct::cpu field to X.
- CPU X is offlined.
- Task A, currently somewhere between the __set_task_cpu() in
copy_process() and the call to wake_up_new_task(), is migrated to
CPU Y by migrate_tasks() when CPU X is offlined.
- CPU X is onlined, but still in the CPUHP_AP_ONLINE_IDLE state. The
scheduler is now active on CPU X, but there are no user tasks on
the runqueue.
- Task A runs on CPU Y & reaches wake_up_new_task(). This calls
select_task_rq() with cpu=X, taken from task B's task_struct,
and select_task_rq() allows CPU X to be returned.
- Task A enqueues task B on CPU X's runqueue, via activate_task() &
enqueue_task().
- CPU X now has a user task on its runqueue before it has reached the
CPUHP_ONLINE state.
In most cases, the user tasks that schedule on the newly onlined CPU
have no idea that anything went wrong, but one case observed to be
problematic is if the task goes on to invoke the sched_setaffinity
syscall. The newly onlined CPU reaches the CPUHP_AP_ONLINE_IDLE state
before the CPU that brought it online calls stop_machine_unpark(). This
means that for a portion of the window of time between
CPUHP_AP_ONLINE_IDLE & CPUHP_ONLINE the newly onlined CPU's struct
cpu_stopper has its enabled field set to false. If a user thread is
executed on the CPU during this window and it invokes sched_setaffinity
with a CPU mask that does not include the CPU it's running on, then when
__set_cpus_allowed_ptr() calls stop_one_cpu() intending to invoke
migration_cpu_stop() and perform the actual migration away from the CPU
it will simply return -ENOENT rather than calling migration_cpu_stop().
We then return from the sched_setaffinity syscall back to the user task
that is now running on a CPU which it just asked not to run on, and
which is not present in its cpus_allowed mask.
This patch resolves the problem by having select_task_rq() enforce that
user tasks run on CPUs that are active - the same requirement that
select_fallback_rq() already enforces. This should ensure that newly
onlined CPUs reach the CPUHP_AP_ACTIVE state before being able to
schedule user tasks, and also implies that bringup_wait_for_ap() will
have called stop_machine_unpark() which resolves the sched_setaffinity
issue above.
I haven't yet investigated them, but it may be of interest to review
whether any of the actions performed by hotplug states between
CPUHP_AP_ONLINE_IDLE & CPUHP_AP_ACTIVE could have similar unintended
effects on user tasks that might schedule before they are reached, which
might widen the scope of the problem from just affecting the behaviour
of sched_setaffinity.
Signed-off-by: Paul Burton <paul.burton@mips.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20180526154648.11635-2-paul.burton@mips.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-05-26 15:46:47 +00:00
|
|
|
if (unlikely(!is_cpu_allowed(p, cpu)))
|
2009-12-16 17:04:38 +00:00
|
|
|
cpu = select_fallback_rq(task_cpu(p), p);
|
2009-12-16 17:04:36 +00:00
|
|
|
|
|
|
|
return cpu;
|
2009-11-25 12:31:39 +00:00
|
|
|
}
|
2010-04-15 05:29:59 +00:00
|
|
|
|
2017-05-29 21:02:57 +00:00
|
|
|
void sched_set_stop_task(int cpu, struct task_struct *stop)
|
|
|
|
{
|
|
|
|
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
|
|
|
|
struct task_struct *old_stop = cpu_rq(cpu)->stop;
|
|
|
|
|
|
|
|
if (stop) {
|
|
|
|
/*
|
|
|
|
* Make it appear like a SCHED_FIFO task, its something
|
|
|
|
* userspace knows about and won't get confused about.
|
|
|
|
*
|
|
|
|
* Also, it will make PI more or less work without too
|
|
|
|
* much confusion -- but then, stop work should not
|
|
|
|
* rely on PI working anyway.
|
|
|
|
*/
|
|
|
|
sched_setscheduler_nocheck(stop, SCHED_FIFO, ¶m);
|
|
|
|
|
|
|
|
stop->sched_class = &stop_sched_class;
|
|
|
|
}
|
|
|
|
|
|
|
|
cpu_rq(cpu)->stop = stop;
|
|
|
|
|
|
|
|
if (old_stop) {
|
|
|
|
/*
|
|
|
|
* Reset it back to a normal scheduling class so that
|
|
|
|
* it can die in pieces.
|
|
|
|
*/
|
|
|
|
old_stop->sched_class = &rt_sched_class;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-15 15:43:34 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
static inline int __set_cpus_allowed_ptr(struct task_struct *p,
|
|
|
|
const struct cpumask *new_mask, bool check)
|
|
|
|
{
|
|
|
|
return set_cpus_allowed_ptr(p, new_mask);
|
|
|
|
}
|
|
|
|
|
2015-06-11 12:46:50 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
2009-11-25 12:31:39 +00:00
|
|
|
|
2011-04-05 15:23:43 +00:00
|
|
|
static void
|
2011-04-05 15:23:55 +00:00
|
|
|
ttwu_stat(struct task_struct *p, int cpu, int wake_flags)
|
2009-12-03 06:08:03 +00:00
|
|
|
{
|
2016-06-17 17:43:26 +00:00
|
|
|
struct rq *rq;
|
2011-04-05 15:23:55 +00:00
|
|
|
|
2016-06-17 17:43:26 +00:00
|
|
|
if (!schedstat_enabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
rq = this_rq();
|
2011-04-05 15:23:43 +00:00
|
|
|
|
2016-06-17 17:43:26 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
if (cpu == rq->cpu) {
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(rq->ttwu_local);
|
|
|
|
__schedstat_inc(p->se.statistics.nr_wakeups_local);
|
2011-04-05 15:23:43 +00:00
|
|
|
} else {
|
|
|
|
struct sched_domain *sd;
|
|
|
|
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(p->se.statistics.nr_wakeups_remote);
|
2011-04-18 09:24:34 +00:00
|
|
|
rcu_read_lock();
|
2016-06-17 17:43:26 +00:00
|
|
|
for_each_domain(rq->cpu, sd) {
|
2011-04-05 15:23:43 +00:00
|
|
|
if (cpumask_test_cpu(cpu, sched_domain_span(sd))) {
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(sd->ttwu_wake_remote);
|
2011-04-05 15:23:43 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-04-18 09:24:34 +00:00
|
|
|
rcu_read_unlock();
|
2011-04-05 15:23:43 +00:00
|
|
|
}
|
2011-05-31 08:49:20 +00:00
|
|
|
|
|
|
|
if (wake_flags & WF_MIGRATED)
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(p->se.statistics.nr_wakeups_migrate);
|
2011-04-05 15:23:43 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(rq->ttwu_count);
|
|
|
|
__schedstat_inc(p->se.statistics.nr_wakeups);
|
2011-04-05 15:23:43 +00:00
|
|
|
|
|
|
|
if (wake_flags & WF_SYNC)
|
2018-01-16 19:51:06 +00:00
|
|
|
__schedstat_inc(p->se.statistics.nr_wakeups_sync);
|
2011-04-05 15:23:43 +00:00
|
|
|
}
|
|
|
|
|
2011-04-05 15:23:56 +00:00
|
|
|
/*
|
|
|
|
* Mark the task runnable and perform wakeup-preemption.
|
|
|
|
*/
|
2015-08-01 17:25:08 +00:00
|
|
|
static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags,
|
2016-09-21 13:38:10 +00:00
|
|
|
struct rq_flags *rf)
|
2009-12-03 06:08:03 +00:00
|
|
|
{
|
|
|
|
check_preempt_curr(rq, p, wake_flags);
|
|
|
|
p->state = TASK_RUNNING;
|
2015-06-09 09:13:36 +00:00
|
|
|
trace_sched_wakeup(p);
|
|
|
|
|
2009-12-03 06:08:03 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2015-06-11 12:46:39 +00:00
|
|
|
if (p->sched_class->task_woken) {
|
|
|
|
/*
|
2015-06-11 12:46:54 +00:00
|
|
|
* Our task @p is fully woken up and running; so its safe to
|
|
|
|
* drop the rq->lock, hereafter rq is only used for statistics.
|
2015-06-11 12:46:39 +00:00
|
|
|
*/
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_unpin_lock(rq, rf);
|
2009-12-03 06:08:03 +00:00
|
|
|
p->sched_class->task_woken(rq, p);
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_repin_lock(rq, rf);
|
2015-06-11 12:46:39 +00:00
|
|
|
}
|
2009-12-03 06:08:03 +00:00
|
|
|
|
2010-12-06 22:10:31 +00:00
|
|
|
if (rq->idle_stamp) {
|
2013-04-11 23:51:02 +00:00
|
|
|
u64 delta = rq_clock(rq) - rq->idle_stamp;
|
2013-09-13 18:26:52 +00:00
|
|
|
u64 max = 2*rq->max_idle_balance_cost;
|
2009-12-03 06:08:03 +00:00
|
|
|
|
2013-09-13 18:26:51 +00:00
|
|
|
update_avg(&rq->avg_idle, delta);
|
|
|
|
|
|
|
|
if (rq->avg_idle > max)
|
2009-12-03 06:08:03 +00:00
|
|
|
rq->avg_idle = max;
|
2013-09-13 18:26:51 +00:00
|
|
|
|
2009-12-03 06:08:03 +00:00
|
|
|
rq->idle_stamp = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-04-05 15:23:57 +00:00
|
|
|
static void
|
2015-08-01 17:25:08 +00:00
|
|
|
ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
|
2016-09-21 13:38:10 +00:00
|
|
|
struct rq_flags *rf)
|
2011-04-05 15:23:57 +00:00
|
|
|
{
|
2017-02-21 13:36:23 +00:00
|
|
|
int en_flags = ENQUEUE_WAKEUP | ENQUEUE_NOCLOCK;
|
2016-05-11 14:10:34 +00:00
|
|
|
|
2015-06-11 12:46:54 +00:00
|
|
|
lockdep_assert_held(&rq->lock);
|
|
|
|
|
2011-04-05 15:23:57 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
if (p->sched_contributes_to_load)
|
|
|
|
rq->nr_uninterruptible--;
|
2016-05-11 14:10:34 +00:00
|
|
|
|
|
|
|
if (wake_flags & WF_MIGRATED)
|
2016-05-10 16:24:37 +00:00
|
|
|
en_flags |= ENQUEUE_MIGRATED;
|
2011-04-05 15:23:57 +00:00
|
|
|
#endif
|
|
|
|
|
2019-04-09 07:53:13 +00:00
|
|
|
activate_task(rq, p, en_flags);
|
2016-09-21 13:38:10 +00:00
|
|
|
ttwu_do_wakeup(rq, p, wake_flags, rf);
|
2011-04-05 15:23:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called in case the task @p isn't fully descheduled from its runqueue,
|
|
|
|
* in this case we must do a remote wakeup. Its a 'light' wakeup though,
|
|
|
|
* since all we need to do is flip p->state to TASK_RUNNING, since
|
|
|
|
* the task is still ->on_rq.
|
|
|
|
*/
|
|
|
|
static int ttwu_remote(struct task_struct *p, int wake_flags)
|
|
|
|
{
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2011-04-05 15:23:57 +00:00
|
|
|
struct rq *rq;
|
|
|
|
int ret = 0;
|
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = __task_rq_lock(p, &rf);
|
2014-08-20 09:47:32 +00:00
|
|
|
if (task_on_rq_queued(p)) {
|
2013-04-11 23:51:00 +00:00
|
|
|
/* check_preempt_curr() may use rq clock */
|
|
|
|
update_rq_clock(rq);
|
2016-09-21 13:38:10 +00:00
|
|
|
ttwu_do_wakeup(rq, p, wake_flags, &rf);
|
2011-04-05 15:23:57 +00:00
|
|
|
ret = 1;
|
|
|
|
}
|
2015-07-31 19:28:18 +00:00
|
|
|
__task_rq_unlock(rq, &rf);
|
2011-04-05 15:23:57 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-04-05 15:23:58 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2014-06-04 17:31:18 +00:00
|
|
|
void sched_ttwu_pending(void)
|
2011-04-05 15:23:58 +00:00
|
|
|
{
|
|
|
|
struct rq *rq = this_rq();
|
2011-09-12 11:06:17 +00:00
|
|
|
struct llist_node *llist = llist_del_all(&rq->wake_list);
|
2017-05-12 00:39:44 +00:00
|
|
|
struct task_struct *p, *t;
|
2016-09-21 13:38:10 +00:00
|
|
|
struct rq_flags rf;
|
2011-04-05 15:23:58 +00:00
|
|
|
|
2014-06-04 17:31:18 +00:00
|
|
|
if (!llist)
|
|
|
|
return;
|
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock_irqsave(rq, &rf);
|
2017-02-21 13:36:23 +00:00
|
|
|
update_rq_clock(rq);
|
2011-04-05 15:23:58 +00:00
|
|
|
|
2017-05-12 00:39:44 +00:00
|
|
|
llist_for_each_entry_safe(p, t, llist, wake_entry)
|
|
|
|
ttwu_do_activate(rq, p, p->sched_remote_wakeup ? WF_MIGRATED : 0, &rf);
|
2011-04-05 15:23:58 +00:00
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irqrestore(rq, &rf);
|
2011-04-05 15:23:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void scheduler_ipi(void)
|
|
|
|
{
|
2013-08-14 12:55:31 +00:00
|
|
|
/*
|
|
|
|
* Fold TIF_NEED_RESCHED into the preempt_count; anybody setting
|
|
|
|
* TIF_NEED_RESCHED remotely (for the first time) will also send
|
|
|
|
* this IPI.
|
|
|
|
*/
|
2013-11-20 11:22:37 +00:00
|
|
|
preempt_fold_need_resched();
|
2013-08-14 12:55:31 +00:00
|
|
|
|
2014-03-18 20:12:53 +00:00
|
|
|
if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick())
|
2011-07-19 22:07:25 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Not all reschedule IPI handlers call irq_enter/irq_exit, since
|
|
|
|
* traditionally all their work was done from the interrupt return
|
|
|
|
* path. Now that we actually do some work, we need to make sure
|
|
|
|
* we do call them.
|
|
|
|
*
|
|
|
|
* Some archs already do call them, luckily irq_enter/exit nest
|
|
|
|
* properly.
|
|
|
|
*
|
|
|
|
* Arguably we should visit all archs and update all handlers,
|
|
|
|
* however a fair share of IPIs are still resched only so this would
|
|
|
|
* somewhat pessimize the simple resched case.
|
|
|
|
*/
|
|
|
|
irq_enter();
|
2011-09-12 11:06:17 +00:00
|
|
|
sched_ttwu_pending();
|
2011-10-03 22:09:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if someone kicked us for doing the nohz idle load balance.
|
|
|
|
*/
|
2013-06-05 08:13:11 +00:00
|
|
|
if (unlikely(got_nohz_idle_kick())) {
|
2011-10-03 22:09:01 +00:00
|
|
|
this_rq()->idle_balance = 1;
|
2011-10-03 22:09:00 +00:00
|
|
|
raise_softirq_irqoff(SCHED_SOFTIRQ);
|
2011-10-03 22:09:01 +00:00
|
|
|
}
|
2011-07-19 22:07:25 +00:00
|
|
|
irq_exit();
|
2011-04-05 15:23:58 +00:00
|
|
|
}
|
|
|
|
|
2016-05-23 09:19:07 +00:00
|
|
|
static void ttwu_queue_remote(struct task_struct *p, int cpu, int wake_flags)
|
2011-04-05 15:23:58 +00:00
|
|
|
{
|
2014-06-04 17:31:18 +00:00
|
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
|
2016-05-23 09:19:07 +00:00
|
|
|
p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED);
|
|
|
|
|
2014-06-04 17:31:18 +00:00
|
|
|
if (llist_add(&p->wake_entry, &cpu_rq(cpu)->wake_list)) {
|
|
|
|
if (!set_nr_if_polling(rq->idle))
|
|
|
|
smp_send_reschedule(cpu);
|
|
|
|
else
|
|
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
|
|
|
}
|
2011-04-05 15:23:58 +00:00
|
|
|
}
|
2011-05-26 12:21:33 +00:00
|
|
|
|
2014-09-04 07:17:53 +00:00
|
|
|
void wake_up_if_idle(int cpu)
|
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2014-09-04 07:17:53 +00:00
|
|
|
|
2014-11-29 16:13:51 +00:00
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
if (!is_idle_task(rcu_dereference(rq->curr)))
|
|
|
|
goto out;
|
2014-09-04 07:17:53 +00:00
|
|
|
|
|
|
|
if (set_nr_if_polling(rq->idle)) {
|
|
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
|
|
|
} else {
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock_irqsave(rq, &rf);
|
2014-09-04 07:17:53 +00:00
|
|
|
if (is_idle_task(rq->curr))
|
|
|
|
smp_send_reschedule(cpu);
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Else CPU is not idle, do nothing here: */
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irqrestore(rq, &rf);
|
2014-09-04 07:17:53 +00:00
|
|
|
}
|
2014-11-29 16:13:51 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
rcu_read_unlock();
|
2014-09-04 07:17:53 +00:00
|
|
|
}
|
|
|
|
|
2012-01-26 11:44:34 +00:00
|
|
|
bool cpus_share_cache(int this_cpu, int that_cpu)
|
2011-12-07 14:07:31 +00:00
|
|
|
{
|
|
|
|
return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu);
|
|
|
|
}
|
2011-05-26 12:21:33 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
2011-04-05 15:23:58 +00:00
|
|
|
|
2016-05-11 14:10:34 +00:00
|
|
|
static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags)
|
2011-04-05 15:23:57 +00:00
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2016-09-21 13:38:10 +00:00
|
|
|
struct rq_flags rf;
|
2011-04-05 15:23:57 +00:00
|
|
|
|
2011-05-20 04:01:10 +00:00
|
|
|
#if defined(CONFIG_SMP)
|
2012-01-26 11:44:34 +00:00
|
|
|
if (sched_feat(TTWU_QUEUE) && !cpus_share_cache(smp_processor_id(), cpu)) {
|
2017-02-01 10:46:42 +00:00
|
|
|
sched_clock_cpu(cpu); /* Sync clocks across CPUs */
|
2016-05-23 09:19:07 +00:00
|
|
|
ttwu_queue_remote(p, cpu, wake_flags);
|
2011-04-05 15:23:58 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
2017-02-21 13:36:23 +00:00
|
|
|
update_rq_clock(rq);
|
2016-09-21 13:38:10 +00:00
|
|
|
ttwu_do_activate(rq, p, wake_flags, &rf);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, &rf);
|
2009-12-03 06:08:03 +00:00
|
|
|
}
|
|
|
|
|
2015-11-17 18:01:11 +00:00
|
|
|
/*
|
|
|
|
* Notes on Program-Order guarantees on SMP systems.
|
|
|
|
*
|
|
|
|
* MIGRATION
|
|
|
|
*
|
|
|
|
* The basic program-order guarantee on SMP systems is that when a task [t]
|
2017-02-01 10:46:42 +00:00
|
|
|
* migrates, all its activity on its old CPU [c0] happens-before any subsequent
|
|
|
|
* execution on its new CPU [c1].
|
2015-11-17 18:01:11 +00:00
|
|
|
*
|
|
|
|
* For migration (of runnable tasks) this is provided by the following means:
|
|
|
|
*
|
|
|
|
* A) UNLOCK of the rq(c0)->lock scheduling out task t
|
|
|
|
* B) migration for t is required to synchronize *both* rq(c0)->lock and
|
|
|
|
* rq(c1)->lock (if not at the same time, then in that order).
|
|
|
|
* C) LOCK of the rq(c1)->lock scheduling in task
|
|
|
|
*
|
2018-07-16 18:06:03 +00:00
|
|
|
* Release/acquire chaining guarantees that B happens after A and C after B.
|
2017-02-01 10:46:42 +00:00
|
|
|
* Note: the CPU doing B need not be c0 or c1
|
2015-11-17 18:01:11 +00:00
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* CPU0 CPU1 CPU2
|
|
|
|
*
|
|
|
|
* LOCK rq(0)->lock
|
|
|
|
* sched-out X
|
|
|
|
* sched-in Y
|
|
|
|
* UNLOCK rq(0)->lock
|
|
|
|
*
|
|
|
|
* LOCK rq(0)->lock // orders against CPU0
|
|
|
|
* dequeue X
|
|
|
|
* UNLOCK rq(0)->lock
|
|
|
|
*
|
|
|
|
* LOCK rq(1)->lock
|
|
|
|
* enqueue X
|
|
|
|
* UNLOCK rq(1)->lock
|
|
|
|
*
|
|
|
|
* LOCK rq(1)->lock // orders against CPU2
|
|
|
|
* sched-out Z
|
|
|
|
* sched-in X
|
|
|
|
* UNLOCK rq(1)->lock
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* BLOCKING -- aka. SLEEP + WAKEUP
|
|
|
|
*
|
|
|
|
* For blocking we (obviously) need to provide the same guarantee as for
|
|
|
|
* migration. However the means are completely different as there is no lock
|
|
|
|
* chain to provide order. Instead we do:
|
|
|
|
*
|
|
|
|
* 1) smp_store_release(X->on_cpu, 0)
|
2016-04-04 08:57:12 +00:00
|
|
|
* 2) smp_cond_load_acquire(!X->on_cpu)
|
2015-11-17 18:01:11 +00:00
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* CPU0 (schedule) CPU1 (try_to_wake_up) CPU2 (schedule)
|
|
|
|
*
|
|
|
|
* LOCK rq(0)->lock LOCK X->pi_lock
|
|
|
|
* dequeue X
|
|
|
|
* sched-out X
|
|
|
|
* smp_store_release(X->on_cpu, 0);
|
|
|
|
*
|
2016-04-04 08:57:12 +00:00
|
|
|
* smp_cond_load_acquire(&X->on_cpu, !VAL);
|
2015-11-17 18:01:11 +00:00
|
|
|
* X->state = WAKING
|
|
|
|
* set_task_cpu(X,2)
|
|
|
|
*
|
|
|
|
* LOCK rq(2)->lock
|
|
|
|
* enqueue X
|
|
|
|
* X->state = RUNNING
|
|
|
|
* UNLOCK rq(2)->lock
|
|
|
|
*
|
|
|
|
* LOCK rq(2)->lock // orders against CPU1
|
|
|
|
* sched-out Z
|
|
|
|
* sched-in X
|
|
|
|
* UNLOCK rq(2)->lock
|
|
|
|
*
|
|
|
|
* UNLOCK X->pi_lock
|
|
|
|
* UNLOCK rq(0)->lock
|
|
|
|
*
|
|
|
|
*
|
2018-07-16 18:06:03 +00:00
|
|
|
* However, for wakeups there is a second guarantee we must provide, namely we
|
|
|
|
* must ensure that CONDITION=1 done by the caller can not be reordered with
|
|
|
|
* accesses to the task state; see try_to_wake_up() and set_current_state().
|
2015-11-17 18:01:11 +00:00
|
|
|
*/
|
|
|
|
|
2009-12-03 06:08:03 +00:00
|
|
|
/**
|
2005-04-16 22:20:36 +00:00
|
|
|
* try_to_wake_up - wake up a thread
|
2009-12-03 06:08:03 +00:00
|
|
|
* @p: the thread to be awakened
|
2005-04-16 22:20:36 +00:00
|
|
|
* @state: the mask of task states that can be woken
|
2009-12-03 06:08:03 +00:00
|
|
|
* @wake_flags: wake modifier flags (WF_*)
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2016-10-19 13:45:27 +00:00
|
|
|
* If (@state & @p->state) @p->state = TASK_RUNNING.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
2016-10-19 13:45:27 +00:00
|
|
|
* If the task was not queued/runnable, also place it back on a runqueue.
|
|
|
|
*
|
|
|
|
* Atomic against schedule() which would dequeue a task, also see
|
|
|
|
* set_current_state().
|
|
|
|
*
|
2018-07-16 18:06:03 +00:00
|
|
|
* This function executes a full memory barrier before accessing the task
|
|
|
|
* state; see set_current_state().
|
|
|
|
*
|
2016-10-19 13:45:27 +00:00
|
|
|
* Return: %true if @p->state changes (an actual wakeup was done),
|
|
|
|
* %false otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2011-04-05 15:23:54 +00:00
|
|
|
static int
|
|
|
|
try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
2011-04-05 15:23:57 +00:00
|
|
|
int cpu, success = 0;
|
2008-06-27 11:41:35 +00:00
|
|
|
|
2019-07-10 10:57:36 +00:00
|
|
|
preempt_disable();
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
if (p == current) {
|
|
|
|
/*
|
|
|
|
* We're waking current, this means 'p->on_rq' and 'task_cpu(p)
|
|
|
|
* == smp_processor_id()'. Together this means we can special
|
|
|
|
* case the whole 'p->on_rq && ttwu_remote()' case below
|
|
|
|
* without taking any locks.
|
|
|
|
*
|
|
|
|
* In particular:
|
|
|
|
* - we rely on Program-Order guarantees for all the ordering,
|
|
|
|
* - we're serialized against set_special_state() by virtue of
|
|
|
|
* it disabling IRQs (this allows not taking ->pi_lock).
|
|
|
|
*/
|
|
|
|
if (!(p->state & state))
|
2019-07-10 10:57:36 +00:00
|
|
|
goto out;
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
|
|
|
|
success = 1;
|
|
|
|
cpu = task_cpu(p);
|
|
|
|
trace_sched_waking(p);
|
|
|
|
p->state = TASK_RUNNING;
|
|
|
|
trace_sched_wakeup(p);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-08-12 16:14:00 +00:00
|
|
|
/*
|
|
|
|
* If we are going to wake up a thread waiting for CONDITION we
|
|
|
|
* need to ensure that CONDITION=1 done by the caller can not be
|
|
|
|
* reordered with p->state check below. This pairs with mb() in
|
|
|
|
* set_current_state() the waiting thread does.
|
|
|
|
*/
|
2011-04-05 15:23:45 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
locking: Introduce smp_mb__after_spinlock()
Since its inception, our understanding of ACQUIRE, esp. as applied to
spinlocks, has changed somewhat. Also, I wonder if, with a simple
change, we cannot make it provide more.
The problem with the comment is that the STORE done by spin_lock isn't
itself ordered by the ACQUIRE, and therefore a later LOAD can pass over
it and cross with any prior STORE, rendering the default WMB
insufficient (pointed out by Alan).
Now, this is only really a problem on PowerPC and ARM64, both of
which already defined smp_mb__before_spinlock() as a smp_mb().
At the same time, we can get a much stronger construct if we place
that same barrier _inside_ the spin_lock(). In that case we upgrade
the RCpc spinlock to an RCsc. That would make all schedule() calls
fully transitive against one another.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 09:37:53 +00:00
|
|
|
smp_mb__after_spinlock();
|
2009-09-15 12:43:03 +00:00
|
|
|
if (!(p->state & state))
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
goto unlock;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-06-09 09:13:36 +00:00
|
|
|
trace_sched_waking(p);
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* We're going to change ->state: */
|
|
|
|
success = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
cpu = task_cpu(p);
|
|
|
|
|
sched/core: Fix a race between try_to_wake_up() and a woken up task
The origin of the issue I've seen is related to
a missing memory barrier between check for task->state and
the check for task->on_rq.
The task being woken up is already awake from a schedule()
and is doing the following:
do {
schedule()
set_current_state(TASK_(UN)INTERRUPTIBLE);
} while (!cond);
The waker, actually gets stuck doing the following in
try_to_wake_up():
while (p->on_cpu)
cpu_relax();
Analysis:
The instance I've seen involves the following race:
CPU1 CPU2
while () {
if (cond)
break;
do {
schedule();
set_current_state(TASK_UN..)
} while (!cond);
wakeup_routine()
spin_lock_irqsave(wait_lock)
raw_spin_lock_irqsave(wait_lock) wake_up_process()
} try_to_wake_up()
set_current_state(TASK_RUNNING); ..
list_del(&waiter.list);
CPU2 wakes up CPU1, but before it can get the wait_lock and set
current state to TASK_RUNNING the following occurs:
CPU3
wakeup_routine()
raw_spin_lock_irqsave(wait_lock)
if (!list_empty)
wake_up_process()
try_to_wake_up()
raw_spin_lock_irqsave(p->pi_lock)
..
if (p->on_rq && ttwu_wakeup())
..
while (p->on_cpu)
cpu_relax()
..
CPU3 tries to wake up the task on CPU1 again since it finds
it on the wait_queue, CPU1 is spinning on wait_lock, but immediately
after CPU2, CPU3 got it.
CPU3 checks the state of p on CPU1, it is TASK_UNINTERRUPTIBLE and
the task is spinning on the wait_lock. Interestingly since p->on_rq
is checked under pi_lock, I've noticed that try_to_wake_up() finds
p->on_rq to be 0. This was the most confusing bit of the analysis,
but p->on_rq is changed under runqueue lock, rq_lock, the p->on_rq
check is not reliable without this fix IMHO. The race is visible
(based on the analysis) only when ttwu_queue() does a remote wakeup
via ttwu_queue_remote. In which case the p->on_rq change is not
done uder the pi_lock.
The result is that after a while the entire system locks up on
the raw_spin_irqlock_save(wait_lock) and the holder spins infintely
Reproduction of the issue:
The issue can be reproduced after a long run on my system with 80
threads and having to tweak available memory to very low and running
memory stress-ng mmapfork test. It usually takes a long time to
reproduce. I am trying to work on a test case that can reproduce
the issue faster, but thats work in progress. I am still testing the
changes on my still in a loop and the tests seem OK thus far.
Big thanks to Benjamin and Nick for helping debug this as well.
Ben helped catch the missing barrier, Nick caught every missing
bit in my theory.
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
[ Updated comment to clarify matching barriers. Many
architectures do not have a full barrier in switch_to()
so that cannot be relied upon. ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nicholas Piggin <nicholas.piggin@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/r/e02cce7b-d9ca-1ad0-7a61-ea97c7582b37@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 03:16:40 +00:00
|
|
|
/*
|
|
|
|
* Ensure we load p->on_rq _after_ p->state, otherwise it would
|
|
|
|
* be possible to, falsely, observe p->on_rq == 0 and get stuck
|
|
|
|
* in smp_cond_load_acquire() below.
|
|
|
|
*
|
2018-07-16 18:06:02 +00:00
|
|
|
* sched_ttwu_pending() try_to_wake_up()
|
|
|
|
* STORE p->on_rq = 1 LOAD p->state
|
|
|
|
* UNLOCK rq->lock
|
|
|
|
*
|
|
|
|
* __schedule() (switch to task 'p')
|
|
|
|
* LOCK rq->lock smp_rmb();
|
|
|
|
* smp_mb__after_spinlock();
|
|
|
|
* UNLOCK rq->lock
|
sched/core: Fix a race between try_to_wake_up() and a woken up task
The origin of the issue I've seen is related to
a missing memory barrier between check for task->state and
the check for task->on_rq.
The task being woken up is already awake from a schedule()
and is doing the following:
do {
schedule()
set_current_state(TASK_(UN)INTERRUPTIBLE);
} while (!cond);
The waker, actually gets stuck doing the following in
try_to_wake_up():
while (p->on_cpu)
cpu_relax();
Analysis:
The instance I've seen involves the following race:
CPU1 CPU2
while () {
if (cond)
break;
do {
schedule();
set_current_state(TASK_UN..)
} while (!cond);
wakeup_routine()
spin_lock_irqsave(wait_lock)
raw_spin_lock_irqsave(wait_lock) wake_up_process()
} try_to_wake_up()
set_current_state(TASK_RUNNING); ..
list_del(&waiter.list);
CPU2 wakes up CPU1, but before it can get the wait_lock and set
current state to TASK_RUNNING the following occurs:
CPU3
wakeup_routine()
raw_spin_lock_irqsave(wait_lock)
if (!list_empty)
wake_up_process()
try_to_wake_up()
raw_spin_lock_irqsave(p->pi_lock)
..
if (p->on_rq && ttwu_wakeup())
..
while (p->on_cpu)
cpu_relax()
..
CPU3 tries to wake up the task on CPU1 again since it finds
it on the wait_queue, CPU1 is spinning on wait_lock, but immediately
after CPU2, CPU3 got it.
CPU3 checks the state of p on CPU1, it is TASK_UNINTERRUPTIBLE and
the task is spinning on the wait_lock. Interestingly since p->on_rq
is checked under pi_lock, I've noticed that try_to_wake_up() finds
p->on_rq to be 0. This was the most confusing bit of the analysis,
but p->on_rq is changed under runqueue lock, rq_lock, the p->on_rq
check is not reliable without this fix IMHO. The race is visible
(based on the analysis) only when ttwu_queue() does a remote wakeup
via ttwu_queue_remote. In which case the p->on_rq change is not
done uder the pi_lock.
The result is that after a while the entire system locks up on
the raw_spin_irqlock_save(wait_lock) and the holder spins infintely
Reproduction of the issue:
The issue can be reproduced after a long run on my system with 80
threads and having to tweak available memory to very low and running
memory stress-ng mmapfork test. It usually takes a long time to
reproduce. I am trying to work on a test case that can reproduce
the issue faster, but thats work in progress. I am still testing the
changes on my still in a loop and the tests seem OK thus far.
Big thanks to Benjamin and Nick for helping debug this as well.
Ben helped catch the missing barrier, Nick caught every missing
bit in my theory.
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
[ Updated comment to clarify matching barriers. Many
architectures do not have a full barrier in switch_to()
so that cannot be relied upon. ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nicholas Piggin <nicholas.piggin@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/r/e02cce7b-d9ca-1ad0-7a61-ea97c7582b37@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 03:16:40 +00:00
|
|
|
*
|
|
|
|
* [task p]
|
2018-07-16 18:06:02 +00:00
|
|
|
* STORE p->state = UNINTERRUPTIBLE LOAD p->on_rq
|
sched/core: Fix a race between try_to_wake_up() and a woken up task
The origin of the issue I've seen is related to
a missing memory barrier between check for task->state and
the check for task->on_rq.
The task being woken up is already awake from a schedule()
and is doing the following:
do {
schedule()
set_current_state(TASK_(UN)INTERRUPTIBLE);
} while (!cond);
The waker, actually gets stuck doing the following in
try_to_wake_up():
while (p->on_cpu)
cpu_relax();
Analysis:
The instance I've seen involves the following race:
CPU1 CPU2
while () {
if (cond)
break;
do {
schedule();
set_current_state(TASK_UN..)
} while (!cond);
wakeup_routine()
spin_lock_irqsave(wait_lock)
raw_spin_lock_irqsave(wait_lock) wake_up_process()
} try_to_wake_up()
set_current_state(TASK_RUNNING); ..
list_del(&waiter.list);
CPU2 wakes up CPU1, but before it can get the wait_lock and set
current state to TASK_RUNNING the following occurs:
CPU3
wakeup_routine()
raw_spin_lock_irqsave(wait_lock)
if (!list_empty)
wake_up_process()
try_to_wake_up()
raw_spin_lock_irqsave(p->pi_lock)
..
if (p->on_rq && ttwu_wakeup())
..
while (p->on_cpu)
cpu_relax()
..
CPU3 tries to wake up the task on CPU1 again since it finds
it on the wait_queue, CPU1 is spinning on wait_lock, but immediately
after CPU2, CPU3 got it.
CPU3 checks the state of p on CPU1, it is TASK_UNINTERRUPTIBLE and
the task is spinning on the wait_lock. Interestingly since p->on_rq
is checked under pi_lock, I've noticed that try_to_wake_up() finds
p->on_rq to be 0. This was the most confusing bit of the analysis,
but p->on_rq is changed under runqueue lock, rq_lock, the p->on_rq
check is not reliable without this fix IMHO. The race is visible
(based on the analysis) only when ttwu_queue() does a remote wakeup
via ttwu_queue_remote. In which case the p->on_rq change is not
done uder the pi_lock.
The result is that after a while the entire system locks up on
the raw_spin_irqlock_save(wait_lock) and the holder spins infintely
Reproduction of the issue:
The issue can be reproduced after a long run on my system with 80
threads and having to tweak available memory to very low and running
memory stress-ng mmapfork test. It usually takes a long time to
reproduce. I am trying to work on a test case that can reproduce
the issue faster, but thats work in progress. I am still testing the
changes on my still in a loop and the tests seem OK thus far.
Big thanks to Benjamin and Nick for helping debug this as well.
Ben helped catch the missing barrier, Nick caught every missing
bit in my theory.
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
[ Updated comment to clarify matching barriers. Many
architectures do not have a full barrier in switch_to()
so that cannot be relied upon. ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nicholas Piggin <nicholas.piggin@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/r/e02cce7b-d9ca-1ad0-7a61-ea97c7582b37@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 03:16:40 +00:00
|
|
|
*
|
2018-07-16 18:06:02 +00:00
|
|
|
* Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
|
|
|
|
* __schedule(). See the comment for smp_mb__after_spinlock().
|
sched/core: Fix a race between try_to_wake_up() and a woken up task
The origin of the issue I've seen is related to
a missing memory barrier between check for task->state and
the check for task->on_rq.
The task being woken up is already awake from a schedule()
and is doing the following:
do {
schedule()
set_current_state(TASK_(UN)INTERRUPTIBLE);
} while (!cond);
The waker, actually gets stuck doing the following in
try_to_wake_up():
while (p->on_cpu)
cpu_relax();
Analysis:
The instance I've seen involves the following race:
CPU1 CPU2
while () {
if (cond)
break;
do {
schedule();
set_current_state(TASK_UN..)
} while (!cond);
wakeup_routine()
spin_lock_irqsave(wait_lock)
raw_spin_lock_irqsave(wait_lock) wake_up_process()
} try_to_wake_up()
set_current_state(TASK_RUNNING); ..
list_del(&waiter.list);
CPU2 wakes up CPU1, but before it can get the wait_lock and set
current state to TASK_RUNNING the following occurs:
CPU3
wakeup_routine()
raw_spin_lock_irqsave(wait_lock)
if (!list_empty)
wake_up_process()
try_to_wake_up()
raw_spin_lock_irqsave(p->pi_lock)
..
if (p->on_rq && ttwu_wakeup())
..
while (p->on_cpu)
cpu_relax()
..
CPU3 tries to wake up the task on CPU1 again since it finds
it on the wait_queue, CPU1 is spinning on wait_lock, but immediately
after CPU2, CPU3 got it.
CPU3 checks the state of p on CPU1, it is TASK_UNINTERRUPTIBLE and
the task is spinning on the wait_lock. Interestingly since p->on_rq
is checked under pi_lock, I've noticed that try_to_wake_up() finds
p->on_rq to be 0. This was the most confusing bit of the analysis,
but p->on_rq is changed under runqueue lock, rq_lock, the p->on_rq
check is not reliable without this fix IMHO. The race is visible
(based on the analysis) only when ttwu_queue() does a remote wakeup
via ttwu_queue_remote. In which case the p->on_rq change is not
done uder the pi_lock.
The result is that after a while the entire system locks up on
the raw_spin_irqlock_save(wait_lock) and the holder spins infintely
Reproduction of the issue:
The issue can be reproduced after a long run on my system with 80
threads and having to tweak available memory to very low and running
memory stress-ng mmapfork test. It usually takes a long time to
reproduce. I am trying to work on a test case that can reproduce
the issue faster, but thats work in progress. I am still testing the
changes on my still in a loop and the tests seem OK thus far.
Big thanks to Benjamin and Nick for helping debug this as well.
Ben helped catch the missing barrier, Nick caught every missing
bit in my theory.
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
[ Updated comment to clarify matching barriers. Many
architectures do not have a full barrier in switch_to()
so that cannot be relied upon. ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Nicholas Piggin <nicholas.piggin@gmail.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: <stable@vger.kernel.org>
Link: http://lkml.kernel.org/r/e02cce7b-d9ca-1ad0-7a61-ea97c7582b37@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 03:16:40 +00:00
|
|
|
*/
|
|
|
|
smp_rmb();
|
2011-04-05 15:23:57 +00:00
|
|
|
if (p->on_rq && ttwu_remote(p, wake_flags))
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
goto unlock;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
2015-10-07 12:14:13 +00:00
|
|
|
/*
|
|
|
|
* Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
|
|
|
|
* possible to, falsely, observe p->on_cpu == 0.
|
|
|
|
*
|
|
|
|
* One must be running (->on_cpu == 1) in order to remove oneself
|
|
|
|
* from the runqueue.
|
|
|
|
*
|
2018-07-16 18:06:02 +00:00
|
|
|
* __schedule() (switch to task 'p') try_to_wake_up()
|
|
|
|
* STORE p->on_cpu = 1 LOAD p->on_rq
|
|
|
|
* UNLOCK rq->lock
|
|
|
|
*
|
|
|
|
* __schedule() (put 'p' to sleep)
|
|
|
|
* LOCK rq->lock smp_rmb();
|
|
|
|
* smp_mb__after_spinlock();
|
|
|
|
* STORE p->on_rq = 0 LOAD p->on_cpu
|
2015-10-07 12:14:13 +00:00
|
|
|
*
|
2018-07-16 18:06:02 +00:00
|
|
|
* Pairs with the LOCK+smp_mb__after_spinlock() on rq->lock in
|
|
|
|
* __schedule(). See the comment for smp_mb__after_spinlock().
|
2015-10-07 12:14:13 +00:00
|
|
|
*/
|
|
|
|
smp_rmb();
|
|
|
|
|
2009-09-15 12:43:03 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* If the owning (remote) CPU is still in the middle of schedule() with
|
2011-04-05 15:23:57 +00:00
|
|
|
* this task as prev, wait until its done referencing the task.
|
2015-10-06 12:36:17 +00:00
|
|
|
*
|
2017-12-15 14:06:03 +00:00
|
|
|
* Pairs with the smp_store_release() in finish_task().
|
2015-10-06 12:36:17 +00:00
|
|
|
*
|
|
|
|
* This ensures that tasks getting woken will be fully ordered against
|
|
|
|
* their previous state and preserve Program Order.
|
2010-02-15 13:45:54 +00:00
|
|
|
*/
|
2016-04-04 08:57:12 +00:00
|
|
|
smp_cond_load_acquire(&p->on_cpu, !VAL);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2011-04-05 15:23:49 +00:00
|
|
|
p->sched_contributes_to_load = !!task_contributes_to_load(p);
|
2009-09-15 12:43:03 +00:00
|
|
|
p->state = TASK_WAKING;
|
2008-01-25 20:08:09 +00:00
|
|
|
|
2016-12-07 20:48:41 +00:00
|
|
|
if (p->in_iowait) {
|
2017-12-18 16:15:10 +00:00
|
|
|
delayacct_blkio_end(p);
|
2016-12-07 20:48:41 +00:00
|
|
|
atomic_dec(&task_rq(p)->nr_iowait);
|
|
|
|
}
|
|
|
|
|
2013-10-07 10:29:16 +00:00
|
|
|
cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags);
|
2011-05-31 08:49:20 +00:00
|
|
|
if (task_cpu(p) != cpu) {
|
|
|
|
wake_flags |= WF_MIGRATED;
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
psi_ttwu_dequeue(p);
|
2011-04-05 15:23:54 +00:00
|
|
|
set_task_cpu(p, cpu);
|
2011-05-31 08:49:20 +00:00
|
|
|
}
|
2016-12-07 20:48:41 +00:00
|
|
|
|
|
|
|
#else /* CONFIG_SMP */
|
|
|
|
|
|
|
|
if (p->in_iowait) {
|
2017-12-18 16:15:10 +00:00
|
|
|
delayacct_blkio_end(p);
|
2016-12-07 20:48:41 +00:00
|
|
|
atomic_dec(&task_rq(p)->nr_iowait);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
2016-05-11 14:10:34 +00:00
|
|
|
ttwu_queue(p, cpu, wake_flags);
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
unlock:
|
2011-04-05 15:23:45 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
sched/core: Optimize try_to_wake_up() for local wakeups
Jens reported that significant performance can be had on some block
workloads by special casing local wakeups. That is, wakeups on the
current task before it schedules out.
Given something like the normal wait pattern:
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
if (cond)
break;
schedule();
}
__set_current_state(TASK_RUNNING);
Any wakeup (on this CPU) after set_current_state() and before
schedule() would benefit from this.
Normal wakeups take p->pi_lock, which serializes wakeups to the same
task. By eliding that we gain concurrency on:
- ttwu_stat(); we already had concurrency on rq stats, this now also
brings it to task stats. -ENOCARE
- tracepoints; it is now possible to get multiple instances of
trace_sched_waking() (and possibly trace_sched_wakeup()) for the
same task. Tracers will have to learn to cope.
Furthermore, p->pi_lock is used by set_special_state(), to order
against TASK_RUNNING stores from other CPUs. But since this is
strictly CPU local, we don't need the lock, and set_special_state()'s
disabling of IRQs is sufficient.
After the normal wakeup takes p->pi_lock it issues
smp_mb__after_spinlock(), in order to ensure the woken task must
observe prior stores before we observe the p->state. If this is CPU
local, this will be satisfied with a compiler barrier, and we rely on
try_to_wake_up() being a funcation call, which implies such.
Since, when 'p == current', 'p->on_rq' must be true, the normal wakeup
would continue into the ttwu_remote() branch, which normally is
concerned with exactly this wakeup scenario, except from a remote CPU.
IOW we're waking a task that is still running. In this case, we can
trivially avoid taking rq->lock, all that's left from this is to set
p->state.
This then yields an extremely simple and fast path for 'p == current'.
Reported-by: Jens Axboe <axboe@kernel.dk>
Tested-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Qian Cai <cai@lca.pw>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: akpm@linux-foundation.org
Cc: gkohli@codeaurora.org
Cc: hch@lst.de
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-06-07 13:39:49 +00:00
|
|
|
out:
|
|
|
|
if (success)
|
|
|
|
ttwu_stat(p, cpu, wake_flags);
|
2019-07-10 10:57:36 +00:00
|
|
|
preempt_enable();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
2009-04-28 14:01:38 +00:00
|
|
|
/**
|
|
|
|
* wake_up_process - Wake up a specific process
|
|
|
|
* @p: The process to be woken up.
|
|
|
|
*
|
|
|
|
* Attempt to wake up the nominated process and move it to the set of runnable
|
2013-07-12 18:45:47 +00:00
|
|
|
* processes.
|
|
|
|
*
|
|
|
|
* Return: 1 if the process was woken up, 0 if it was already running.
|
2009-04-28 14:01:38 +00:00
|
|
|
*
|
2018-07-16 18:06:03 +00:00
|
|
|
* This function executes a full memory barrier before accessing the task state.
|
2009-04-28 14:01:38 +00:00
|
|
|
*/
|
2008-02-08 12:19:53 +00:00
|
|
|
int wake_up_process(struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2013-01-21 19:48:17 +00:00
|
|
|
return try_to_wake_up(p, TASK_NORMAL, 0);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(wake_up_process);
|
|
|
|
|
2008-02-08 12:19:53 +00:00
|
|
|
int wake_up_state(struct task_struct *p, unsigned int state)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
return try_to_wake_up(p, state, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Perform scheduler related setup for a newly forked process p.
|
|
|
|
* p is forked by current.
|
2007-07-09 16:51:59 +00:00
|
|
|
*
|
|
|
|
* __sched_fork() is basic setup used by init_idle() too:
|
|
|
|
*/
|
2013-10-07 10:29:26 +00:00
|
|
|
static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2011-04-05 15:23:44 +00:00
|
|
|
p->on_rq = 0;
|
|
|
|
|
|
|
|
p->se.on_rq = 0;
|
2007-07-09 16:51:59 +00:00
|
|
|
p->se.exec_start = 0;
|
|
|
|
p->se.sum_exec_runtime = 0;
|
2007-08-28 10:53:24 +00:00
|
|
|
p->se.prev_sum_exec_runtime = 0;
|
2008-12-14 11:34:15 +00:00
|
|
|
p->se.nr_migrations = 0;
|
2011-01-17 16:03:27 +00:00
|
|
|
p->se.vruntime = 0;
|
2011-04-05 15:23:44 +00:00
|
|
|
INIT_LIST_HEAD(&p->se.group_node);
|
2007-08-02 15:41:40 +00:00
|
|
|
|
2015-10-23 16:16:19 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
|
|
|
p->se.cfs_rq = NULL;
|
|
|
|
#endif
|
|
|
|
|
2007-08-02 15:41:40 +00:00
|
|
|
#ifdef CONFIG_SCHEDSTATS
|
2016-02-05 09:08:36 +00:00
|
|
|
/* Even if schedstat is disabled, there should not be garbage */
|
2010-03-11 02:37:45 +00:00
|
|
|
memset(&p->se.statistics, 0, sizeof(p->se.statistics));
|
2007-08-02 15:41:40 +00:00
|
|
|
#endif
|
2005-06-25 21:57:29 +00:00
|
|
|
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
RB_CLEAR_NODE(&p->dl.rb_node);
|
2015-01-28 14:08:03 +00:00
|
|
|
init_dl_task_timer(&p->dl);
|
2017-05-18 20:13:29 +00:00
|
|
|
init_dl_inactive_task_timer(&p->dl);
|
2014-09-19 09:22:39 +00:00
|
|
|
__dl_clear_params(p);
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
|
2008-01-25 20:08:27 +00:00
|
|
|
INIT_LIST_HEAD(&p->rt.run_list);
|
2016-01-18 14:27:07 +00:00
|
|
|
p->rt.timeout = 0;
|
|
|
|
p->rt.time_slice = sched_rr_timeslice;
|
|
|
|
p->rt.on_rq = 0;
|
|
|
|
p->rt.on_list = 0;
|
2005-06-25 21:57:29 +00:00
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
#ifdef CONFIG_PREEMPT_NOTIFIERS
|
|
|
|
INIT_HLIST_HEAD(&p->preempt_notifiers);
|
|
|
|
#endif
|
2012-10-25 12:16:43 +00:00
|
|
|
|
2019-03-05 23:45:41 +00:00
|
|
|
#ifdef CONFIG_COMPACTION
|
|
|
|
p->capture_control = NULL;
|
|
|
|
#endif
|
2018-05-04 15:41:09 +00:00
|
|
|
init_numa_balancing(clone_flags, p);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2015-08-11 16:24:21 +00:00
|
|
|
DEFINE_STATIC_KEY_FALSE(sched_numa_balancing);
|
|
|
|
|
2012-11-22 11:16:36 +00:00
|
|
|
#ifdef CONFIG_NUMA_BALANCING
|
2015-08-11 11:00:12 +00:00
|
|
|
|
2012-11-22 11:16:36 +00:00
|
|
|
void set_numabalancing_state(bool enabled)
|
|
|
|
{
|
|
|
|
if (enabled)
|
2015-08-11 16:24:21 +00:00
|
|
|
static_branch_enable(&sched_numa_balancing);
|
2012-11-22 11:16:36 +00:00
|
|
|
else
|
2015-08-11 16:24:21 +00:00
|
|
|
static_branch_disable(&sched_numa_balancing);
|
2012-11-22 11:16:36 +00:00
|
|
|
}
|
2014-01-23 23:53:13 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_PROC_SYSCTL
|
|
|
|
int sysctl_numa_balancing(struct ctl_table *table, int write,
|
|
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
|
{
|
|
|
|
struct ctl_table t;
|
|
|
|
int err;
|
2015-08-11 16:24:21 +00:00
|
|
|
int state = static_branch_likely(&sched_numa_balancing);
|
2014-01-23 23:53:13 +00:00
|
|
|
|
|
|
|
if (write && !capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
t = *table;
|
|
|
|
t.data = &state;
|
|
|
|
err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
if (write)
|
|
|
|
set_numabalancing_state(state);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2016-06-07 19:43:16 +00:00
|
|
|
#ifdef CONFIG_SCHEDSTATS
|
|
|
|
|
2016-02-05 09:08:36 +00:00
|
|
|
DEFINE_STATIC_KEY_FALSE(sched_schedstats);
|
2016-06-07 19:43:16 +00:00
|
|
|
static bool __initdata __sched_schedstats = false;
|
2016-02-05 09:08:36 +00:00
|
|
|
|
|
|
|
static void set_schedstats(bool enabled)
|
|
|
|
{
|
|
|
|
if (enabled)
|
|
|
|
static_branch_enable(&sched_schedstats);
|
|
|
|
else
|
|
|
|
static_branch_disable(&sched_schedstats);
|
|
|
|
}
|
|
|
|
|
|
|
|
void force_schedstat_enabled(void)
|
|
|
|
{
|
|
|
|
if (!schedstat_enabled()) {
|
|
|
|
pr_info("kernel profiling enabled schedstats, disable via kernel.sched_schedstats.\n");
|
|
|
|
static_branch_enable(&sched_schedstats);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __init setup_schedstats(char *str)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
if (!str)
|
|
|
|
goto out;
|
|
|
|
|
2016-06-07 19:43:16 +00:00
|
|
|
/*
|
|
|
|
* This code is called before jump labels have been set up, so we can't
|
|
|
|
* change the static branch directly just yet. Instead set a temporary
|
|
|
|
* variable so init_schedstats() can do it later.
|
|
|
|
*/
|
2016-02-05 09:08:36 +00:00
|
|
|
if (!strcmp(str, "enable")) {
|
2016-06-07 19:43:16 +00:00
|
|
|
__sched_schedstats = true;
|
2016-02-05 09:08:36 +00:00
|
|
|
ret = 1;
|
|
|
|
} else if (!strcmp(str, "disable")) {
|
2016-06-07 19:43:16 +00:00
|
|
|
__sched_schedstats = false;
|
2016-02-05 09:08:36 +00:00
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
if (!ret)
|
|
|
|
pr_warn("Unable to parse schedstats=\n");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
__setup("schedstats=", setup_schedstats);
|
|
|
|
|
2016-06-07 19:43:16 +00:00
|
|
|
static void __init init_schedstats(void)
|
|
|
|
{
|
|
|
|
set_schedstats(__sched_schedstats);
|
|
|
|
}
|
|
|
|
|
2016-02-05 09:08:36 +00:00
|
|
|
#ifdef CONFIG_PROC_SYSCTL
|
|
|
|
int sysctl_schedstats(struct ctl_table *table, int write,
|
|
|
|
void __user *buffer, size_t *lenp, loff_t *ppos)
|
|
|
|
{
|
|
|
|
struct ctl_table t;
|
|
|
|
int err;
|
|
|
|
int state = static_branch_likely(&sched_schedstats);
|
|
|
|
|
|
|
|
if (write && !capable(CAP_SYS_ADMIN))
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
t = *table;
|
|
|
|
t.data = &state;
|
|
|
|
err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
if (write)
|
|
|
|
set_schedstats(state);
|
|
|
|
return err;
|
|
|
|
}
|
2016-06-07 19:43:16 +00:00
|
|
|
#endif /* CONFIG_PROC_SYSCTL */
|
|
|
|
#else /* !CONFIG_SCHEDSTATS */
|
|
|
|
static inline void init_schedstats(void) {}
|
|
|
|
#endif /* CONFIG_SCHEDSTATS */
|
2007-07-09 16:51:59 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* fork()/clone()-time setup:
|
|
|
|
*/
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
int sched_fork(unsigned long clone_flags, struct task_struct *p)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2011-04-05 15:23:51 +00:00
|
|
|
unsigned long flags;
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2013-10-07 10:29:26 +00:00
|
|
|
__sched_fork(clone_flags, p);
|
2009-12-16 17:04:35 +00:00
|
|
|
/*
|
2016-06-16 11:29:28 +00:00
|
|
|
* We mark the process as NEW here. This guarantees that
|
2009-12-16 17:04:35 +00:00
|
|
|
* nobody will actually run it, and a signal or other external
|
|
|
|
* event cannot wake it up and insert it on the runqueue either.
|
|
|
|
*/
|
2016-06-16 11:29:28 +00:00
|
|
|
p->state = TASK_NEW;
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2011-07-27 15:14:55 +00:00
|
|
|
/*
|
|
|
|
* Make sure we do not leak PI boosting priority to the child.
|
|
|
|
*/
|
|
|
|
p->prio = current->normal_prio;
|
|
|
|
|
2019-06-21 08:42:05 +00:00
|
|
|
uclamp_fork(p);
|
|
|
|
|
2009-06-17 08:46:01 +00:00
|
|
|
/*
|
|
|
|
* Revert to default priority/policy on fork if requested.
|
|
|
|
*/
|
|
|
|
if (unlikely(p->sched_reset_on_fork)) {
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
|
2009-06-17 08:46:01 +00:00
|
|
|
p->policy = SCHED_NORMAL;
|
2009-06-17 08:48:02 +00:00
|
|
|
p->static_prio = NICE_TO_PRIO(0);
|
2011-07-27 15:14:55 +00:00
|
|
|
p->rt_priority = 0;
|
|
|
|
} else if (PRIO_TO_NICE(p->static_prio) < 0)
|
|
|
|
p->static_prio = NICE_TO_PRIO(0);
|
|
|
|
|
|
|
|
p->prio = p->normal_prio = __normal_prio(p);
|
2017-05-17 09:50:45 +00:00
|
|
|
set_load_weight(p, false);
|
2009-06-17 08:48:02 +00:00
|
|
|
|
2009-06-17 08:46:01 +00:00
|
|
|
/*
|
|
|
|
* We don't need the reset flag anymore after the fork. It has
|
|
|
|
* fulfilled its duty:
|
|
|
|
*/
|
|
|
|
p->sched_reset_on_fork = 0;
|
|
|
|
}
|
2009-06-15 15:17:47 +00:00
|
|
|
|
2018-07-06 13:06:15 +00:00
|
|
|
if (dl_prio(p->prio))
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
return -EAGAIN;
|
2018-07-06 13:06:15 +00:00
|
|
|
else if (rt_prio(p->prio))
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
p->sched_class = &rt_sched_class;
|
2018-07-06 13:06:15 +00:00
|
|
|
else
|
2007-10-15 15:00:11 +00:00
|
|
|
p->sched_class = &fair_sched_class;
|
2006-06-27 09:54:51 +00:00
|
|
|
|
2016-06-16 11:29:28 +00:00
|
|
|
init_entity_runnable_average(&p->se);
|
2009-11-27 16:32:46 +00:00
|
|
|
|
2010-06-22 09:44:53 +00:00
|
|
|
/*
|
|
|
|
* The child is not yet in the pid-hash so no cgroup attach races,
|
|
|
|
* and the cgroup is pinned to this child due to cgroup_fork()
|
|
|
|
* is ran before sched_fork().
|
|
|
|
*
|
|
|
|
* Silence PROVE_RCU.
|
|
|
|
*/
|
2011-04-05 15:23:51 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
2016-06-16 16:51:48 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* We're setting the CPU for the first time, we don't migrate,
|
2016-06-16 16:51:48 +00:00
|
|
|
* so use __set_task_cpu().
|
|
|
|
*/
|
2018-07-06 13:06:15 +00:00
|
|
|
__set_task_cpu(p, smp_processor_id());
|
2016-06-16 16:51:48 +00:00
|
|
|
if (p->sched_class->task_fork)
|
|
|
|
p->sched_class->task_fork(p);
|
2011-04-05 15:23:51 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
2009-09-10 11:42:00 +00:00
|
|
|
|
2015-06-25 18:23:37 +00:00
|
|
|
#ifdef CONFIG_SCHED_INFO
|
2007-07-09 16:51:59 +00:00
|
|
|
if (likely(sched_info_on()))
|
2006-07-14 07:24:38 +00:00
|
|
|
memset(&p->sched_info, 0, sizeof(p->sched_info));
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2011-04-05 15:23:40 +00:00
|
|
|
#if defined(CONFIG_SMP)
|
|
|
|
p->on_cpu = 0;
|
2005-06-25 21:57:23 +00:00
|
|
|
#endif
|
2013-08-14 12:55:46 +00:00
|
|
|
init_task_preempt_count(p);
|
2010-11-30 18:51:33 +00:00
|
|
|
#ifdef CONFIG_SMP
|
sched: create "pushable_tasks" list to limit pushing to one attempt
The RT scheduler employs a "push/pull" design to actively balance tasks
within the system (on a per disjoint cpuset basis). When a task is
awoken, it is immediately determined if there are any lower priority
cpus which should be preempted. This is opposed to the way normal
SCHED_OTHER tasks behave, which will wait for a periodic rebalancing
operation to occur before spreading out load.
When a particular RQ has more than 1 active RT task, it is said to
be in an "overloaded" state. Once this occurs, the system enters
the active balancing mode, where it will try to push the task away,
or persuade a different cpu to pull it over. The system will stay
in this state until the system falls back below the <= 1 queued RT
task per RQ.
However, the current implementation suffers from a limitation in the
push logic. Once overloaded, all tasks (other than current) on the
RQ are analyzed on every push operation, even if it was previously
unpushable (due to affinity, etc). Whats more, the operation stops
at the first task that is unpushable and will not look at items
lower in the queue. This causes two problems:
1) We can have the same tasks analyzed over and over again during each
push, which extends out the fast path in the scheduler for no
gain. Consider a RQ that has dozens of tasks that are bound to a
core. Each one of those tasks will be encountered and skipped
for each push operation while they are queued.
2) There may be lower-priority tasks under the unpushable task that
could have been successfully pushed, but will never be considered
until either the unpushable task is cleared, or a pull operation
succeeds. The net result is a potential latency source for mid
priority tasks.
This patch aims to rectify these two conditions by introducing a new
priority sorted list: "pushable_tasks". A task is added to the list
each time a task is activated or preempted. It is removed from the
list any time it is deactivated, made current, or fails to push.
This works because a task only needs to be attempted to push once.
After an initial failure to push, the other cpus will eventually try to
pull the task when the conditions are proper. This also solves the
problem that we don't completely analyze all tasks due to encountering
an unpushable tasks. Now every task will have a push attempted (when
appropriate).
This reduces latency both by shorting the critical section of the
rq->lock for certain workloads, and by making sure the algorithm
considers all eligible tasks in the system.
[ rostedt: added a couple more BUG_ONs ]
Signed-off-by: Gregory Haskins <ghaskins@novell.com>
Acked-by: Steven Rostedt <srostedt@redhat.com>
2008-12-29 14:39:53 +00:00
|
|
|
plist_node_init(&p->pushable_tasks, MAX_PRIO);
|
sched/deadline: Add SCHED_DEADLINE SMP-related data structures & logic
Introduces data structures relevant for implementing dynamic
migration of -deadline tasks and the logic for checking if
runqueues are overloaded with -deadline tasks and for choosing
where a task should migrate, when it is the case.
Adds also dynamic migrations to SCHED_DEADLINE, so that tasks can
be moved among CPUs when necessary. It is also possible to bind a
task to a (set of) CPU(s), thus restricting its capability of
migrating, or forbidding migrations at all.
The very same approach used in sched_rt is utilised:
- -deadline tasks are kept into CPU-specific runqueues,
- -deadline tasks are migrated among runqueues to achieve the
following:
* on an M-CPU system the M earliest deadline ready tasks
are always running;
* affinity/cpusets settings of all the -deadline tasks is
always respected.
Therefore, this very special form of "load balancing" is done with
an active method, i.e., the scheduler pushes or pulls tasks between
runqueues when they are woken up and/or (de)scheduled.
IOW, every time a preemption occurs, the descheduled task might be sent
to some other CPU (depending on its deadline) to continue executing
(push). On the other hand, every time a CPU becomes idle, it might pull
the second earliest deadline ready task from some other CPU.
To enforce this, a pull operation is always attempted before taking any
scheduling decision (pre_schedule()), as well as a push one after each
scheduling decision (post_schedule()). In addition, when a task arrives
or wakes up, the best CPU where to resume it is selected taking into
account its affinity mask, the system topology, but also its deadline.
E.g., from the scheduling point of view, the best CPU where to wake
up (and also where to push) a task is the one which is running the task
with the latest deadline among the M executing ones.
In order to facilitate these decisions, per-runqueue "caching" of the
deadlines of the currently running and of the first ready task is used.
Queued but not running tasks are also parked in another rb-tree to
speed-up pushes.
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-5-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:38 +00:00
|
|
|
RB_CLEAR_NODE(&p->pushable_dl_tasks);
|
2010-11-30 18:51:33 +00:00
|
|
|
#endif
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
unsigned long to_ratio(u64 period, u64 runtime)
|
|
|
|
{
|
|
|
|
if (runtime == RUNTIME_INF)
|
2017-05-18 20:13:31 +00:00
|
|
|
return BW_UNIT;
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Doing this here saves a lot of checks in all
|
|
|
|
* the calling paths, and returning zero seems
|
|
|
|
* safe for them anyway.
|
|
|
|
*/
|
|
|
|
if (period == 0)
|
|
|
|
return 0;
|
|
|
|
|
2017-05-18 20:13:31 +00:00
|
|
|
return div64_u64(runtime << BW_SHIFT, period);
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* wake_up_new_task - wake up a newly created task for the first time.
|
|
|
|
*
|
|
|
|
* This function will do some initial scheduler statistics housekeeping
|
|
|
|
* that must be done for every newly created context, then puts the task
|
|
|
|
* on the runqueue and wakes it.
|
|
|
|
*/
|
2011-05-11 16:18:05 +00:00
|
|
|
void wake_up_new_task(struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2007-07-09 16:51:59 +00:00
|
|
|
struct rq *rq;
|
2010-01-21 20:04:57 +00:00
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
|
2016-06-16 11:29:28 +00:00
|
|
|
p->state = TASK_RUNNING;
|
2010-01-21 20:04:57 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/*
|
|
|
|
* Fork balancing, do it here and not earlier because:
|
2019-04-23 14:26:36 +00:00
|
|
|
* - cpus_ptr can change in the fork path
|
2017-02-01 10:46:42 +00:00
|
|
|
* - any previously selected CPU might disappear through hotplug
|
2016-06-16 16:51:48 +00:00
|
|
|
*
|
|
|
|
* Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq,
|
|
|
|
* as we're not fully set-up yet.
|
2010-01-21 20:04:57 +00:00
|
|
|
*/
|
2018-01-30 10:45:55 +00:00
|
|
|
p->recent_used_cpu = task_cpu(p);
|
2016-06-16 16:51:48 +00:00
|
|
|
__set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0));
|
2010-03-24 17:34:10 +00:00
|
|
|
#endif
|
sched/fair: Fix post_init_entity_util_avg() serialization
Chris Wilson reported a divide by 0 at:
post_init_entity_util_avg():
> 725 if (cfs_rq->avg.util_avg != 0) {
> 726 sa->util_avg = cfs_rq->avg.util_avg * se->load.weight;
> -> 727 sa->util_avg /= (cfs_rq->avg.load_avg + 1);
> 728
> 729 if (sa->util_avg > cap)
> 730 sa->util_avg = cap;
> 731 } else {
Which given the lack of serialization, and the code generated from
update_cfs_rq_load_avg() is entirely possible:
if (atomic_long_read(&cfs_rq->removed_load_avg)) {
s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
sa->load_avg = max_t(long, sa->load_avg - r, 0);
sa->load_sum = max_t(s64, sa->load_sum - r * LOAD_AVG_MAX, 0);
removed_load = 1;
}
turns into:
ffffffff81087064: 49 8b 85 98 00 00 00 mov 0x98(%r13),%rax
ffffffff8108706b: 48 85 c0 test %rax,%rax
ffffffff8108706e: 74 40 je ffffffff810870b0
ffffffff81087070: 4c 89 f8 mov %r15,%rax
ffffffff81087073: 49 87 85 98 00 00 00 xchg %rax,0x98(%r13)
ffffffff8108707a: 49 29 45 70 sub %rax,0x70(%r13)
ffffffff8108707e: 4c 89 f9 mov %r15,%rcx
ffffffff81087081: bb 01 00 00 00 mov $0x1,%ebx
ffffffff81087086: 49 83 7d 70 00 cmpq $0x0,0x70(%r13)
ffffffff8108708b: 49 0f 49 4d 70 cmovns 0x70(%r13),%rcx
Which you'll note ends up with 'sa->load_avg - r' in memory at
ffffffff8108707a.
By calling post_init_entity_util_avg() under rq->lock we're sure to be
fully serialized against PELT updates and cannot observe intermediate
state like this.
Reported-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yuyang Du <yuyang.du@intel.com>
Cc: bsegall@google.com
Cc: morten.rasmussen@arm.com
Cc: pjt@google.com
Cc: steve.muckle@linaro.org
Fixes: 2b8c41daba32 ("sched/fair: Initiate a new task's util avg to a bounded value")
Link: http://lkml.kernel.org/r/20160609130750.GQ30909@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-06-09 13:07:50 +00:00
|
|
|
rq = __task_rq_lock(p, &rf);
|
2016-10-03 14:20:59 +00:00
|
|
|
update_rq_clock(rq);
|
2019-01-22 16:25:01 +00:00
|
|
|
post_init_entity_util_avg(p);
|
2010-03-24 17:34:10 +00:00
|
|
|
|
2017-02-21 13:47:02 +00:00
|
|
|
activate_task(rq, p, ENQUEUE_NOCLOCK);
|
2015-06-09 09:13:36 +00:00
|
|
|
trace_sched_wakeup_new(p);
|
2009-09-14 18:02:34 +00:00
|
|
|
check_preempt_curr(rq, p, WF_FORK);
|
2008-01-25 20:08:22 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2015-10-23 09:50:08 +00:00
|
|
|
if (p->sched_class->task_woken) {
|
|
|
|
/*
|
|
|
|
* Nothing relies on rq->lock after this, so its fine to
|
|
|
|
* drop it.
|
|
|
|
*/
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_unpin_lock(rq, &rf);
|
2009-12-16 17:04:40 +00:00
|
|
|
p->sched_class->task_woken(rq, p);
|
2016-09-21 13:38:10 +00:00
|
|
|
rq_repin_lock(rq, &rf);
|
2015-10-23 09:50:08 +00:00
|
|
|
}
|
2008-01-25 20:08:22 +00:00
|
|
|
#endif
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
#ifdef CONFIG_PREEMPT_NOTIFIERS
|
|
|
|
|
2018-03-26 21:09:26 +00:00
|
|
|
static DEFINE_STATIC_KEY_FALSE(preempt_notifier_key);
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
|
2015-07-03 16:53:58 +00:00
|
|
|
void preempt_notifier_inc(void)
|
|
|
|
{
|
2018-03-26 21:09:26 +00:00
|
|
|
static_branch_inc(&preempt_notifier_key);
|
2015-07-03 16:53:58 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_inc);
|
|
|
|
|
|
|
|
void preempt_notifier_dec(void)
|
|
|
|
{
|
2018-03-26 21:09:26 +00:00
|
|
|
static_branch_dec(&preempt_notifier_key);
|
2015-07-03 16:53:58 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_dec);
|
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
/**
|
2009-03-16 19:58:09 +00:00
|
|
|
* preempt_notifier_register - tell me when current is being preempted & rescheduled
|
2007-07-31 07:37:50 +00:00
|
|
|
* @notifier: notifier struct to register
|
2007-07-26 11:40:43 +00:00
|
|
|
*/
|
|
|
|
void preempt_notifier_register(struct preempt_notifier *notifier)
|
|
|
|
{
|
2018-03-26 21:09:26 +00:00
|
|
|
if (!static_branch_unlikely(&preempt_notifier_key))
|
2015-07-03 16:53:58 +00:00
|
|
|
WARN(1, "registering preempt_notifier while notifiers disabled\n");
|
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
hlist_add_head(¬ifier->link, ¤t->preempt_notifiers);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_register);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* preempt_notifier_unregister - no longer interested in preemption notifications
|
2007-07-31 07:37:50 +00:00
|
|
|
* @notifier: notifier struct to unregister
|
2007-07-26 11:40:43 +00:00
|
|
|
*
|
2015-05-17 16:53:10 +00:00
|
|
|
* This is *not* safe to call from within a preemption notifier.
|
2007-07-26 11:40:43 +00:00
|
|
|
*/
|
|
|
|
void preempt_notifier_unregister(struct preempt_notifier *notifier)
|
|
|
|
{
|
|
|
|
hlist_del(¬ifier->link);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_unregister);
|
|
|
|
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
static void __fire_sched_in_preempt_notifiers(struct task_struct *curr)
|
2007-07-26 11:40:43 +00:00
|
|
|
{
|
|
|
|
struct preempt_notifier *notifier;
|
|
|
|
|
hlist: drop the node parameter from iterators
I'm not sure why, but the hlist for each entry iterators were conceived
list_for_each_entry(pos, head, member)
The hlist ones were greedy and wanted an extra parameter:
hlist_for_each_entry(tpos, pos, head, member)
Why did they need an extra pos parameter? I'm not quite sure. Not only
they don't really need it, it also prevents the iterator from looking
exactly like the list iterator, which is unfortunate.
Besides the semantic patch, there was some manual work required:
- Fix up the actual hlist iterators in linux/list.h
- Fix up the declaration of other iterators based on the hlist ones.
- A very small amount of places were using the 'node' parameter, this
was modified to use 'obj->member' instead.
- Coccinelle didn't handle the hlist_for_each_entry_safe iterator
properly, so those had to be fixed up manually.
The semantic patch which is mostly the work of Peter Senna Tschudin is here:
@@
iterator name hlist_for_each_entry, hlist_for_each_entry_continue, hlist_for_each_entry_from, hlist_for_each_entry_rcu, hlist_for_each_entry_rcu_bh, hlist_for_each_entry_continue_rcu_bh, for_each_busy_worker, ax25_uid_for_each, ax25_for_each, inet_bind_bucket_for_each, sctp_for_each_hentry, sk_for_each, sk_for_each_rcu, sk_for_each_from, sk_for_each_safe, sk_for_each_bound, hlist_for_each_entry_safe, hlist_for_each_entry_continue_rcu, nr_neigh_for_each, nr_neigh_for_each_safe, nr_node_for_each, nr_node_for_each_safe, for_each_gfn_indirect_valid_sp, for_each_gfn_sp, for_each_host;
type T;
expression a,c,d,e;
identifier b;
statement S;
@@
-T b;
<+... when != b
(
hlist_for_each_entry(a,
- b,
c, d) S
|
hlist_for_each_entry_continue(a,
- b,
c) S
|
hlist_for_each_entry_from(a,
- b,
c) S
|
hlist_for_each_entry_rcu(a,
- b,
c, d) S
|
hlist_for_each_entry_rcu_bh(a,
- b,
c, d) S
|
hlist_for_each_entry_continue_rcu_bh(a,
- b,
c) S
|
for_each_busy_worker(a, c,
- b,
d) S
|
ax25_uid_for_each(a,
- b,
c) S
|
ax25_for_each(a,
- b,
c) S
|
inet_bind_bucket_for_each(a,
- b,
c) S
|
sctp_for_each_hentry(a,
- b,
c) S
|
sk_for_each(a,
- b,
c) S
|
sk_for_each_rcu(a,
- b,
c) S
|
sk_for_each_from
-(a, b)
+(a)
S
+ sk_for_each_from(a) S
|
sk_for_each_safe(a,
- b,
c, d) S
|
sk_for_each_bound(a,
- b,
c) S
|
hlist_for_each_entry_safe(a,
- b,
c, d, e) S
|
hlist_for_each_entry_continue_rcu(a,
- b,
c) S
|
nr_neigh_for_each(a,
- b,
c) S
|
nr_neigh_for_each_safe(a,
- b,
c, d) S
|
nr_node_for_each(a,
- b,
c) S
|
nr_node_for_each_safe(a,
- b,
c, d) S
|
- for_each_gfn_sp(a, c, d, b) S
+ for_each_gfn_sp(a, c, d) S
|
- for_each_gfn_indirect_valid_sp(a, c, d, b) S
+ for_each_gfn_indirect_valid_sp(a, c, d) S
|
for_each_host(a,
- b,
c) S
|
for_each_host_safe(a,
- b,
c, d) S
|
for_each_mesh_entry(a,
- b,
c, d) S
)
...+>
[akpm@linux-foundation.org: drop bogus change from net/ipv4/raw.c]
[akpm@linux-foundation.org: drop bogus hunk from net/ipv6/raw.c]
[akpm@linux-foundation.org: checkpatch fixes]
[akpm@linux-foundation.org: fix warnings]
[akpm@linux-foudnation.org: redo intrusive kvm changes]
Tested-by: Peter Senna Tschudin <peter.senna@gmail.com>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-28 01:06:00 +00:00
|
|
|
hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
|
2007-07-26 11:40:43 +00:00
|
|
|
notifier->ops->sched_in(notifier, raw_smp_processor_id());
|
|
|
|
}
|
|
|
|
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
static __always_inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
|
|
|
|
{
|
2018-03-26 21:09:26 +00:00
|
|
|
if (static_branch_unlikely(&preempt_notifier_key))
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
__fire_sched_in_preempt_notifiers(curr);
|
|
|
|
}
|
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
static void
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
__fire_sched_out_preempt_notifiers(struct task_struct *curr,
|
|
|
|
struct task_struct *next)
|
2007-07-26 11:40:43 +00:00
|
|
|
{
|
|
|
|
struct preempt_notifier *notifier;
|
|
|
|
|
hlist: drop the node parameter from iterators
I'm not sure why, but the hlist for each entry iterators were conceived
list_for_each_entry(pos, head, member)
The hlist ones were greedy and wanted an extra parameter:
hlist_for_each_entry(tpos, pos, head, member)
Why did they need an extra pos parameter? I'm not quite sure. Not only
they don't really need it, it also prevents the iterator from looking
exactly like the list iterator, which is unfortunate.
Besides the semantic patch, there was some manual work required:
- Fix up the actual hlist iterators in linux/list.h
- Fix up the declaration of other iterators based on the hlist ones.
- A very small amount of places were using the 'node' parameter, this
was modified to use 'obj->member' instead.
- Coccinelle didn't handle the hlist_for_each_entry_safe iterator
properly, so those had to be fixed up manually.
The semantic patch which is mostly the work of Peter Senna Tschudin is here:
@@
iterator name hlist_for_each_entry, hlist_for_each_entry_continue, hlist_for_each_entry_from, hlist_for_each_entry_rcu, hlist_for_each_entry_rcu_bh, hlist_for_each_entry_continue_rcu_bh, for_each_busy_worker, ax25_uid_for_each, ax25_for_each, inet_bind_bucket_for_each, sctp_for_each_hentry, sk_for_each, sk_for_each_rcu, sk_for_each_from, sk_for_each_safe, sk_for_each_bound, hlist_for_each_entry_safe, hlist_for_each_entry_continue_rcu, nr_neigh_for_each, nr_neigh_for_each_safe, nr_node_for_each, nr_node_for_each_safe, for_each_gfn_indirect_valid_sp, for_each_gfn_sp, for_each_host;
type T;
expression a,c,d,e;
identifier b;
statement S;
@@
-T b;
<+... when != b
(
hlist_for_each_entry(a,
- b,
c, d) S
|
hlist_for_each_entry_continue(a,
- b,
c) S
|
hlist_for_each_entry_from(a,
- b,
c) S
|
hlist_for_each_entry_rcu(a,
- b,
c, d) S
|
hlist_for_each_entry_rcu_bh(a,
- b,
c, d) S
|
hlist_for_each_entry_continue_rcu_bh(a,
- b,
c) S
|
for_each_busy_worker(a, c,
- b,
d) S
|
ax25_uid_for_each(a,
- b,
c) S
|
ax25_for_each(a,
- b,
c) S
|
inet_bind_bucket_for_each(a,
- b,
c) S
|
sctp_for_each_hentry(a,
- b,
c) S
|
sk_for_each(a,
- b,
c) S
|
sk_for_each_rcu(a,
- b,
c) S
|
sk_for_each_from
-(a, b)
+(a)
S
+ sk_for_each_from(a) S
|
sk_for_each_safe(a,
- b,
c, d) S
|
sk_for_each_bound(a,
- b,
c) S
|
hlist_for_each_entry_safe(a,
- b,
c, d, e) S
|
hlist_for_each_entry_continue_rcu(a,
- b,
c) S
|
nr_neigh_for_each(a,
- b,
c) S
|
nr_neigh_for_each_safe(a,
- b,
c, d) S
|
nr_node_for_each(a,
- b,
c) S
|
nr_node_for_each_safe(a,
- b,
c, d) S
|
- for_each_gfn_sp(a, c, d, b) S
+ for_each_gfn_sp(a, c, d) S
|
- for_each_gfn_indirect_valid_sp(a, c, d, b) S
+ for_each_gfn_indirect_valid_sp(a, c, d) S
|
for_each_host(a,
- b,
c) S
|
for_each_host_safe(a,
- b,
c, d) S
|
for_each_mesh_entry(a,
- b,
c, d) S
)
...+>
[akpm@linux-foundation.org: drop bogus change from net/ipv4/raw.c]
[akpm@linux-foundation.org: drop bogus hunk from net/ipv6/raw.c]
[akpm@linux-foundation.org: checkpatch fixes]
[akpm@linux-foundation.org: fix warnings]
[akpm@linux-foudnation.org: redo intrusive kvm changes]
Tested-by: Peter Senna Tschudin <peter.senna@gmail.com>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
Cc: Wu Fengguang <fengguang.wu@intel.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-02-28 01:06:00 +00:00
|
|
|
hlist_for_each_entry(notifier, &curr->preempt_notifiers, link)
|
2007-07-26 11:40:43 +00:00
|
|
|
notifier->ops->sched_out(notifier, next);
|
|
|
|
}
|
|
|
|
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
static __always_inline void
|
|
|
|
fire_sched_out_preempt_notifiers(struct task_struct *curr,
|
|
|
|
struct task_struct *next)
|
|
|
|
{
|
2018-03-26 21:09:26 +00:00
|
|
|
if (static_branch_unlikely(&preempt_notifier_key))
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
__fire_sched_out_preempt_notifiers(curr, next);
|
|
|
|
}
|
|
|
|
|
2008-05-30 12:23:45 +00:00
|
|
|
#else /* !CONFIG_PREEMPT_NOTIFIERS */
|
2007-07-26 11:40:43 +00:00
|
|
|
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
static inline void fire_sched_in_preempt_notifiers(struct task_struct *curr)
|
2007-07-26 11:40:43 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
sched/preempt: Add static_key() to preempt_notifiers
Avoid touching the curr->preempt_notifier cacheline when not needed.
Provides a small improvement on pipe-bench:
taskset 01 perf stat --repeat 10 -- perf bench sched pipe
before:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12385.016204 task-clock (msec) # 1.001 CPUs utilized ( +- 0.34% )
2,000,023 context-switches # 0.161 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
175 page-faults # 0.014 K/sec ( +- 0.26% )
41,376,162,250 cycles # 3.341 GHz ( +- 0.11% )
17,389,139,321 stalled-cycles-frontend # 42.03% frontend cycles idle ( +- 0.25% )
<not supported> stalled-cycles-backend
68,788,588,003 instructions # 1.66 insns per cycle
# 0.25 stalled cycles per insn ( +- 0.02% )
13,449,387,620 branches # 1085.940 M/sec ( +- 0.02% )
20,880,690 branch-misses # 0.16% of all branches ( +- 0.98% )
12.372646094 seconds time elapsed ( +- 0.34% )
after:
Performance counter stats for 'perf bench sched pipe' (10 runs):
12180.936528 task-clock (msec) # 1.001 CPUs utilized ( +- 0.33% )
2,000,077 context-switches # 0.164 M/sec ( +- 0.00% )
0 cpu-migrations # 0.000 K/sec
174 page-faults # 0.014 K/sec ( +- 0.27% )
40,691,545,577 cycles # 3.341 GHz ( +- 0.06% )
16,446,333,371 stalled-cycles-frontend # 40.42% frontend cycles idle ( +- 0.18% )
<not supported> stalled-cycles-backend
68,570,100,387 instructions # 1.69 insns per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
13,389,740,014 branches # 1099.237 M/sec ( +- 0.01% )
20,175,440 branch-misses # 0.15% of all branches ( +- 0.52% )
12.169253010 seconds time elapsed ( +- 0.33% )
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-06-08 14:00:30 +00:00
|
|
|
static inline void
|
2007-07-26 11:40:43 +00:00
|
|
|
fire_sched_out_preempt_notifiers(struct task_struct *curr,
|
|
|
|
struct task_struct *next)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_PREEMPT_NOTIFIERS */
|
2007-07-26 11:40:43 +00:00
|
|
|
|
2017-12-15 14:06:03 +00:00
|
|
|
static inline void prepare_task(struct task_struct *next)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/*
|
|
|
|
* Claim the task as running, we do this before switching to it
|
|
|
|
* such that any running task will have this set.
|
|
|
|
*/
|
|
|
|
next->on_cpu = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void finish_task(struct task_struct *prev)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/*
|
|
|
|
* After ->on_cpu is cleared, the task can be moved to a different CPU.
|
|
|
|
* We must ensure this doesn't happen until the switch is completely
|
|
|
|
* finished.
|
|
|
|
*
|
|
|
|
* In particular, the load of prev->state in finish_task_switch() must
|
|
|
|
* happen before this.
|
|
|
|
*
|
|
|
|
* Pairs with the smp_cond_load_acquire() in try_to_wake_up().
|
|
|
|
*/
|
|
|
|
smp_store_release(&prev->on_cpu, 0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-02-06 16:52:13 +00:00
|
|
|
static inline void
|
|
|
|
prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf)
|
2017-12-15 14:06:03 +00:00
|
|
|
{
|
2018-02-06 16:52:13 +00:00
|
|
|
/*
|
|
|
|
* Since the runqueue lock will be released by the next
|
|
|
|
* task (which is an invalid locking op but in the case
|
|
|
|
* of the scheduler it's an obvious special-case), so we
|
|
|
|
* do an early lockdep release here:
|
|
|
|
*/
|
|
|
|
rq_unpin_lock(rq, rf);
|
2019-09-19 16:09:40 +00:00
|
|
|
spin_release(&rq->lock.dep_map, _THIS_IP_);
|
2017-12-15 14:06:03 +00:00
|
|
|
#ifdef CONFIG_DEBUG_SPINLOCK
|
|
|
|
/* this is a valid case when another task releases the spinlock */
|
2018-02-06 16:52:13 +00:00
|
|
|
rq->lock.owner = next;
|
2017-12-15 14:06:03 +00:00
|
|
|
#endif
|
2018-02-06 16:52:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void finish_lock_switch(struct rq *rq)
|
|
|
|
{
|
2017-12-15 14:06:03 +00:00
|
|
|
/*
|
|
|
|
* If we are tracking spinlock dependencies then we have to
|
|
|
|
* fix up the runqueue lock - which gets 'carried over' from
|
|
|
|
* prev into current:
|
|
|
|
*/
|
|
|
|
spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
|
|
|
|
raw_spin_unlock_irq(&rq->lock);
|
|
|
|
}
|
|
|
|
|
2018-03-03 11:20:47 +00:00
|
|
|
/*
|
|
|
|
* NOP if the arch has not defined these:
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef prepare_arch_switch
|
|
|
|
# define prepare_arch_switch(next) do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef finish_arch_post_lock_switch
|
|
|
|
# define finish_arch_post_lock_switch() do { } while (0)
|
|
|
|
#endif
|
|
|
|
|
2005-06-25 21:57:23 +00:00
|
|
|
/**
|
|
|
|
* prepare_task_switch - prepare to switch tasks
|
|
|
|
* @rq: the runqueue preparing to switch
|
2007-07-31 07:37:50 +00:00
|
|
|
* @prev: the current task that is being switched out
|
2005-06-25 21:57:23 +00:00
|
|
|
* @next: the task we are going to switch to.
|
|
|
|
*
|
|
|
|
* This is called with the rq lock held and interrupts off. It must
|
|
|
|
* be paired with a subsequent finish_task_switch after the context
|
|
|
|
* switch.
|
|
|
|
*
|
|
|
|
* prepare_task_switch sets up locking and calls architecture specific
|
|
|
|
* hooks.
|
|
|
|
*/
|
2007-07-26 11:40:43 +00:00
|
|
|
static inline void
|
|
|
|
prepare_task_switch(struct rq *rq, struct task_struct *prev,
|
|
|
|
struct task_struct *next)
|
2005-06-25 21:57:23 +00:00
|
|
|
{
|
sched/core / kcov: avoid kcov_area during task switch
During a context switch, we first switch_mm() to the next task's mm,
then switch_to() that new task. This means that vmalloc'd regions which
had previously been faulted in can transiently disappear in the context
of the prev task.
Functions instrumented by KCOV may try to access a vmalloc'd kcov_area
during this window, and as the fault handling code is instrumented, this
results in a recursive fault.
We must avoid accessing any kcov_area during this window. We can do so
with a new flag in kcov_mode, set prior to switching the mm, and cleared
once the new task is live. Since task_struct::kcov_mode isn't always a
specific enum kcov_mode value, this is made an unsigned int.
The manipulation is hidden behind kcov_{prepare,finish}_switch() helpers,
which are empty for !CONFIG_KCOV kernels.
The code uses macros because I can't use static inline functions without a
circular include dependency between <linux/sched.h> and <linux/kcov.h>,
since the definition of task_struct uses things defined in <linux/kcov.h>
Link: http://lkml.kernel.org/r/20180504135535.53744-4-mark.rutland@arm.com
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-06-14 22:27:41 +00:00
|
|
|
kcov_prepare_switch(prev);
|
2013-09-22 14:20:54 +00:00
|
|
|
sched_info_switch(rq, prev, next);
|
2011-02-02 12:19:09 +00:00
|
|
|
perf_event_task_sched_out(prev, next);
|
rseq: Introduce restartable sequences system call
Expose a new system call allowing each thread to register one userspace
memory area to be used as an ABI between kernel and user-space for two
purposes: user-space restartable sequences and quick access to read the
current CPU number value from user-space.
* Restartable sequences (per-cpu atomics)
Restartables sequences allow user-space to perform update operations on
per-cpu data without requiring heavy-weight atomic operations.
The restartable critical sections (percpu atomics) work has been started
by Paul Turner and Andrew Hunter. It lets the kernel handle restart of
critical sections. [1] [2] The re-implementation proposed here brings a
few simplifications to the ABI which facilitates porting to other
architectures and speeds up the user-space fast path.
Here are benchmarks of various rseq use-cases.
Test hardware:
arm32: ARMv7 Processor rev 4 (v7l) "Cubietruck", 2-core
x86-64: Intel E5-2630 v3@2.40GHz, 16-core, hyperthreading
The following benchmarks were all performed on a single thread.
* Per-CPU statistic counter increment
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 344.0 31.4 11.0
x86-64: 15.3 2.0 7.7
* LTTng-UST: write event 32-bit header, 32-bit payload into tracer
per-cpu buffer
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 2502.0 2250.0 1.1
x86-64: 117.4 98.0 1.2
* liburcu percpu: lock-unlock pair, dereference, read/compare word
getcpu+atomic (ns/op) rseq (ns/op) speedup
arm32: 751.0 128.5 5.8
x86-64: 53.4 28.6 1.9
* jemalloc memory allocator adapted to use rseq
Using rseq with per-cpu memory pools in jemalloc at Facebook (based on
rseq 2016 implementation):
The production workload response-time has 1-2% gain avg. latency, and
the P99 overall latency drops by 2-3%.
* Reading the current CPU number
Speeding up reading the current CPU number on which the caller thread is
running is done by keeping the current CPU number up do date within the
cpu_id field of the memory area registered by the thread. This is done
by making scheduler preemption set the TIF_NOTIFY_RESUME flag on the
current thread. Upon return to user-space, a notify-resume handler
updates the current CPU value within the registered user-space memory
area. User-space can then read the current CPU number directly from
memory.
Keeping the current cpu id in a memory area shared between kernel and
user-space is an improvement over current mechanisms available to read
the current CPU number, which has the following benefits over
alternative approaches:
- 35x speedup on ARM vs system call through glibc
- 20x speedup on x86 compared to calling glibc, which calls vdso
executing a "lsl" instruction,
- 14x speedup on x86 compared to inlined "lsl" instruction,
- Unlike vdso approaches, this cpu_id value can be read from an inline
assembly, which makes it a useful building block for restartable
sequences.
- The approach of reading the cpu id through memory mapping shared
between kernel and user-space is portable (e.g. ARM), which is not the
case for the lsl-based x86 vdso.
On x86, yet another possible approach would be to use the gs segment
selector to point to user-space per-cpu data. This approach performs
similarly to the cpu id cache, but it has two disadvantages: it is
not portable, and it is incompatible with existing applications already
using the gs segment selector for other purposes.
Benchmarking various approaches for reading the current CPU number:
ARMv7 Processor rev 4 (v7l)
Machine model: Cubietruck
- Baseline (empty loop): 8.4 ns
- Read CPU from rseq cpu_id: 16.7 ns
- Read CPU from rseq cpu_id (lazy register): 19.8 ns
- glibc 2.19-0ubuntu6.6 getcpu: 301.8 ns
- getcpu system call: 234.9 ns
x86-64 Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz:
- Baseline (empty loop): 0.8 ns
- Read CPU from rseq cpu_id: 0.8 ns
- Read CPU from rseq cpu_id (lazy register): 0.8 ns
- Read using gs segment selector: 0.8 ns
- "lsl" inline assembly: 13.0 ns
- glibc 2.19-0ubuntu6 getcpu: 16.6 ns
- getcpu system call: 53.9 ns
- Speed (benchmark taken on v8 of patchset)
Running 10 runs of hackbench -l 100000 seems to indicate, contrary to
expectations, that enabling CONFIG_RSEQ slightly accelerates the
scheduler:
Configuration: 2 sockets * 8-core Intel(R) Xeon(R) CPU E5-2630 v3 @
2.40GHz (directly on hardware, hyperthreading disabled in BIOS, energy
saving disabled in BIOS, turboboost disabled in BIOS, cpuidle.off=1
kernel parameter), with a Linux v4.6 defconfig+localyesconfig,
restartable sequences series applied.
* CONFIG_RSEQ=n
avg.: 41.37 s
std.dev.: 0.36 s
* CONFIG_RSEQ=y
avg.: 40.46 s
std.dev.: 0.33 s
- Size
On x86-64, between CONFIG_RSEQ=n/y, the text size increase of vmlinux is
567 bytes, and the data size increase of vmlinux is 5696 bytes.
[1] https://lwn.net/Articles/650333/
[2] http://www.linuxplumbersconf.org/2013/ocw/system/presentations/1695/original/LPC%20-%20PerCpu%20Atomics.pdf
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Dave Watson <davejwatson@fb.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: "H . Peter Anvin" <hpa@zytor.com>
Cc: Chris Lameter <cl@linux.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Andrew Hunter <ahh@google.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: "Paul E . McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Ben Maurer <bmaurer@fb.com>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: linux-api@vger.kernel.org
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20151027235635.16059.11630.stgit@pjt-glaptop.roam.corp.google.com
Link: http://lkml.kernel.org/r/20150624222609.6116.86035.stgit@kitami.mtv.corp.google.com
Link: https://lkml.kernel.org/r/20180602124408.8430-3-mathieu.desnoyers@efficios.com
2018-06-02 12:43:54 +00:00
|
|
|
rseq_preempt(prev);
|
2007-07-26 11:40:43 +00:00
|
|
|
fire_sched_out_preempt_notifiers(prev, next);
|
2017-12-15 14:06:03 +00:00
|
|
|
prepare_task(next);
|
2005-06-25 21:57:23 +00:00
|
|
|
prepare_arch_switch(next);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* finish_task_switch - clean up after a task-switch
|
|
|
|
* @prev: the thread we just switched away from.
|
|
|
|
*
|
2005-06-25 21:57:23 +00:00
|
|
|
* finish_task_switch must be called after the context switch, paired
|
|
|
|
* with a prepare_task_switch call before the context switch.
|
|
|
|
* finish_task_switch will reconcile locking set up by prepare_task_switch,
|
|
|
|
* and do any other architecture-specific cleanup actions.
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* Note that we may have delayed dropping an mm in context_switch(). If
|
2007-12-05 14:46:09 +00:00
|
|
|
* so, we finish that here outside of the runqueue lock. (Doing it
|
2005-04-16 22:20:36 +00:00
|
|
|
* with the lock held can cause deadlocks; see schedule() for
|
|
|
|
* details.)
|
2014-10-09 19:32:32 +00:00
|
|
|
*
|
|
|
|
* The context switch have flipped the stack from under us and restored the
|
|
|
|
* local variables which were saved when this task called schedule() in the
|
|
|
|
* past. prev == current is still correct but we need to recalculate this_rq
|
|
|
|
* because prev may have moved to another CPU.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2014-10-09 19:32:32 +00:00
|
|
|
static struct rq *finish_task_switch(struct task_struct *prev)
|
2005-04-16 22:20:36 +00:00
|
|
|
__releases(rq->lock)
|
|
|
|
{
|
2014-10-09 19:32:32 +00:00
|
|
|
struct rq *rq = this_rq();
|
2005-04-16 22:20:36 +00:00
|
|
|
struct mm_struct *mm = rq->prev_mm;
|
2006-09-29 09:01:10 +00:00
|
|
|
long prev_state;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-09-28 15:52:18 +00:00
|
|
|
/*
|
|
|
|
* The previous task will have left us with a preempt_count of 2
|
|
|
|
* because it left us after:
|
|
|
|
*
|
|
|
|
* schedule()
|
|
|
|
* preempt_disable(); // 1
|
|
|
|
* __schedule()
|
|
|
|
* raw_spin_lock_irq(&rq->lock) // 2
|
|
|
|
*
|
|
|
|
* Also, see FORK_PREEMPT_COUNT.
|
|
|
|
*/
|
2015-09-29 10:18:46 +00:00
|
|
|
if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
|
|
|
|
"corrupted preempt_count: %s/%d/0x%x\n",
|
|
|
|
current->comm, current->pid, preempt_count()))
|
|
|
|
preempt_count_set(FORK_PREEMPT_COUNT);
|
2015-09-28 15:52:18 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
rq->prev_mm = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A task struct has one reference for the use as "current".
|
2006-09-29 09:01:11 +00:00
|
|
|
* If a task dies, then it sets TASK_DEAD in tsk->state and calls
|
2006-09-29 09:01:10 +00:00
|
|
|
* schedule one last time. The schedule call will never return, and
|
|
|
|
* the scheduled task must drop that reference.
|
2015-09-29 12:45:09 +00:00
|
|
|
*
|
|
|
|
* We must observe prev->state before clearing prev->on_cpu (in
|
2017-12-15 14:06:03 +00:00
|
|
|
* finish_task), otherwise a concurrent wakeup can get prev
|
2015-09-29 12:45:09 +00:00
|
|
|
* running on another CPU and we could rave with its RUNNING -> DEAD
|
|
|
|
* transition, resulting in a double drop.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2006-09-29 09:01:10 +00:00
|
|
|
prev_state = prev->state;
|
2012-09-08 13:23:11 +00:00
|
|
|
vtime_task_switch(prev);
|
perf events: Fix slow and broken cgroup context switch code
The current cgroup context switch code was incorrect leading
to bogus counts. Furthermore, as soon as there was an active
cgroup event on a CPU, the context switch cost on that CPU
would increase by a significant amount as demonstrated by a
simple ping/pong example:
$ ./pong
Both processes pinned to CPU1, running for 10s
10684.51 ctxsw/s
Now start a cgroup perf stat:
$ perf stat -e cycles,cycles -A -a -G test -C 1 -- sleep 100
$ ./pong
Both processes pinned to CPU1, running for 10s
6674.61 ctxsw/s
That's a 37% penalty.
Note that pong is not even in the monitored cgroup.
The results shown by perf stat are bogus:
$ perf stat -e cycles,cycles -A -a -G test -C 1 -- sleep 100
Performance counter stats for 'sleep 100':
CPU1 <not counted> cycles test
CPU1 16,984,189,138 cycles # 0.000 GHz
The second 'cycles' event should report a count @ CPU clock
(here 2.4GHz) as it is counting across all cgroups.
The patch below fixes the bogus accounting and bypasses any
cgroup switches in case the outgoing and incoming tasks are
in the same cgroup.
With this patch the same test now yields:
$ ./pong
Both processes pinned to CPU1, running for 10s
10775.30 ctxsw/s
Start perf stat with cgroup:
$ perf stat -e cycles,cycles -A -a -G test -C 1 -- sleep 10
Run pong outside the cgroup:
$ /pong
Both processes pinned to CPU1, running for 10s
10687.80 ctxsw/s
The penalty is now less than 2%.
And the results for perf stat are correct:
$ perf stat -e cycles,cycles -A -a -G test -C 1 -- sleep 10
Performance counter stats for 'sleep 10':
CPU1 <not counted> cycles test # 0.000 GHz
CPU1 23,933,981,448 cycles # 0.000 GHz
Now perf stat reports the correct counts for
for the non cgroup event.
If we run pong inside the cgroup, then we also get the
correct counts:
$ perf stat -e cycles,cycles -A -a -G test -C 1 -- sleep 10
Performance counter stats for 'sleep 10':
CPU1 22,297,726,205 cycles test # 0.000 GHz
CPU1 23,933,981,448 cycles # 0.000 GHz
10.001457237 seconds time elapsed
Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20110825135803.GA4697@quad
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-08-25 13:58:03 +00:00
|
|
|
perf_event_task_sched_in(prev, current);
|
2017-12-15 14:06:03 +00:00
|
|
|
finish_task(prev);
|
|
|
|
finish_lock_switch(rq);
|
2011-11-27 21:43:10 +00:00
|
|
|
finish_arch_post_lock_switch();
|
sched/core / kcov: avoid kcov_area during task switch
During a context switch, we first switch_mm() to the next task's mm,
then switch_to() that new task. This means that vmalloc'd regions which
had previously been faulted in can transiently disappear in the context
of the prev task.
Functions instrumented by KCOV may try to access a vmalloc'd kcov_area
during this window, and as the fault handling code is instrumented, this
results in a recursive fault.
We must avoid accessing any kcov_area during this window. We can do so
with a new flag in kcov_mode, set prior to switching the mm, and cleared
once the new task is live. Since task_struct::kcov_mode isn't always a
specific enum kcov_mode value, this is made an unsigned int.
The manipulation is hidden behind kcov_{prepare,finish}_switch() helpers,
which are empty for !CONFIG_KCOV kernels.
The code uses macros because I can't use static inline functions without a
circular include dependency between <linux/sched.h> and <linux/kcov.h>,
since the definition of task_struct uses things defined in <linux/kcov.h>
Link: http://lkml.kernel.org/r/20180504135535.53744-4-mark.rutland@arm.com
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-06-14 22:27:41 +00:00
|
|
|
kcov_finish_switch(current);
|
2008-01-25 20:08:05 +00:00
|
|
|
|
2007-07-26 11:40:43 +00:00
|
|
|
fire_sched_in_preempt_notifiers(current);
|
2018-01-29 20:20:12 +00:00
|
|
|
/*
|
2018-01-29 20:20:17 +00:00
|
|
|
* When switching through a kernel thread, the loop in
|
|
|
|
* membarrier_{private,global}_expedited() may have observed that
|
|
|
|
* kernel thread and not issued an IPI. It is therefore possible to
|
|
|
|
* schedule between user->kernel->user threads without passing though
|
|
|
|
* switch_mm(). Membarrier requires a barrier after storing to
|
|
|
|
* rq->curr, before returning to userspace, so provide them here:
|
|
|
|
*
|
|
|
|
* - a full memory barrier for {PRIVATE,GLOBAL}_EXPEDITED, implicitly
|
|
|
|
* provided by mmdrop(),
|
|
|
|
* - a sync_core for SYNC_CORE.
|
2018-01-29 20:20:12 +00:00
|
|
|
*/
|
2018-01-29 20:20:17 +00:00
|
|
|
if (mm) {
|
|
|
|
membarrier_mm_sync_core_before_usermode(mm);
|
2005-04-16 22:20:36 +00:00
|
|
|
mmdrop(mm);
|
2018-01-29 20:20:17 +00:00
|
|
|
}
|
2018-06-07 09:45:49 +00:00
|
|
|
if (unlikely(prev_state == TASK_DEAD)) {
|
|
|
|
if (prev->sched_class->task_dead)
|
|
|
|
prev->sched_class->task_dead(prev);
|
2016-09-16 05:45:48 +00:00
|
|
|
|
2018-06-07 09:45:49 +00:00
|
|
|
/*
|
|
|
|
* Remove function-return probe instances associated with this
|
|
|
|
* task and put them back on the free list.
|
|
|
|
*/
|
|
|
|
kprobe_flush_task(prev);
|
|
|
|
|
|
|
|
/* Task is done with its stack. */
|
|
|
|
put_task_stack(prev);
|
|
|
|
|
2019-09-14 12:33:58 +00:00
|
|
|
put_task_struct_rcu_user(prev);
|
2006-03-26 09:38:20 +00:00
|
|
|
}
|
2013-04-20 15:11:50 +00:00
|
|
|
|
2015-06-11 16:07:12 +00:00
|
|
|
tick_nohz_task_switch();
|
2014-10-09 19:32:32 +00:00
|
|
|
return rq;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2009-07-29 15:08:47 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
|
|
|
|
/* rq->lock is NOT held, but preemption is disabled */
|
2015-06-11 12:46:37 +00:00
|
|
|
static void __balance_callback(struct rq *rq)
|
2009-07-29 15:08:47 +00:00
|
|
|
{
|
2015-06-11 12:46:37 +00:00
|
|
|
struct callback_head *head, *next;
|
|
|
|
void (*func)(struct rq *rq);
|
|
|
|
unsigned long flags;
|
2009-07-29 15:08:47 +00:00
|
|
|
|
2015-06-11 12:46:37 +00:00
|
|
|
raw_spin_lock_irqsave(&rq->lock, flags);
|
|
|
|
head = rq->balance_callback;
|
|
|
|
rq->balance_callback = NULL;
|
|
|
|
while (head) {
|
|
|
|
func = (void (*)(struct rq *))head->func;
|
|
|
|
next = head->next;
|
|
|
|
head->next = NULL;
|
|
|
|
head = next;
|
2009-07-29 15:08:47 +00:00
|
|
|
|
2015-06-11 12:46:37 +00:00
|
|
|
func(rq);
|
2009-07-29 15:08:47 +00:00
|
|
|
}
|
2015-06-11 12:46:37 +00:00
|
|
|
raw_spin_unlock_irqrestore(&rq->lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void balance_callback(struct rq *rq)
|
|
|
|
{
|
|
|
|
if (unlikely(rq->balance_callback))
|
|
|
|
__balance_callback(rq);
|
2009-07-29 15:08:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2009-07-29 04:21:22 +00:00
|
|
|
|
2015-06-11 12:46:37 +00:00
|
|
|
static inline void balance_callback(struct rq *rq)
|
2009-07-29 15:08:47 +00:00
|
|
|
{
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2009-07-29 15:08:47 +00:00
|
|
|
#endif
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* schedule_tail - first thing a freshly forked thread must call.
|
|
|
|
* @prev: the thread we just switched away from.
|
|
|
|
*/
|
2014-05-01 22:44:38 +00:00
|
|
|
asmlinkage __visible void schedule_tail(struct task_struct *prev)
|
2005-04-16 22:20:36 +00:00
|
|
|
__releases(rq->lock)
|
|
|
|
{
|
2014-10-08 19:36:44 +00:00
|
|
|
struct rq *rq;
|
2009-07-29 04:21:22 +00:00
|
|
|
|
2015-09-28 15:52:18 +00:00
|
|
|
/*
|
|
|
|
* New tasks start with FORK_PREEMPT_COUNT, see there and
|
|
|
|
* finish_task_switch() for details.
|
|
|
|
*
|
|
|
|
* finish_task_switch() will drop rq->lock() and lower preempt_count
|
|
|
|
* and the preempt_enable() will end up enabling preemption (on
|
|
|
|
* PREEMPT_COUNT kernels).
|
|
|
|
*/
|
|
|
|
|
2014-10-09 19:32:32 +00:00
|
|
|
rq = finish_task_switch(prev);
|
2015-06-11 12:46:37 +00:00
|
|
|
balance_callback(rq);
|
2014-10-08 19:36:44 +00:00
|
|
|
preempt_enable();
|
2006-07-03 07:25:42 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
if (current->set_child_tid)
|
2007-10-19 06:40:14 +00:00
|
|
|
put_user(task_pid_vnr(current), current->set_child_tid);
|
2018-07-23 22:26:49 +00:00
|
|
|
|
|
|
|
calculate_sigpending();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-10-09 19:32:32 +00:00
|
|
|
* context_switch - switch to the new MM and the new thread's register state.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2016-02-29 04:22:39 +00:00
|
|
|
static __always_inline struct rq *
|
2006-07-03 07:25:42 +00:00
|
|
|
context_switch(struct rq *rq, struct task_struct *prev,
|
2016-09-21 13:38:10 +00:00
|
|
|
struct task_struct *next, struct rq_flags *rf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2007-07-26 11:40:43 +00:00
|
|
|
prepare_task_switch(rq, prev, next);
|
2011-02-02 12:19:09 +00:00
|
|
|
|
2007-02-13 12:26:21 +00:00
|
|
|
/*
|
|
|
|
* For paravirt, this is coupled with an exit in switch_to to
|
|
|
|
* combine the page table reload and the switch backend into
|
|
|
|
* one hypercall.
|
|
|
|
*/
|
2009-02-18 19:18:57 +00:00
|
|
|
arch_start_context_switch(prev);
|
2007-02-13 12:26:21 +00:00
|
|
|
|
2018-01-29 20:20:12 +00:00
|
|
|
/*
|
2019-07-29 14:05:15 +00:00
|
|
|
* kernel -> kernel lazy + transfer active
|
|
|
|
* user -> kernel lazy + mmgrab() active
|
|
|
|
*
|
|
|
|
* kernel -> user switch + mmdrop() active
|
|
|
|
* user -> user switch
|
2018-01-29 20:20:12 +00:00
|
|
|
*/
|
2019-07-29 14:05:15 +00:00
|
|
|
if (!next->mm) { // to kernel
|
|
|
|
enter_lazy_tlb(prev->active_mm, next);
|
|
|
|
|
|
|
|
next->active_mm = prev->active_mm;
|
|
|
|
if (prev->mm) // from user
|
|
|
|
mmgrab(prev->active_mm);
|
|
|
|
else
|
|
|
|
prev->active_mm = NULL;
|
|
|
|
} else { // to user
|
2019-09-19 17:37:02 +00:00
|
|
|
membarrier_switch_mm(rq, prev->active_mm, next->mm);
|
2019-07-29 14:05:15 +00:00
|
|
|
/*
|
|
|
|
* sys_membarrier() requires an smp_mb() between setting
|
2019-09-19 17:37:02 +00:00
|
|
|
* rq->curr / membarrier_switch_mm() and returning to userspace.
|
2019-07-29 14:05:15 +00:00
|
|
|
*
|
|
|
|
* The below provides this either through switch_mm(), or in
|
|
|
|
* case 'prev->active_mm == next->mm' through
|
|
|
|
* finish_task_switch()'s mmdrop().
|
|
|
|
*/
|
|
|
|
switch_mm_irqs_off(prev->active_mm, next->mm, next);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-07-29 14:05:15 +00:00
|
|
|
if (!prev->mm) { // from kernel
|
|
|
|
/* will mmdrop() in finish_task_switch(). */
|
|
|
|
rq->prev_mm = prev->active_mm;
|
|
|
|
prev->active_mm = NULL;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2016-09-21 13:38:11 +00:00
|
|
|
|
2016-09-21 13:38:13 +00:00
|
|
|
rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);
|
2016-09-21 13:38:11 +00:00
|
|
|
|
2018-02-06 16:52:13 +00:00
|
|
|
prepare_lock_switch(rq, next, rf);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* Here we just switch the register state and the stack. */
|
|
|
|
switch_to(prev, next, prev);
|
2007-07-09 16:51:59 +00:00
|
|
|
barrier();
|
2014-10-09 19:32:32 +00:00
|
|
|
|
|
|
|
return finish_task_switch(prev);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2013-02-20 09:14:38 +00:00
|
|
|
* nr_running and nr_context_switches:
|
2005-04-16 22:20:36 +00:00
|
|
|
*
|
|
|
|
* externally visible scheduler statistics: current number of runnable
|
2013-02-20 09:14:38 +00:00
|
|
|
* threads, total number of context switches performed since bootup.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
unsigned long nr_running(void)
|
|
|
|
{
|
|
|
|
unsigned long i, sum = 0;
|
|
|
|
|
|
|
|
for_each_online_cpu(i)
|
|
|
|
sum += cpu_rq(i)->nr_running;
|
|
|
|
|
|
|
|
return sum;
|
2009-04-14 04:55:30 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-07-31 17:29:48 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Check if only the current task is running on the CPU.
|
2015-09-18 09:27:45 +00:00
|
|
|
*
|
|
|
|
* Caution: this function does not check that the caller has disabled
|
|
|
|
* preemption, thus the result might have a time-of-check-to-time-of-use
|
|
|
|
* race. The caller is responsible to use it correctly, for example:
|
|
|
|
*
|
2018-12-03 09:05:56 +00:00
|
|
|
* - from a non-preemptible section (of course)
|
2015-09-18 09:27:45 +00:00
|
|
|
*
|
|
|
|
* - from a thread that is bound to a single CPU
|
|
|
|
*
|
|
|
|
* - in a loop with very short iterations (e.g. a polling loop)
|
2014-07-31 17:29:48 +00:00
|
|
|
*/
|
|
|
|
bool single_task_running(void)
|
|
|
|
{
|
2015-09-18 09:27:45 +00:00
|
|
|
return raw_rq()->nr_running == 1;
|
2014-07-31 17:29:48 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(single_task_running);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned long long nr_context_switches(void)
|
2007-05-08 07:32:51 +00:00
|
|
|
{
|
2006-06-27 09:54:31 +00:00
|
|
|
int i;
|
|
|
|
unsigned long long sum = 0;
|
2007-05-08 07:32:51 +00:00
|
|
|
|
2006-03-28 09:56:37 +00:00
|
|
|
for_each_possible_cpu(i)
|
2005-04-16 22:20:36 +00:00
|
|
|
sum += cpu_rq(i)->nr_switches;
|
2007-05-08 07:32:51 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return sum;
|
|
|
|
}
|
2009-02-04 19:59:44 +00:00
|
|
|
|
2018-10-04 12:04:02 +00:00
|
|
|
/*
|
|
|
|
* Consumers of these two interfaces, like for example the cpuidle menu
|
|
|
|
* governor, are using nonsensical data. Preferring shallow idle state selection
|
|
|
|
* for a CPU that has IO-wait which might not even end up running the task when
|
|
|
|
* it does become runnable.
|
|
|
|
*/
|
|
|
|
|
|
|
|
unsigned long nr_iowait_cpu(int cpu)
|
|
|
|
{
|
|
|
|
return atomic_read(&cpu_rq(cpu)->nr_iowait);
|
|
|
|
}
|
|
|
|
|
2016-12-07 20:48:41 +00:00
|
|
|
/*
|
|
|
|
* IO-wait accounting, and how its mostly bollocks (on SMP).
|
|
|
|
*
|
|
|
|
* The idea behind IO-wait account is to account the idle time that we could
|
|
|
|
* have spend running if it were not for IO. That is, if we were to improve the
|
|
|
|
* storage performance, we'd have a proportional reduction in IO-wait time.
|
|
|
|
*
|
|
|
|
* This all works nicely on UP, where, when a task blocks on IO, we account
|
|
|
|
* idle time as IO-wait, because if the storage were faster, it could've been
|
|
|
|
* running and we'd not be idle.
|
|
|
|
*
|
|
|
|
* This has been extended to SMP, by doing the same for each CPU. This however
|
|
|
|
* is broken.
|
|
|
|
*
|
|
|
|
* Imagine for instance the case where two tasks block on one CPU, only the one
|
|
|
|
* CPU will have IO-wait accounted, while the other has regular idle. Even
|
|
|
|
* though, if the storage were faster, both could've ran at the same time,
|
|
|
|
* utilising both CPUs.
|
|
|
|
*
|
|
|
|
* This means, that when looking globally, the current IO-wait accounting on
|
|
|
|
* SMP is a lower bound, by reason of under accounting.
|
|
|
|
*
|
|
|
|
* Worse, since the numbers are provided per CPU, they are sometimes
|
|
|
|
* interpreted per CPU, and that is nonsensical. A blocked task isn't strictly
|
|
|
|
* associated with any one particular CPU, it can wake to another CPU than it
|
|
|
|
* blocked on. This means the per CPU IO-wait number is meaningless.
|
|
|
|
*
|
|
|
|
* Task CPU affinities can make all that even more 'interesting'.
|
|
|
|
*/
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned long nr_iowait(void)
|
|
|
|
{
|
|
|
|
unsigned long i, sum = 0;
|
2009-02-04 19:59:44 +00:00
|
|
|
|
2006-03-28 09:56:37 +00:00
|
|
|
for_each_possible_cpu(i)
|
2018-10-04 12:04:02 +00:00
|
|
|
sum += nr_iowait_cpu(i);
|
2007-05-08 07:32:51 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return sum;
|
|
|
|
}
|
2009-02-04 19:59:44 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
#ifdef CONFIG_SMP
|
sched: don't rebalance if attached on NULL domain
Impact: fix function graph trace hang / drop pointless softirq on UP
While debugging a function graph trace hang on an old PII, I saw
that it consumed most of its time on the timer interrupt. And
the domain rebalancing softirq was the most concerned.
The timer interrupt calls trigger_load_balance() which will
decide if it is worth to schedule a rebalancing softirq.
In case of builtin UP kernel, no problem arises because there is
no domain question.
In case of builtin SMP kernel running on an SMP box, still no
problem, the softirq will be raised each time we reach the
next_balance time.
In case of builtin SMP kernel running on a UP box (most distros
provide default SMP kernels, whatever the box you have), then
the CPU is attached to the NULL sched domain. So a kind of
unexpected behaviour happen:
trigger_load_balance() -> raises the rebalancing softirq later
on softirq: run_rebalance_domains() -> rebalance_domains() where
the for_each_domain(cpu, sd) is not taken because of the NULL
domain we are attached at. Which means rq->next_balance is never
updated. So on the next timer tick, we will enter
trigger_load_balance() which will always reschedule() the
rebalacing softirq:
if (time_after_eq(jiffies, rq->next_balance))
raise_softirq(SCHED_SOFTIRQ);
So for each tick, we process this pointless softirq.
This patch fixes it by checking if we are attached to the null
domain before raising the softirq, another possible fix would be
to set the maximal possible JIFFIES value to rq->next_balance if
we are attached to the NULL domain.
v2: build fix on UP
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Peter Zijlstra <peterz@infradead.org>
LKML-Reference: <49af242d.1c07d00a.32d5.ffffc019@mx.google.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-03-05 00:27:02 +00:00
|
|
|
|
2007-05-08 07:32:51 +00:00
|
|
|
/*
|
2009-12-16 17:04:37 +00:00
|
|
|
* sched_exec - execve() is a valuable balancing opportunity, because at
|
|
|
|
* this point the task has the smallest effective memory and cache footprint.
|
2007-05-08 07:32:51 +00:00
|
|
|
*/
|
2009-12-16 17:04:37 +00:00
|
|
|
void sched_exec(void)
|
2007-05-08 07:32:51 +00:00
|
|
|
{
|
2009-12-16 17:04:37 +00:00
|
|
|
struct task_struct *p = current;
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned long flags;
|
2010-03-24 17:34:10 +00:00
|
|
|
int dest_cpu;
|
2007-05-08 07:32:51 +00:00
|
|
|
|
2011-04-05 15:23:53 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
2013-10-07 10:29:16 +00:00
|
|
|
dest_cpu = p->sched_class->select_task_rq(p, task_cpu(p), SD_BALANCE_EXEC, 0);
|
2010-03-24 17:34:10 +00:00
|
|
|
if (dest_cpu == smp_processor_id())
|
|
|
|
goto unlock;
|
2009-12-16 17:04:37 +00:00
|
|
|
|
2011-04-05 15:23:53 +00:00
|
|
|
if (likely(cpu_active(dest_cpu))) {
|
2010-05-06 16:49:21 +00:00
|
|
|
struct migration_arg arg = { p, dest_cpu };
|
2007-05-08 07:32:51 +00:00
|
|
|
|
2011-04-05 15:23:53 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
|
|
|
stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg);
|
2005-04-16 22:20:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-03-24 17:34:10 +00:00
|
|
|
unlock:
|
2011-04-05 15:23:53 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
DEFINE_PER_CPU(struct kernel_stat, kstat);
|
2011-11-28 16:45:17 +00:00
|
|
|
DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
EXPORT_PER_CPU_SYMBOL(kstat);
|
2011-11-28 16:45:17 +00:00
|
|
|
EXPORT_PER_CPU_SYMBOL(kernel_cpustat);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
sched/cputime: Mitigate performance regression in times()/clock_gettime()
Commit:
6e998916dfe3 ("sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency")
fixed a problem whereby clock_nanosleep() followed by clock_gettime() could
allow a task to wake early. It addressed the problem by calling the scheduling
classes update_curr() when the cputimer starts.
Said change induced a considerable performance regression on the syscalls
times() and clock_gettimes(CLOCK_PROCESS_CPUTIME_ID). There are some
debuggers and applications that monitor their own performance that
accidentally depend on the performance of these specific calls.
This patch mitigates the performace loss by prefetching data in the CPU
cache, as stalls due to cache misses appear to be where most time is spent
in our benchmarks.
Here are the performance gain of this patch over v4.7-rc7 on a Sandy Bridge
box with 32 logical cores and 2 NUMA nodes. The test is repeated with a
variable number of threads, from 2 to 4*num_cpus; the results are in
seconds and correspond to the average of 10 runs; the percentage gain is
computed with (before-after)/before so a positive value is an improvement
(it's faster). The improvement varies between a few percents for 5-20
threads and more than 10% for 2 or >20 threads.
pound_clock_gettime:
threads 4.7-rc7 patched 4.7-rc7
[num] [secs] [secs (percent)]
2 3.48 3.06 ( 11.83%)
5 3.33 3.25 ( 2.40%)
8 3.37 3.26 ( 3.30%)
12 3.32 3.37 ( -1.60%)
21 4.01 3.90 ( 2.74%)
30 3.63 3.36 ( 7.41%)
48 3.71 3.11 ( 16.27%)
79 3.75 3.16 ( 15.74%)
110 3.81 3.25 ( 14.80%)
128 3.88 3.31 ( 14.76%)
pound_times:
threads 4.7-rc7 patched 4.7-rc7
[num] [secs] [secs (percent)]
2 3.65 3.25 ( 11.03%)
5 3.45 3.17 ( 7.92%)
8 3.52 3.22 ( 8.69%)
12 3.29 3.36 ( -2.04%)
21 4.07 3.92 ( 3.78%)
30 3.87 3.40 ( 12.17%)
48 3.79 3.16 ( 16.61%)
79 3.88 3.28 ( 15.42%)
110 3.90 3.38 ( 13.35%)
128 4.00 3.38 ( 15.45%)
pound_clock_gettime and pound_clock_gettime are two benchmarks included in
the MMTests framework. They launch a given number of threads which
repeatedly call times() or clock_gettimes(). The results above can be
reproduced with cloning MMTests from github.com and running the "poundtime"
workload:
$ git clone https://github.com/gormanm/mmtests.git
$ cd mmtests
$ cp configs/config-global-dhp__workload_poundtime config
$ ./run-mmtests.sh --run-monitor $(uname -r)
The above will run "poundtime" measuring the kernel currently running on
the machine; Once a new kernel is installed and the machine rebooted,
running again
$ cd mmtests
$ ./run-mmtests.sh --run-monitor $(uname -r)
will produce results to compare with. A comparison table will be output
with:
$ cd mmtests/work/log
$ ../../compare-kernels.sh
the table will contain a lot of entries; grepping for "Amean" (as in
"arithmetic mean") will give the tables presented above. The source code
for the two benchmarks is reported at the end of this changelog for
clairity.
The cache misses addressed by this patch were found using a combination of
`perf top`, `perf record` and `perf annotate`. The incriminated lines were
found to be
struct sched_entity *curr = cfs_rq->curr;
and
delta_exec = now - curr->exec_start;
in the function update_curr() from kernel/sched/fair.c. This patch
prefetches the data from memory just before update_curr is called in the
interested execution path.
A comparison of the total number of cycles before and after the patch
follows; the data is obtained using `perf stat -r 10 -ddd <program>`
running over the same sequence of number of threads used above (a positive
gain is an improvement):
threads cycles before cycles after gain
2 19,699,563,964 +-1.19% 17,358,917,517 +-1.85% 11.88%
5 47,401,089,566 +-2.96% 45,103,730,829 +-0.97% 4.85%
8 80,923,501,004 +-3.01% 71,419,385,977 +-0.77% 11.74%
12 112,326,485,473 +-0.47% 110,371,524,403 +-0.47% 1.74%
21 193,455,574,299 +-0.72% 180,120,667,904 +-0.36% 6.89%
30 315,073,519,013 +-1.64% 271,222,225,950 +-1.29% 13.92%
48 321,969,515,332 +-1.48% 273,353,977,321 +-1.16% 15.10%
79 337,866,003,422 +-0.97% 289,462,481,538 +-1.05% 14.33%
110 338,712,691,920 +-0.78% 290,574,233,170 +-0.77% 14.21%
128 348,384,794,006 +-0.50% 292,691,648,206 +-0.66% 15.99%
A comparison of cache miss vs total cache loads ratios, before and after
the patch (again from the `perf stat -r 10 -ddd <program>` tables):
threads L1 misses/total*100 L1 misses/total*100 gain
before after
2 7.43 +-4.90% 7.36 +-4.70% 0.94%
5 13.09 +-4.74% 13.52 +-3.73% -3.28%
8 13.79 +-5.61% 12.90 +-3.27% 6.45%
12 11.57 +-2.44% 8.71 +-1.40% 24.72%
21 12.39 +-3.92% 9.97 +-1.84% 19.53%
30 13.91 +-2.53% 11.73 +-2.28% 15.67%
48 13.71 +-1.59% 12.32 +-1.97% 10.14%
79 14.44 +-0.66% 13.40 +-1.06% 7.20%
110 15.86 +-0.50% 14.46 +-0.59% 8.83%
128 16.51 +-0.32% 15.06 +-0.78% 8.78%
As a final note, the following shows the evolution of performance figures
in the "poundtime" benchmark and pinpoints commit 6e998916dfe3
("sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency") as a
major source of degradation, mostly unaddressed to this day (figures
expressed in seconds).
pound_clock_gettime:
threads parent of 6e998916dfe3 4.7-rc7
6e998916dfe3 itself
2 2.23 3.68 ( -64.56%) 3.48 (-55.48%)
5 2.83 3.78 ( -33.42%) 3.33 (-17.43%)
8 2.84 4.31 ( -52.12%) 3.37 (-18.76%)
12 3.09 3.61 ( -16.74%) 3.32 ( -7.17%)
21 3.14 4.63 ( -47.36%) 4.01 (-27.71%)
30 3.28 5.75 ( -75.37%) 3.63 (-10.80%)
48 3.02 6.05 (-100.56%) 3.71 (-22.99%)
79 2.88 6.30 (-118.90%) 3.75 (-30.26%)
110 2.95 6.46 (-119.00%) 3.81 (-29.24%)
128 3.05 6.42 (-110.08%) 3.88 (-27.04%)
pound_times:
threads parent of 6e998916dfe3 4.7-rc7
6e998916dfe3 itself
2 2.27 3.73 ( -64.71%) 3.65 (-61.14%)
5 2.78 3.77 ( -35.56%) 3.45 (-23.98%)
8 2.79 4.41 ( -57.71%) 3.52 (-26.05%)
12 3.02 3.56 ( -17.94%) 3.29 ( -9.08%)
21 3.10 4.61 ( -48.74%) 4.07 (-31.34%)
30 3.33 5.75 ( -72.53%) 3.87 (-16.01%)
48 2.96 6.06 (-105.04%) 3.79 (-28.10%)
79 2.88 6.24 (-116.83%) 3.88 (-34.81%)
110 2.98 6.37 (-114.08%) 3.90 (-31.12%)
128 3.10 6.35 (-104.61%) 4.00 (-28.87%)
The source code of the two benchmarks follows. To compile the two:
NR_THREADS=42
for FILE in pound_times pound_clock_gettime; do
gcc -lrt -O2 -lpthread -DNUM_THREADS=$NR_THREADS $FILE.c -o $FILE
done
==== BEGIN pound_times.c ====
struct tms start;
void *pound (void *threadid)
{
struct tms end;
int oldutime = 0;
int utime;
int i;
for (i = 0; i < 5000000 / NUM_THREADS; i++) {
times(&end);
utime = ((int)end.tms_utime - (int)start.tms_utime);
if (oldutime > utime) {
printf("utime decreased, was %d, now %d!\n", oldutime, utime);
}
oldutime = utime;
}
pthread_exit(NULL);
}
int main()
{
pthread_t th[NUM_THREADS];
long i;
times(&start);
for (i = 0; i < NUM_THREADS; i++) {
pthread_create (&th[i], NULL, pound, (void *)i);
}
pthread_exit(NULL);
return 0;
}
==== END pound_times.c ====
==== BEGIN pound_clock_gettime.c ====
void *pound (void *threadid)
{
struct timespec ts;
int rc, i;
unsigned long prev = 0, this = 0;
for (i = 0; i < 5000000 / NUM_THREADS; i++) {
rc = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
if (rc < 0)
perror("clock_gettime");
this = (ts.tv_sec * 1000000000) + ts.tv_nsec;
if (0 && this < prev)
printf("%lu ns timewarp at iteration %d\n", prev - this, i);
prev = this;
}
pthread_exit(NULL);
}
int main()
{
pthread_t th[NUM_THREADS];
long rc, i;
pid_t pgid;
for (i = 0; i < NUM_THREADS; i++) {
rc = pthread_create(&th[i], NULL, pound, (void *)i);
if (rc < 0)
perror("pthread_create");
}
pthread_exit(NULL);
return 0;
}
==== END pound_clock_gettime.c ====
Suggested-by: Mike Galbraith <mgalbraith@suse.de>
Signed-off-by: Giovanni Gherdovich <ggherdovich@suse.cz>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1470385316-15027-2-git-send-email-ggherdovich@suse.cz
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-05 08:21:56 +00:00
|
|
|
/*
|
|
|
|
* The function fair_sched_class.update_curr accesses the struct curr
|
|
|
|
* and its field curr->exec_start; when called from task_sched_runtime(),
|
|
|
|
* we observe a high rate of cache misses in practice.
|
|
|
|
* Prefetching this data results in improved performance.
|
|
|
|
*/
|
|
|
|
static inline void prefetch_curr_exec_start(struct task_struct *p)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
|
|
|
struct sched_entity *curr = (&p->se)->cfs_rq->curr;
|
|
|
|
#else
|
|
|
|
struct sched_entity *curr = (&task_rq(p)->cfs)->curr;
|
|
|
|
#endif
|
|
|
|
prefetch(curr);
|
|
|
|
prefetch(&curr->exec_start);
|
|
|
|
}
|
|
|
|
|
2009-03-31 07:56:03 +00:00
|
|
|
/*
|
|
|
|
* Return accounted runtime for the task.
|
|
|
|
* In case the task is currently running, return the runtime plus current's
|
|
|
|
* pending runtime that have not been accounted yet.
|
|
|
|
*/
|
|
|
|
unsigned long long task_sched_runtime(struct task_struct *p)
|
|
|
|
{
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2009-03-31 07:56:03 +00:00
|
|
|
struct rq *rq;
|
sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency
Commit d670ec13178d0 "posix-cpu-timers: Cure SMP wobbles" fixes one glibc
test case in cost of breaking another one. After that commit, calling
clock_nanosleep(TIMER_ABSTIME, X) and then clock_gettime(&Y) can result
of Y time being smaller than X time.
Reproducer/tester can be found further below, it can be compiled and ran by:
gcc -o tst-cpuclock2 tst-cpuclock2.c -pthread
while ./tst-cpuclock2 ; do : ; done
This reproducer, when running on a buggy kernel, will complain
about "clock_gettime difference too small".
Issue happens because on start in thread_group_cputimer() we initialize
sum_exec_runtime of cputimer with threads runtime not yet accounted and
then add the threads runtime to running cputimer again on scheduler
tick, making it's sum_exec_runtime bigger than actual threads runtime.
KOSAKI Motohiro posted a fix for this problem, but that patch was never
applied: https://lkml.org/lkml/2013/5/26/191 .
This patch takes different approach to cure the problem. It calls
update_curr() when cputimer starts, that assure we will have updated
stats of running threads and on the next schedule tick we will account
only the runtime that elapsed from cputimer start. That also assure we
have consistent state between cpu times of individual threads and cpu
time of the process consisted by those threads.
Full reproducer (tst-cpuclock2.c):
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <stdint.h>
#include <inttypes.h>
/* Parameters for the Linux kernel ABI for CPU clocks. */
#define CPUCLOCK_SCHED 2
#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
static pthread_barrier_t barrier;
/* Help advance the clock. */
static void *chew_cpu(void *arg)
{
pthread_barrier_wait(&barrier);
while (1) ;
return NULL;
}
/* Don't use the glibc wrapper. */
static int do_nanosleep(int flags, const struct timespec *req)
{
clockid_t clock_id = MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED);
return syscall(SYS_clock_nanosleep, clock_id, flags, req, NULL);
}
static int64_t tsdiff(const struct timespec *before, const struct timespec *after)
{
int64_t before_i = before->tv_sec * 1000000000ULL + before->tv_nsec;
int64_t after_i = after->tv_sec * 1000000000ULL + after->tv_nsec;
return after_i - before_i;
}
int main(void)
{
int result = 0;
pthread_t th;
pthread_barrier_init(&barrier, NULL, 2);
if (pthread_create(&th, NULL, chew_cpu, NULL) != 0) {
perror("pthread_create");
return 1;
}
pthread_barrier_wait(&barrier);
/* The test. */
struct timespec before, after, sleeptimeabs;
int64_t sleepdiff, diffabs;
const struct timespec sleeptime = {.tv_sec = 0,.tv_nsec = 100000000 };
/* The relative nanosleep. Not sure why this is needed, but its presence
seems to make it easier to reproduce the problem. */
if (do_nanosleep(0, &sleeptime) != 0) {
perror("clock_nanosleep");
return 1;
}
/* Get the current time. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &before) < 0) {
perror("clock_gettime[2]");
return 1;
}
/* Compute the absolute sleep time based on the current time. */
uint64_t nsec = before.tv_nsec + sleeptime.tv_nsec;
sleeptimeabs.tv_sec = before.tv_sec + nsec / 1000000000;
sleeptimeabs.tv_nsec = nsec % 1000000000;
/* Sleep for the computed time. */
if (do_nanosleep(TIMER_ABSTIME, &sleeptimeabs) != 0) {
perror("absolute clock_nanosleep");
return 1;
}
/* Get the time after the sleep. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &after) < 0) {
perror("clock_gettime[3]");
return 1;
}
/* The time after sleep should always be equal to or after the absolute sleep
time passed to clock_nanosleep. */
sleepdiff = tsdiff(&sleeptimeabs, &after);
if (sleepdiff < 0) {
printf("absolute clock_nanosleep woke too early: %" PRId64 "\n", sleepdiff);
result = 1;
printf("Before %llu.%09llu\n", before.tv_sec, before.tv_nsec);
printf("After %llu.%09llu\n", after.tv_sec, after.tv_nsec);
printf("Sleep %llu.%09llu\n", sleeptimeabs.tv_sec, sleeptimeabs.tv_nsec);
}
/* The difference between the timestamps taken before and after the
clock_nanosleep call should be equal to or more than the duration of the
sleep. */
diffabs = tsdiff(&before, &after);
if (diffabs < sleeptime.tv_nsec) {
printf("clock_gettime difference too small: %" PRId64 "\n", diffabs);
result = 1;
}
pthread_cancel(th);
return result;
}
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20141112155843.GA24803@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-11-12 15:58:44 +00:00
|
|
|
u64 ns;
|
2009-03-31 07:56:03 +00:00
|
|
|
|
2013-11-11 17:21:56 +00:00
|
|
|
#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
|
|
|
|
/*
|
sched: Clean up and harmonize the coding style of the scheduler code base
A good number of small style inconsistencies have accumulated
in the scheduler core, so do a pass over them to harmonize
all these details:
- fix speling in comments,
- use curly braces for multi-line statements,
- remove unnecessary parentheses from integer literals,
- capitalize consistently,
- remove stray newlines,
- add comments where necessary,
- remove invalid/unnecessary comments,
- align structure definitions and other data types vertically,
- add missing newlines for increased readability,
- fix vertical tabulation where it's misaligned,
- harmonize preprocessor conditional block labeling
and vertical alignment,
- remove line-breaks where they uglify the code,
- add newline after local variable definitions,
No change in functionality:
md5:
1191fa0a890cfa8132156d2959d7e9e2 built-in.o.before.asm
1191fa0a890cfa8132156d2959d7e9e2 built-in.o.after.asm
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2018-03-03 13:01:12 +00:00
|
|
|
* 64-bit doesn't need locks to atomically read a 64-bit value.
|
2013-11-11 17:21:56 +00:00
|
|
|
* So we have a optimization chance when the task's delta_exec is 0.
|
|
|
|
* Reading ->on_cpu is racy, but this is ok.
|
|
|
|
*
|
2017-02-01 10:46:42 +00:00
|
|
|
* If we race with it leaving CPU, we'll take a lock. So we're correct.
|
|
|
|
* If we race with it entering CPU, unaccounted time is 0. This is
|
2013-11-11 17:21:56 +00:00
|
|
|
* indistinguishable from the read occurring a few cycles earlier.
|
2014-06-24 05:49:40 +00:00
|
|
|
* If we see ->on_cpu without ->on_rq, the task is leaving, and has
|
|
|
|
* been accounted, so we're correct here as well.
|
2013-11-11 17:21:56 +00:00
|
|
|
*/
|
2014-08-20 09:47:32 +00:00
|
|
|
if (!p->on_cpu || !task_on_rq_queued(p))
|
2013-11-11 17:21:56 +00:00
|
|
|
return p->se.sum_exec_runtime;
|
|
|
|
#endif
|
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency
Commit d670ec13178d0 "posix-cpu-timers: Cure SMP wobbles" fixes one glibc
test case in cost of breaking another one. After that commit, calling
clock_nanosleep(TIMER_ABSTIME, X) and then clock_gettime(&Y) can result
of Y time being smaller than X time.
Reproducer/tester can be found further below, it can be compiled and ran by:
gcc -o tst-cpuclock2 tst-cpuclock2.c -pthread
while ./tst-cpuclock2 ; do : ; done
This reproducer, when running on a buggy kernel, will complain
about "clock_gettime difference too small".
Issue happens because on start in thread_group_cputimer() we initialize
sum_exec_runtime of cputimer with threads runtime not yet accounted and
then add the threads runtime to running cputimer again on scheduler
tick, making it's sum_exec_runtime bigger than actual threads runtime.
KOSAKI Motohiro posted a fix for this problem, but that patch was never
applied: https://lkml.org/lkml/2013/5/26/191 .
This patch takes different approach to cure the problem. It calls
update_curr() when cputimer starts, that assure we will have updated
stats of running threads and on the next schedule tick we will account
only the runtime that elapsed from cputimer start. That also assure we
have consistent state between cpu times of individual threads and cpu
time of the process consisted by those threads.
Full reproducer (tst-cpuclock2.c):
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <stdint.h>
#include <inttypes.h>
/* Parameters for the Linux kernel ABI for CPU clocks. */
#define CPUCLOCK_SCHED 2
#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
static pthread_barrier_t barrier;
/* Help advance the clock. */
static void *chew_cpu(void *arg)
{
pthread_barrier_wait(&barrier);
while (1) ;
return NULL;
}
/* Don't use the glibc wrapper. */
static int do_nanosleep(int flags, const struct timespec *req)
{
clockid_t clock_id = MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED);
return syscall(SYS_clock_nanosleep, clock_id, flags, req, NULL);
}
static int64_t tsdiff(const struct timespec *before, const struct timespec *after)
{
int64_t before_i = before->tv_sec * 1000000000ULL + before->tv_nsec;
int64_t after_i = after->tv_sec * 1000000000ULL + after->tv_nsec;
return after_i - before_i;
}
int main(void)
{
int result = 0;
pthread_t th;
pthread_barrier_init(&barrier, NULL, 2);
if (pthread_create(&th, NULL, chew_cpu, NULL) != 0) {
perror("pthread_create");
return 1;
}
pthread_barrier_wait(&barrier);
/* The test. */
struct timespec before, after, sleeptimeabs;
int64_t sleepdiff, diffabs;
const struct timespec sleeptime = {.tv_sec = 0,.tv_nsec = 100000000 };
/* The relative nanosleep. Not sure why this is needed, but its presence
seems to make it easier to reproduce the problem. */
if (do_nanosleep(0, &sleeptime) != 0) {
perror("clock_nanosleep");
return 1;
}
/* Get the current time. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &before) < 0) {
perror("clock_gettime[2]");
return 1;
}
/* Compute the absolute sleep time based on the current time. */
uint64_t nsec = before.tv_nsec + sleeptime.tv_nsec;
sleeptimeabs.tv_sec = before.tv_sec + nsec / 1000000000;
sleeptimeabs.tv_nsec = nsec % 1000000000;
/* Sleep for the computed time. */
if (do_nanosleep(TIMER_ABSTIME, &sleeptimeabs) != 0) {
perror("absolute clock_nanosleep");
return 1;
}
/* Get the time after the sleep. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &after) < 0) {
perror("clock_gettime[3]");
return 1;
}
/* The time after sleep should always be equal to or after the absolute sleep
time passed to clock_nanosleep. */
sleepdiff = tsdiff(&sleeptimeabs, &after);
if (sleepdiff < 0) {
printf("absolute clock_nanosleep woke too early: %" PRId64 "\n", sleepdiff);
result = 1;
printf("Before %llu.%09llu\n", before.tv_sec, before.tv_nsec);
printf("After %llu.%09llu\n", after.tv_sec, after.tv_nsec);
printf("Sleep %llu.%09llu\n", sleeptimeabs.tv_sec, sleeptimeabs.tv_nsec);
}
/* The difference between the timestamps taken before and after the
clock_nanosleep call should be equal to or more than the duration of the
sleep. */
diffabs = tsdiff(&before, &after);
if (diffabs < sleeptime.tv_nsec) {
printf("clock_gettime difference too small: %" PRId64 "\n", diffabs);
result = 1;
}
pthread_cancel(th);
return result;
}
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20141112155843.GA24803@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-11-12 15:58:44 +00:00
|
|
|
/*
|
|
|
|
* Must be ->curr _and_ ->on_rq. If dequeued, we would
|
|
|
|
* project cycles that may never be accounted to this
|
|
|
|
* thread, breaking clock_gettime().
|
|
|
|
*/
|
|
|
|
if (task_current(rq, p) && task_on_rq_queued(p)) {
|
sched/cputime: Mitigate performance regression in times()/clock_gettime()
Commit:
6e998916dfe3 ("sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency")
fixed a problem whereby clock_nanosleep() followed by clock_gettime() could
allow a task to wake early. It addressed the problem by calling the scheduling
classes update_curr() when the cputimer starts.
Said change induced a considerable performance regression on the syscalls
times() and clock_gettimes(CLOCK_PROCESS_CPUTIME_ID). There are some
debuggers and applications that monitor their own performance that
accidentally depend on the performance of these specific calls.
This patch mitigates the performace loss by prefetching data in the CPU
cache, as stalls due to cache misses appear to be where most time is spent
in our benchmarks.
Here are the performance gain of this patch over v4.7-rc7 on a Sandy Bridge
box with 32 logical cores and 2 NUMA nodes. The test is repeated with a
variable number of threads, from 2 to 4*num_cpus; the results are in
seconds and correspond to the average of 10 runs; the percentage gain is
computed with (before-after)/before so a positive value is an improvement
(it's faster). The improvement varies between a few percents for 5-20
threads and more than 10% for 2 or >20 threads.
pound_clock_gettime:
threads 4.7-rc7 patched 4.7-rc7
[num] [secs] [secs (percent)]
2 3.48 3.06 ( 11.83%)
5 3.33 3.25 ( 2.40%)
8 3.37 3.26 ( 3.30%)
12 3.32 3.37 ( -1.60%)
21 4.01 3.90 ( 2.74%)
30 3.63 3.36 ( 7.41%)
48 3.71 3.11 ( 16.27%)
79 3.75 3.16 ( 15.74%)
110 3.81 3.25 ( 14.80%)
128 3.88 3.31 ( 14.76%)
pound_times:
threads 4.7-rc7 patched 4.7-rc7
[num] [secs] [secs (percent)]
2 3.65 3.25 ( 11.03%)
5 3.45 3.17 ( 7.92%)
8 3.52 3.22 ( 8.69%)
12 3.29 3.36 ( -2.04%)
21 4.07 3.92 ( 3.78%)
30 3.87 3.40 ( 12.17%)
48 3.79 3.16 ( 16.61%)
79 3.88 3.28 ( 15.42%)
110 3.90 3.38 ( 13.35%)
128 4.00 3.38 ( 15.45%)
pound_clock_gettime and pound_clock_gettime are two benchmarks included in
the MMTests framework. They launch a given number of threads which
repeatedly call times() or clock_gettimes(). The results above can be
reproduced with cloning MMTests from github.com and running the "poundtime"
workload:
$ git clone https://github.com/gormanm/mmtests.git
$ cd mmtests
$ cp configs/config-global-dhp__workload_poundtime config
$ ./run-mmtests.sh --run-monitor $(uname -r)
The above will run "poundtime" measuring the kernel currently running on
the machine; Once a new kernel is installed and the machine rebooted,
running again
$ cd mmtests
$ ./run-mmtests.sh --run-monitor $(uname -r)
will produce results to compare with. A comparison table will be output
with:
$ cd mmtests/work/log
$ ../../compare-kernels.sh
the table will contain a lot of entries; grepping for "Amean" (as in
"arithmetic mean") will give the tables presented above. The source code
for the two benchmarks is reported at the end of this changelog for
clairity.
The cache misses addressed by this patch were found using a combination of
`perf top`, `perf record` and `perf annotate`. The incriminated lines were
found to be
struct sched_entity *curr = cfs_rq->curr;
and
delta_exec = now - curr->exec_start;
in the function update_curr() from kernel/sched/fair.c. This patch
prefetches the data from memory just before update_curr is called in the
interested execution path.
A comparison of the total number of cycles before and after the patch
follows; the data is obtained using `perf stat -r 10 -ddd <program>`
running over the same sequence of number of threads used above (a positive
gain is an improvement):
threads cycles before cycles after gain
2 19,699,563,964 +-1.19% 17,358,917,517 +-1.85% 11.88%
5 47,401,089,566 +-2.96% 45,103,730,829 +-0.97% 4.85%
8 80,923,501,004 +-3.01% 71,419,385,977 +-0.77% 11.74%
12 112,326,485,473 +-0.47% 110,371,524,403 +-0.47% 1.74%
21 193,455,574,299 +-0.72% 180,120,667,904 +-0.36% 6.89%
30 315,073,519,013 +-1.64% 271,222,225,950 +-1.29% 13.92%
48 321,969,515,332 +-1.48% 273,353,977,321 +-1.16% 15.10%
79 337,866,003,422 +-0.97% 289,462,481,538 +-1.05% 14.33%
110 338,712,691,920 +-0.78% 290,574,233,170 +-0.77% 14.21%
128 348,384,794,006 +-0.50% 292,691,648,206 +-0.66% 15.99%
A comparison of cache miss vs total cache loads ratios, before and after
the patch (again from the `perf stat -r 10 -ddd <program>` tables):
threads L1 misses/total*100 L1 misses/total*100 gain
before after
2 7.43 +-4.90% 7.36 +-4.70% 0.94%
5 13.09 +-4.74% 13.52 +-3.73% -3.28%
8 13.79 +-5.61% 12.90 +-3.27% 6.45%
12 11.57 +-2.44% 8.71 +-1.40% 24.72%
21 12.39 +-3.92% 9.97 +-1.84% 19.53%
30 13.91 +-2.53% 11.73 +-2.28% 15.67%
48 13.71 +-1.59% 12.32 +-1.97% 10.14%
79 14.44 +-0.66% 13.40 +-1.06% 7.20%
110 15.86 +-0.50% 14.46 +-0.59% 8.83%
128 16.51 +-0.32% 15.06 +-0.78% 8.78%
As a final note, the following shows the evolution of performance figures
in the "poundtime" benchmark and pinpoints commit 6e998916dfe3
("sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency") as a
major source of degradation, mostly unaddressed to this day (figures
expressed in seconds).
pound_clock_gettime:
threads parent of 6e998916dfe3 4.7-rc7
6e998916dfe3 itself
2 2.23 3.68 ( -64.56%) 3.48 (-55.48%)
5 2.83 3.78 ( -33.42%) 3.33 (-17.43%)
8 2.84 4.31 ( -52.12%) 3.37 (-18.76%)
12 3.09 3.61 ( -16.74%) 3.32 ( -7.17%)
21 3.14 4.63 ( -47.36%) 4.01 (-27.71%)
30 3.28 5.75 ( -75.37%) 3.63 (-10.80%)
48 3.02 6.05 (-100.56%) 3.71 (-22.99%)
79 2.88 6.30 (-118.90%) 3.75 (-30.26%)
110 2.95 6.46 (-119.00%) 3.81 (-29.24%)
128 3.05 6.42 (-110.08%) 3.88 (-27.04%)
pound_times:
threads parent of 6e998916dfe3 4.7-rc7
6e998916dfe3 itself
2 2.27 3.73 ( -64.71%) 3.65 (-61.14%)
5 2.78 3.77 ( -35.56%) 3.45 (-23.98%)
8 2.79 4.41 ( -57.71%) 3.52 (-26.05%)
12 3.02 3.56 ( -17.94%) 3.29 ( -9.08%)
21 3.10 4.61 ( -48.74%) 4.07 (-31.34%)
30 3.33 5.75 ( -72.53%) 3.87 (-16.01%)
48 2.96 6.06 (-105.04%) 3.79 (-28.10%)
79 2.88 6.24 (-116.83%) 3.88 (-34.81%)
110 2.98 6.37 (-114.08%) 3.90 (-31.12%)
128 3.10 6.35 (-104.61%) 4.00 (-28.87%)
The source code of the two benchmarks follows. To compile the two:
NR_THREADS=42
for FILE in pound_times pound_clock_gettime; do
gcc -lrt -O2 -lpthread -DNUM_THREADS=$NR_THREADS $FILE.c -o $FILE
done
==== BEGIN pound_times.c ====
struct tms start;
void *pound (void *threadid)
{
struct tms end;
int oldutime = 0;
int utime;
int i;
for (i = 0; i < 5000000 / NUM_THREADS; i++) {
times(&end);
utime = ((int)end.tms_utime - (int)start.tms_utime);
if (oldutime > utime) {
printf("utime decreased, was %d, now %d!\n", oldutime, utime);
}
oldutime = utime;
}
pthread_exit(NULL);
}
int main()
{
pthread_t th[NUM_THREADS];
long i;
times(&start);
for (i = 0; i < NUM_THREADS; i++) {
pthread_create (&th[i], NULL, pound, (void *)i);
}
pthread_exit(NULL);
return 0;
}
==== END pound_times.c ====
==== BEGIN pound_clock_gettime.c ====
void *pound (void *threadid)
{
struct timespec ts;
int rc, i;
unsigned long prev = 0, this = 0;
for (i = 0; i < 5000000 / NUM_THREADS; i++) {
rc = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
if (rc < 0)
perror("clock_gettime");
this = (ts.tv_sec * 1000000000) + ts.tv_nsec;
if (0 && this < prev)
printf("%lu ns timewarp at iteration %d\n", prev - this, i);
prev = this;
}
pthread_exit(NULL);
}
int main()
{
pthread_t th[NUM_THREADS];
long rc, i;
pid_t pgid;
for (i = 0; i < NUM_THREADS; i++) {
rc = pthread_create(&th[i], NULL, pound, (void *)i);
if (rc < 0)
perror("pthread_create");
}
pthread_exit(NULL);
return 0;
}
==== END pound_clock_gettime.c ====
Suggested-by: Mike Galbraith <mgalbraith@suse.de>
Signed-off-by: Giovanni Gherdovich <ggherdovich@suse.cz>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stanislaw Gruszka <sgruszka@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1470385316-15027-2-git-send-email-ggherdovich@suse.cz
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-05 08:21:56 +00:00
|
|
|
prefetch_curr_exec_start(p);
|
sched/cputime: Fix clock_nanosleep()/clock_gettime() inconsistency
Commit d670ec13178d0 "posix-cpu-timers: Cure SMP wobbles" fixes one glibc
test case in cost of breaking another one. After that commit, calling
clock_nanosleep(TIMER_ABSTIME, X) and then clock_gettime(&Y) can result
of Y time being smaller than X time.
Reproducer/tester can be found further below, it can be compiled and ran by:
gcc -o tst-cpuclock2 tst-cpuclock2.c -pthread
while ./tst-cpuclock2 ; do : ; done
This reproducer, when running on a buggy kernel, will complain
about "clock_gettime difference too small".
Issue happens because on start in thread_group_cputimer() we initialize
sum_exec_runtime of cputimer with threads runtime not yet accounted and
then add the threads runtime to running cputimer again on scheduler
tick, making it's sum_exec_runtime bigger than actual threads runtime.
KOSAKI Motohiro posted a fix for this problem, but that patch was never
applied: https://lkml.org/lkml/2013/5/26/191 .
This patch takes different approach to cure the problem. It calls
update_curr() when cputimer starts, that assure we will have updated
stats of running threads and on the next schedule tick we will account
only the runtime that elapsed from cputimer start. That also assure we
have consistent state between cpu times of individual threads and cpu
time of the process consisted by those threads.
Full reproducer (tst-cpuclock2.c):
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <stdint.h>
#include <inttypes.h>
/* Parameters for the Linux kernel ABI for CPU clocks. */
#define CPUCLOCK_SCHED 2
#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
static pthread_barrier_t barrier;
/* Help advance the clock. */
static void *chew_cpu(void *arg)
{
pthread_barrier_wait(&barrier);
while (1) ;
return NULL;
}
/* Don't use the glibc wrapper. */
static int do_nanosleep(int flags, const struct timespec *req)
{
clockid_t clock_id = MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED);
return syscall(SYS_clock_nanosleep, clock_id, flags, req, NULL);
}
static int64_t tsdiff(const struct timespec *before, const struct timespec *after)
{
int64_t before_i = before->tv_sec * 1000000000ULL + before->tv_nsec;
int64_t after_i = after->tv_sec * 1000000000ULL + after->tv_nsec;
return after_i - before_i;
}
int main(void)
{
int result = 0;
pthread_t th;
pthread_barrier_init(&barrier, NULL, 2);
if (pthread_create(&th, NULL, chew_cpu, NULL) != 0) {
perror("pthread_create");
return 1;
}
pthread_barrier_wait(&barrier);
/* The test. */
struct timespec before, after, sleeptimeabs;
int64_t sleepdiff, diffabs;
const struct timespec sleeptime = {.tv_sec = 0,.tv_nsec = 100000000 };
/* The relative nanosleep. Not sure why this is needed, but its presence
seems to make it easier to reproduce the problem. */
if (do_nanosleep(0, &sleeptime) != 0) {
perror("clock_nanosleep");
return 1;
}
/* Get the current time. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &before) < 0) {
perror("clock_gettime[2]");
return 1;
}
/* Compute the absolute sleep time based on the current time. */
uint64_t nsec = before.tv_nsec + sleeptime.tv_nsec;
sleeptimeabs.tv_sec = before.tv_sec + nsec / 1000000000;
sleeptimeabs.tv_nsec = nsec % 1000000000;
/* Sleep for the computed time. */
if (do_nanosleep(TIMER_ABSTIME, &sleeptimeabs) != 0) {
perror("absolute clock_nanosleep");
return 1;
}
/* Get the time after the sleep. */
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &after) < 0) {
perror("clock_gettime[3]");
return 1;
}
/* The time after sleep should always be equal to or after the absolute sleep
time passed to clock_nanosleep. */
sleepdiff = tsdiff(&sleeptimeabs, &after);
if (sleepdiff < 0) {
printf("absolute clock_nanosleep woke too early: %" PRId64 "\n", sleepdiff);
result = 1;
printf("Before %llu.%09llu\n", before.tv_sec, before.tv_nsec);
printf("After %llu.%09llu\n", after.tv_sec, after.tv_nsec);
printf("Sleep %llu.%09llu\n", sleeptimeabs.tv_sec, sleeptimeabs.tv_nsec);
}
/* The difference between the timestamps taken before and after the
clock_nanosleep call should be equal to or more than the duration of the
sleep. */
diffabs = tsdiff(&before, &after);
if (diffabs < sleeptime.tv_nsec) {
printf("clock_gettime difference too small: %" PRId64 "\n", diffabs);
result = 1;
}
pthread_cancel(th);
return result;
}
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20141112155843.GA24803@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-11-12 15:58:44 +00:00
|
|
|
update_rq_clock(rq);
|
|
|
|
p->sched_class->update_curr(rq);
|
|
|
|
}
|
|
|
|
ns = p->se.sum_exec_runtime;
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2009-03-31 07:56:03 +00:00
|
|
|
|
|
|
|
return ns;
|
|
|
|
}
|
2006-07-03 07:25:40 +00:00
|
|
|
|
2020-03-06 13:26:31 +00:00
|
|
|
DEFINE_PER_CPU(unsigned long, thermal_pressure);
|
|
|
|
|
|
|
|
void arch_set_thermal_pressure(struct cpumask *cpus,
|
|
|
|
unsigned long th_pressure)
|
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
for_each_cpu(cpu, cpus)
|
|
|
|
WRITE_ONCE(per_cpu(thermal_pressure, cpu), th_pressure);
|
|
|
|
}
|
|
|
|
|
2006-12-10 10:20:22 +00:00
|
|
|
/*
|
|
|
|
* This function gets called by the timer code, with HZ frequency.
|
|
|
|
* We call it with interrupts disabled.
|
|
|
|
*/
|
|
|
|
void scheduler_tick(void)
|
|
|
|
{
|
|
|
|
int cpu = smp_processor_id();
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2007-07-09 16:51:59 +00:00
|
|
|
struct task_struct *curr = rq->curr;
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2020-02-22 00:52:10 +00:00
|
|
|
unsigned long thermal_pressure;
|
2008-05-03 16:29:28 +00:00
|
|
|
|
x86, sched: Add support for frequency invariance
Implement arch_scale_freq_capacity() for 'modern' x86. This function
is used by the scheduler to correctly account usage in the face of
DVFS.
The present patch addresses Intel processors specifically and has positive
performance and performance-per-watt implications for the schedutil cpufreq
governor, bringing it closer to, if not on-par with, the powersave governor
from the intel_pstate driver/framework.
Large performance gains are obtained when the machine is lightly loaded and
no regression are observed at saturation. The benchmarks with the largest
gains are kernel compilation, tbench (the networking version of dbench) and
shell-intensive workloads.
1. FREQUENCY INVARIANCE: MOTIVATION
* Without it, a task looks larger if the CPU runs slower
2. PECULIARITIES OF X86
* freq invariance accounting requires knowing the ratio freq_curr/freq_max
2.1 CURRENT FREQUENCY
* Use delta_APERF / delta_MPERF * freq_base (a.k.a "BusyMHz")
2.2 MAX FREQUENCY
* It varies with time (turbo). As an approximation, we set it to a
constant, i.e. 4-cores turbo frequency.
3. EFFECTS ON THE SCHEDUTIL FREQUENCY GOVERNOR
* The invariant schedutil's formula has no feedback loop and reacts faster
to utilization changes
4. KNOWN LIMITATIONS
* In some cases tasks can't reach max util despite how hard they try
5. PERFORMANCE TESTING
5.1 MACHINES
* Skylake, Broadwell, Haswell
5.2 SETUP
* baseline Linux v5.2 w/ non-invariant schedutil. Tested freq_max = 1-2-3-4-8-12
active cores turbo w/ invariant schedutil, and intel_pstate/powersave
5.3 BENCHMARK RESULTS
5.3.1 NEUTRAL BENCHMARKS
* NAS Parallel Benchmark (HPC), hackbench
5.3.2 NON-NEUTRAL BENCHMARKS
* tbench (10-30% better), kernbench (10-15% better),
shell-intensive-scripts (30-50% better)
* no regressions
5.3.3 SELECTION OF DETAILED RESULTS
5.3.4 POWER CONSUMPTION, PERFORMANCE-PER-WATT
* dbench (5% worse on one machine), kernbench (3% worse),
tbench (5-10% better), shell-intensive-scripts (10-40% better)
6. MICROARCH'ES ADDRESSED HERE
* Xeon Core before Scalable Performance processors line (Xeon Gold/Platinum
etc have different MSRs semantic for querying turbo levels)
7. REFERENCES
* MMTests performance testing framework, github.com/gormanm/mmtests
+-------------------------------------------------------------------------+
| 1. FREQUENCY INVARIANCE: MOTIVATION
+-------------------------------------------------------------------------+
For example; suppose a CPU has two frequencies: 500 and 1000 Mhz. When
running a task that would consume 1/3rd of a CPU at 1000 MHz, it would
appear to consume 2/3rd (or 66.6%) when running at 500 MHz, giving the
false impression this CPU is almost at capacity, even though it can go
faster [*]. In a nutshell, without frequency scale-invariance tasks look
larger just because the CPU is running slower.
[*] (footnote: this assumes a linear frequency/performance relation; which
everybody knows to be false, but given realities its the best approximation
we can make.)
+-------------------------------------------------------------------------+
| 2. PECULIARITIES OF X86
+-------------------------------------------------------------------------+
Accounting for frequency changes in PELT signals requires the computation of
the ratio freq_curr / freq_max. On x86 neither of those terms is readily
available.
2.1 CURRENT FREQUENCY
====================
Since modern x86 has hardware control over the actual frequency we run
at (because amongst other things, Turbo-Mode), we cannot simply use
the frequency as requested through cpufreq.
Instead we use the APERF/MPERF MSRs to compute the effective frequency
over the recent past. Also, because reading MSRs is expensive, don't
do so every time we need the value, but amortize the cost by doing it
every tick.
2.2 MAX FREQUENCY
=================
Obtaining freq_max is also non-trivial because at any time the hardware can
provide a frequency boost to a selected subset of cores if the package has
enough power to spare (eg: Turbo Boost). This means that the maximum frequency
available to a given core changes with time.
The approach taken in this change is to arbitrarily set freq_max to a constant
value at boot. The value chosen is the "4-cores (4C) turbo frequency" on most
microarchitectures, after evaluating the following candidates:
* 1-core (1C) turbo frequency (the fastest turbo state available)
* around base frequency (a.k.a. max P-state)
* something in between, such as 4C turbo
To interpret these options, consider that this is the denominator in
freq_curr/freq_max, and that ratio will be used to scale PELT signals such as
util_avg and load_avg. A large denominator will undershoot (util_avg looks a
bit smaller than it really is), viceversa with a smaller denominator PELT
signals will tend to overshoot. Given that PELT drives frequency selection
in the schedutil governor, we will have:
freq_max set to | effect on DVFS
--------------------+------------------
1C turbo | power efficiency (lower freq choices)
base freq | performance (higher util_avg, higher freq requests)
4C turbo | a bit of both
4C turbo proves to be a good compromise in a number of benchmarks (see below).
+-------------------------------------------------------------------------+
| 3. EFFECTS ON THE SCHEDUTIL FREQUENCY GOVERNOR
+-------------------------------------------------------------------------+
Once an architecture implements a frequency scale-invariant utilization (the
PELT signal util_avg), schedutil switches its frequency selection formula from
freq_next = 1.25 * freq_curr * util [non-invariant util signal]
to
freq_next = 1.25 * freq_max * util [invariant util signal]
where, in the second formula, freq_max is set to the 1C turbo frequency (max
turbo). The advantage of the second formula, whose usage we unlock with this
patch, is that freq_next doesn't depend on the current frequency in an
iterative fashion, but can jump to any frequency in a single update. This
absence of feedback in the formula makes it quicker to react to utilization
changes and more robust against pathological instabilities.
Compare it to the update formula of intel_pstate/powersave:
freq_next = 1.25 * freq_max * Busy%
where again freq_max is 1C turbo and Busy% is the percentage of time not spent
idling (calculated with delta_MPERF / delta_TSC); essentially the same as
invariant schedutil, and largely responsible for intel_pstate/powersave good
reputation. The non-invariant schedutil formula is derived from the invariant
one by approximating util_inv with util_raw * freq_curr / freq_max, but this
has limitations.
Testing shows improved performances due to better frequency selections when
the machine is lightly loaded, and essentially no change in behaviour at
saturation / overutilization.
+-------------------------------------------------------------------------+
| 4. KNOWN LIMITATIONS
+-------------------------------------------------------------------------+
It's been shown that it is possible to create pathological scenarios where a
CPU-bound task cannot reach max utilization, if the normalizing factor
freq_max is fixed to a constant value (see [Lelli-2018]).
If freq_max is set to 4C turbo as we do here, one needs to peg at least 5
cores in a package doing some busywork, and observe that none of those task
will ever reach max util (1024) because they're all running at less than the
4C turbo frequency.
While this concern still applies, we believe the performance benefit of
frequency scale-invariant PELT signals outweights the cost of this limitation.
[Lelli-2018]
https://lore.kernel.org/lkml/20180517150418.GF22493@localhost.localdomain/
+-------------------------------------------------------------------------+
| 5. PERFORMANCE TESTING
+-------------------------------------------------------------------------+
5.1 MACHINES
============
We tested the patch on three machines, with Skylake, Broadwell and Haswell
CPUs. The details are below, together with the available turbo ratios as
reported by the appropriate MSRs.
* 8x-SKYLAKE-UMA:
Single socket E3-1240 v5, Skylake 4 cores/8 threads
Max EFFiciency, BASE frequency and available turbo levels (MHz):
EFFIC 800 |********
BASE 3500 |***********************************
4C 3700 |*************************************
3C 3800 |**************************************
2C 3900 |***************************************
1C 3900 |***************************************
* 80x-BROADWELL-NUMA:
Two sockets E5-2698 v4, 2x Broadwell 20 cores/40 threads
Max EFFiciency, BASE frequency and available turbo levels (MHz):
EFFIC 1200 |************
BASE 2200 |**********************
8C 2900 |*****************************
7C 3000 |******************************
6C 3100 |*******************************
5C 3200 |********************************
4C 3300 |*********************************
3C 3400 |**********************************
2C 3600 |************************************
1C 3600 |************************************
* 48x-HASWELL-NUMA
Two sockets E5-2670 v3, 2x Haswell 12 cores/24 threads
Max EFFiciency, BASE frequency and available turbo levels (MHz):
EFFIC 1200 |************
BASE 2300 |***********************
12C 2600 |**************************
11C 2600 |**************************
10C 2600 |**************************
9C 2600 |**************************
8C 2600 |**************************
7C 2600 |**************************
6C 2600 |**************************
5C 2700 |***************************
4C 2800 |****************************
3C 2900 |*****************************
2C 3100 |*******************************
1C 3100 |*******************************
5.2 SETUP
=========
* The baseline is Linux v5.2 with schedutil (non-invariant) and the intel_pstate
driver in passive mode.
* The rationale for choosing the various freq_max values to test have been to
try all the 1-2-3-4C turbo levels (note that 1C and 2C turbo are identical
on all machines), plus one more value closer to base_freq but still in the
turbo range (8C turbo for both 80x-BROADWELL-NUMA and 48x-HASWELL-NUMA).
* In addition we've run all tests with intel_pstate/powersave for comparison.
* The filesystem is always XFS, the userspace is openSUSE Leap 15.1.
* 8x-SKYLAKE-UMA is capable of HWP (Hardware-Managed P-States), so the runs
with active intel_pstate on this machine use that.
This gives, in terms of combinations tested on each machine:
* 8x-SKYLAKE-UMA
* Baseline: Linux v5.2, non-invariant schedutil, intel_pstate passive
* intel_pstate active + powersave + HWP
* invariant schedutil, freq_max = 1C turbo
* invariant schedutil, freq_max = 3C turbo
* invariant schedutil, freq_max = 4C turbo
* both 80x-BROADWELL-NUMA and 48x-HASWELL-NUMA
* [same as 8x-SKYLAKE-UMA, but no HWP capable]
* invariant schedutil, freq_max = 8C turbo
(which on 48x-HASWELL-NUMA is the same as 12C turbo, or "all cores turbo")
5.3 BENCHMARK RESULTS
=====================
5.3.1 NEUTRAL BENCHMARKS
------------------------
Tests that didn't show any measurable difference in performance on any of the
test machines between non-invariant schedutil and our patch are:
* NAS Parallel Benchmarks (NPB) using either MPI or openMP for IPC, any
computational kernel
* flexible I/O (FIO)
* hackbench (using threads or processes, and using pipes or sockets)
5.3.2 NON-NEUTRAL BENCHMARKS
----------------------------
What follow are summary tables where each benchmark result is given a score.
* A tilde (~) means a neutral result, i.e. no difference from baseline.
* Scores are computed with the ratio result_new / result_baseline, so a tilde
means a score of 1.00.
* The results in the score ratio are the geometric means of results running
the benchmark with different parameters (eg: for kernbench: using 1, 2, 4,
... number of processes; for pgbench: varying the number of clients, and so
on).
* The first three tables show higher-is-better kind of tests (i.e. measured in
operations/second), the subsequent three show lower-is-better kind of tests
(i.e. the workload is fixed and we measure elapsed time, think kernbench).
* "gitsource" is a name we made up for the test consisting in running the
entire unit tests suite of the Git SCM and measuring how long it takes. We
take it as a typical example of shell-intensive serialized workload.
* In the "I_PSTATE" column we have the results for intel_pstate/powersave. Other
columns show invariant schedutil for different values of freq_max. 4C turbo
is circled as it's the value we've chosen for the final implementation.
80x-BROADWELL-NUMA (comparison ratio; higher is better)
+------+
I_PSTATE 1C 3C | 4C | 8C
pgbench-ro 1.14 ~ ~ | 1.11 | 1.14
pgbench-rw ~ ~ ~ | ~ | ~
netperf-udp 1.06 ~ 1.06 | 1.05 | 1.07
netperf-tcp ~ 1.03 ~ | 1.01 | 1.02
tbench4 1.57 1.18 1.22 | 1.30 | 1.56
+------+
8x-SKYLAKE-UMA (comparison ratio; higher is better)
+------+
I_PSTATE/HWP 1C 3C | 4C |
pgbench-ro ~ ~ ~ | ~ |
pgbench-rw ~ ~ ~ | ~ |
netperf-udp ~ ~ ~ | ~ |
netperf-tcp ~ ~ ~ | ~ |
tbench4 1.30 1.14 1.14 | 1.16 |
+------+
48x-HASWELL-NUMA (comparison ratio; higher is better)
+------+
I_PSTATE 1C 3C | 4C | 12C
pgbench-ro 1.15 ~ ~ | 1.06 | 1.16
pgbench-rw ~ ~ ~ | ~ | ~
netperf-udp 1.05 0.97 1.04 | 1.04 | 1.02
netperf-tcp 0.96 1.01 1.01 | 1.01 | 1.01
tbench4 1.50 1.05 1.13 | 1.13 | 1.25
+------+
In the table above we see that active intel_pstate is slightly better than our
4C-turbo patch (both in reference to the baseline non-invariant schedutil) on
read-only pgbench and much better on tbench. Both cases are notable in which
it shows that lowering our freq_max (to 8C-turbo and 12C-turbo on
80x-BROADWELL-NUMA and 48x-HASWELL-NUMA respectively) helps invariant
schedutil to get closer.
If we ignore active intel_pstate and focus on the comparison with baseline
alone, there are several instances of double-digit performance improvement.
80x-BROADWELL-NUMA (comparison ratio; lower is better)
+------+
I_PSTATE 1C 3C | 4C | 8C
dbench4 1.23 0.95 0.95 | 0.95 | 0.95
kernbench 0.93 0.83 0.83 | 0.83 | 0.82
gitsource 0.98 0.49 0.49 | 0.49 | 0.48
+------+
8x-SKYLAKE-UMA (comparison ratio; lower is better)
+------+
I_PSTATE/HWP 1C 3C | 4C |
dbench4 ~ ~ ~ | ~ |
kernbench ~ ~ ~ | ~ |
gitsource 0.92 0.55 0.55 | 0.55 |
+------+
48x-HASWELL-NUMA (comparison ratio; lower is better)
+------+
I_PSTATE 1C 3C | 4C | 8C
dbench4 ~ ~ ~ | ~ | ~
kernbench 0.94 0.90 0.89 | 0.90 | 0.90
gitsource 0.97 0.69 0.69 | 0.69 | 0.69
+------+
dbench is not very remarkable here, unless we notice how poorly active
intel_pstate is performing on 80x-BROADWELL-NUMA: 23% regression versus
non-invariant schedutil. We repeated that run getting consistent results. Out
of scope for the patch at hand, but deserving future investigation. Other than
that, we previously ran this campaign with Linux v5.0 and saw the patch doing
better on dbench a the time. We haven't checked closely and can only speculate
at this point.
On the NUMA boxes kernbench gets 10-15% improvements on average; we'll see in
the detailed tables that the gains concentrate on low process counts (lightly
loaded machines).
The test we call "gitsource" (running the git unit test suite, a long-running
single-threaded shell script) appears rather spectacular in this table (gains
of 30-50% depending on the machine). It is to be noted, however, that
gitsource has no adjustable parameters (such as the number of jobs in
kernbench, which we average over in order to get a single-number summary
score) and is exactly the kind of low-parallelism workload that benefits the
most from this patch. When looking at the detailed tables of kernbench or
tbench4, at low process or client counts one can see similar numbers.
5.3.3 SELECTION OF DETAILED RESULTS
-----------------------------------
Machine : 48x-HASWELL-NUMA
Benchmark : tbench4 (i.e. dbench4 over the network, actually loopback)
Varying parameter : number of clients
Unit : MB/sec (higher is better)
5.2.0 vanilla (BASELINE) 5.2.0 intel_pstate 5.2.0 1C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hmean 1 126.73 +- 0.31% ( ) 315.91 +- 0.66% ( 149.28%) 125.03 +- 0.76% ( -1.34%)
Hmean 2 258.04 +- 0.62% ( ) 614.16 +- 0.51% ( 138.01%) 269.58 +- 1.45% ( 4.47%)
Hmean 4 514.30 +- 0.67% ( ) 1146.58 +- 0.54% ( 122.94%) 533.84 +- 1.99% ( 3.80%)
Hmean 8 1111.38 +- 2.52% ( ) 2159.78 +- 0.38% ( 94.33%) 1359.92 +- 1.56% ( 22.36%)
Hmean 16 2286.47 +- 1.36% ( ) 3338.29 +- 0.21% ( 46.00%) 2720.20 +- 0.52% ( 18.97%)
Hmean 32 4704.84 +- 0.35% ( ) 4759.03 +- 0.43% ( 1.15%) 4774.48 +- 0.30% ( 1.48%)
Hmean 64 7578.04 +- 0.27% ( ) 7533.70 +- 0.43% ( -0.59%) 7462.17 +- 0.65% ( -1.53%)
Hmean 128 6998.52 +- 0.16% ( ) 6987.59 +- 0.12% ( -0.16%) 6909.17 +- 0.14% ( -1.28%)
Hmean 192 6901.35 +- 0.25% ( ) 6913.16 +- 0.10% ( 0.17%) 6855.47 +- 0.21% ( -0.66%)
5.2.0 3C-turbo 5.2.0 4C-turbo 5.2.0 12C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hmean 1 128.43 +- 0.28% ( 1.34%) 130.64 +- 3.81% ( 3.09%) 153.71 +- 5.89% ( 21.30%)
Hmean 2 311.70 +- 6.15% ( 20.79%) 281.66 +- 3.40% ( 9.15%) 305.08 +- 5.70% ( 18.23%)
Hmean 4 641.98 +- 2.32% ( 24.83%) 623.88 +- 5.28% ( 21.31%) 906.84 +- 4.65% ( 76.32%)
Hmean 8 1633.31 +- 1.56% ( 46.96%) 1714.16 +- 0.93% ( 54.24%) 2095.74 +- 0.47% ( 88.57%)
Hmean 16 3047.24 +- 0.42% ( 33.27%) 3155.02 +- 0.30% ( 37.99%) 3634.58 +- 0.15% ( 58.96%)
Hmean 32 4734.31 +- 0.60% ( 0.63%) 4804.38 +- 0.23% ( 2.12%) 4674.62 +- 0.27% ( -0.64%)
Hmean 64 7699.74 +- 0.35% ( 1.61%) 7499.72 +- 0.34% ( -1.03%) 7659.03 +- 0.25% ( 1.07%)
Hmean 128 6935.18 +- 0.15% ( -0.91%) 6942.54 +- 0.10% ( -0.80%) 7004.85 +- 0.12% ( 0.09%)
Hmean 192 6901.62 +- 0.12% ( 0.00%) 6856.93 +- 0.10% ( -0.64%) 6978.74 +- 0.10% ( 1.12%)
This is one of the cases where the patch still can't surpass active
intel_pstate, not even when freq_max is as low as 12C-turbo. Otherwise, gains are
visible up to 16 clients and the saturated scenario is the same as baseline.
The scores in the summary table from the previous sections are ratios of
geometric means of the results over different clients, as seen in this table.
Machine : 80x-BROADWELL-NUMA
Benchmark : kernbench (kernel compilation)
Varying parameter : number of jobs
Unit : seconds (lower is better)
5.2.0 vanilla (BASELINE) 5.2.0 intel_pstate 5.2.0 1C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Amean 2 379.68 +- 0.06% ( ) 330.20 +- 0.43% ( 13.03%) 285.93 +- 0.07% ( 24.69%)
Amean 4 200.15 +- 0.24% ( ) 175.89 +- 0.22% ( 12.12%) 153.78 +- 0.25% ( 23.17%)
Amean 8 106.20 +- 0.31% ( ) 95.54 +- 0.23% ( 10.03%) 86.74 +- 0.10% ( 18.32%)
Amean 16 56.96 +- 1.31% ( ) 53.25 +- 1.22% ( 6.50%) 48.34 +- 1.73% ( 15.13%)
Amean 32 34.80 +- 2.46% ( ) 33.81 +- 0.77% ( 2.83%) 30.28 +- 1.59% ( 12.99%)
Amean 64 26.11 +- 1.63% ( ) 25.04 +- 1.07% ( 4.10%) 22.41 +- 2.37% ( 14.16%)
Amean 128 24.80 +- 1.36% ( ) 23.57 +- 1.23% ( 4.93%) 21.44 +- 1.37% ( 13.55%)
Amean 160 24.85 +- 0.56% ( ) 23.85 +- 1.17% ( 4.06%) 21.25 +- 1.12% ( 14.49%)
5.2.0 3C-turbo 5.2.0 4C-turbo 5.2.0 8C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Amean 2 284.08 +- 0.13% ( 25.18%) 283.96 +- 0.51% ( 25.21%) 285.05 +- 0.21% ( 24.92%)
Amean 4 153.18 +- 0.22% ( 23.47%) 154.70 +- 1.64% ( 22.71%) 153.64 +- 0.30% ( 23.24%)
Amean 8 87.06 +- 0.28% ( 18.02%) 86.77 +- 0.46% ( 18.29%) 86.78 +- 0.22% ( 18.28%)
Amean 16 48.03 +- 0.93% ( 15.68%) 47.75 +- 1.99% ( 16.17%) 47.52 +- 1.61% ( 16.57%)
Amean 32 30.23 +- 1.20% ( 13.14%) 30.08 +- 1.67% ( 13.57%) 30.07 +- 1.67% ( 13.60%)
Amean 64 22.59 +- 2.02% ( 13.50%) 22.63 +- 0.81% ( 13.32%) 22.42 +- 0.76% ( 14.12%)
Amean 128 21.37 +- 0.67% ( 13.82%) 21.31 +- 1.15% ( 14.07%) 21.17 +- 1.93% ( 14.63%)
Amean 160 21.68 +- 0.57% ( 12.76%) 21.18 +- 1.74% ( 14.77%) 21.22 +- 1.00% ( 14.61%)
The patch outperform active intel_pstate (and baseline) by a considerable
margin; the summary table from the previous section says 4C turbo and active
intel_pstate are 0.83 and 0.93 against baseline respectively, so 4C turbo is
0.83/0.93=0.89 against intel_pstate (~10% better on average). There is no
noticeable difference with regard to the value of freq_max.
Machine : 8x-SKYLAKE-UMA
Benchmark : gitsource (time to run the git unit test suite)
Varying parameter : none
Unit : seconds (lower is better)
5.2.0 vanilla 5.2.0 intel_pstate/hwp 5.2.0 1C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Amean 858.85 +- 1.16% ( ) 791.94 +- 0.21% ( 7.79%) 474.95 ( 44.70%)
5.2.0 3C-turbo 5.2.0 4C-turbo
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Amean 475.26 +- 0.20% ( 44.66%) 474.34 +- 0.13% ( 44.77%)
In this test, which is of interest as representing shell-intensive
(i.e. fork-intensive) serialized workloads, invariant schedutil outperforms
intel_pstate/powersave by a whopping 40% margin.
5.3.4 POWER CONSUMPTION, PERFORMANCE-PER-WATT
---------------------------------------------
The following table shows average power consumption in watt for each
benchmark. Data comes from turbostat (package average), which in turn is read
from the RAPL interface on CPUs. We know the patch affects CPU frequencies so
it's reasonable to ignore other power consumers (such as memory or I/O). Also,
we don't have a power meter available in the lab so RAPL is the best we have.
turbostat sampled average power every 10 seconds for the entire duration of
each benchmark. We took all those values and averaged them (i.e. with don't
have detail on a per-parameter granularity, only on whole benchmarks).
80x-BROADWELL-NUMA (power consumption, watts)
+--------+
BASELINE I_PSTATE 1C 3C | 4C | 8C
pgbench-ro 130.01 142.77 131.11 132.45 | 134.65 | 136.84
pgbench-rw 68.30 60.83 71.45 71.70 | 71.65 | 72.54
dbench4 90.25 59.06 101.43 99.89 | 101.10 | 102.94
netperf-udp 65.70 69.81 66.02 68.03 | 68.27 | 68.95
netperf-tcp 88.08 87.96 88.97 88.89 | 88.85 | 88.20
tbench4 142.32 176.73 153.02 163.91 | 165.58 | 176.07
kernbench 92.94 101.95 114.91 115.47 | 115.52 | 115.10
gitsource 40.92 41.87 75.14 75.20 | 75.40 | 75.70
+--------+
8x-SKYLAKE-UMA (power consumption, watts)
+--------+
BASELINE I_PSTATE/HWP 1C 3C | 4C |
pgbench-ro 46.49 46.68 46.56 46.59 | 46.52 |
pgbench-rw 29.34 31.38 30.98 31.00 | 31.00 |
dbench4 27.28 27.37 27.49 27.41 | 27.38 |
netperf-udp 22.33 22.41 22.36 22.35 | 22.36 |
netperf-tcp 27.29 27.29 27.30 27.31 | 27.33 |
tbench4 41.13 45.61 43.10 43.33 | 43.56 |
kernbench 42.56 42.63 43.01 43.01 | 43.01 |
gitsource 13.32 13.69 17.33 17.30 | 17.35 |
+--------+
48x-HASWELL-NUMA (power consumption, watts)
+--------+
BASELINE I_PSTATE 1C 3C | 4C | 12C
pgbench-ro 128.84 136.04 129.87 132.43 | 132.30 | 134.86
pgbench-rw 37.68 37.92 37.17 37.74 | 37.73 | 37.31
dbench4 28.56 28.73 28.60 28.73 | 28.70 | 28.79
netperf-udp 56.70 60.44 56.79 57.42 | 57.54 | 57.52
netperf-tcp 75.49 75.27 75.87 76.02 | 76.01 | 75.95
tbench4 115.44 139.51 119.53 123.07 | 123.97 | 130.22
kernbench 83.23 91.55 95.58 95.69 | 95.72 | 96.04
gitsource 36.79 36.99 39.99 40.34 | 40.35 | 40.23
+--------+
A lower power consumption isn't necessarily better, it depends on what is done
with that energy. Here are tables with the ratio of performance-per-watt on
each machine and benchmark. Higher is always better; a tilde (~) means a
neutral ratio (i.e. 1.00).
80x-BROADWELL-NUMA (performance-per-watt ratios; higher is better)
+------+
I_PSTATE 1C 3C | 4C | 8C
pgbench-ro 1.04 1.06 0.94 | 1.07 | 1.08
pgbench-rw 1.10 0.97 0.96 | 0.96 | 0.97
dbench4 1.24 0.94 0.95 | 0.94 | 0.92
netperf-udp ~ 1.02 1.02 | ~ | 1.02
netperf-tcp ~ 1.02 ~ | ~ | 1.02
tbench4 1.26 1.10 1.06 | 1.12 | 1.26
kernbench 0.98 0.97 0.97 | 0.97 | 0.98
gitsource ~ 1.11 1.11 | 1.11 | 1.13
+------+
8x-SKYLAKE-UMA (performance-per-watt ratios; higher is better)
+------+
I_PSTATE/HWP 1C 3C | 4C |
pgbench-ro ~ ~ ~ | ~ |
pgbench-rw 0.95 0.97 0.96 | 0.96 |
dbench4 ~ ~ ~ | ~ |
netperf-udp ~ ~ ~ | ~ |
netperf-tcp ~ ~ ~ | ~ |
tbench4 1.17 1.09 1.08 | 1.10 |
kernbench ~ ~ ~ | ~ |
gitsource 1.06 1.40 1.40 | 1.40 |
+------+
48x-HASWELL-NUMA (performance-per-watt ratios; higher is better)
+------+
I_PSTATE 1C 3C | 4C | 12C
pgbench-ro 1.09 ~ 1.09 | 1.03 | 1.11
pgbench-rw ~ 0.86 ~ | ~ | 0.86
dbench4 ~ 1.02 1.02 | 1.02 | ~
netperf-udp ~ 0.97 1.03 | 1.02 | ~
netperf-tcp 0.96 ~ ~ | ~ | ~
tbench4 1.24 ~ 1.06 | 1.05 | 1.11
kernbench 0.97 0.97 0.98 | 0.97 | 0.96
gitsource 1.03 1.33 1.32 | 1.32 | 1.33
+------+
These results are overall pleasing: in plenty of cases we observe
performance-per-watt improvements. The few regressions (read/write pgbench and
dbench on the Broadwell machine) are of small magnitude. kernbench loses a few
percentage points (it has a 10-15% performance improvement, but apparently the
increase in power consumption is larger than that). tbench4 and gitsource, which
benefit the most from the patch, keep a positive score in this table which is
a welcome surprise; that suggests that in those particular workloads the
non-invariant schedutil (and active intel_pstate, too) makes some rather
suboptimal frequency selections.
+-------------------------------------------------------------------------+
| 6. MICROARCH'ES ADDRESSED HERE
+-------------------------------------------------------------------------+
The patch addresses Xeon Core processors that use MSR_PLATFORM_INFO and
MSR_TURBO_RATIO_LIMIT to advertise their base frequency and turbo frequencies
respectively. This excludes the recent Xeon Scalable Performance processors
line (Xeon Gold, Platinum etc) whose MSRs have to be parsed differently.
Subsequent patches will address:
* Xeon Scalable Performance processors and Atom Goldmont/Goldmont Plus
* Xeon Phi (Knights Landing, Knights Mill)
* Atom Silvermont
+-------------------------------------------------------------------------+
| 7. REFERENCES
+-------------------------------------------------------------------------+
Tests have been run with the help of the MMTests performance testing
framework, see github.com/gormanm/mmtests. The configuration file names for
the benchmark used are:
db-pgbench-timed-ro-small-xfs
db-pgbench-timed-rw-small-xfs
io-dbench4-async-xfs
network-netperf-unbound
network-tbench
scheduler-unbound
workload-kerndevel-xfs
workload-shellscripts-xfs
hpc-nas-c-class-mpi-full-xfs
hpc-nas-c-class-omp-full
All those benchmarks are generally available on the web:
pgbench: https://www.postgresql.org/docs/10/pgbench.html
netperf: https://hewlettpackard.github.io/netperf/
dbench/tbench: https://dbench.samba.org/
gitsource: git unit test suite, github.com/git/git
NAS Parallel Benchmarks: https://www.nas.nasa.gov/publications/npb.html
hackbench: https://people.redhat.com/mingo/cfs-scheduler/tools/hackbench.c
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Giovanni Gherdovich <ggherdovich@suse.cz>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Acked-by: Doug Smythies <dsmythies@telus.net>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lkml.kernel.org/r/20200122151617.531-2-ggherdovich@suse.cz
2020-01-22 15:16:12 +00:00
|
|
|
arch_scale_freq_tick();
|
2008-05-03 16:29:28 +00:00
|
|
|
sched_clock_tick();
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
|
|
|
|
2008-05-03 16:29:28 +00:00
|
|
|
update_rq_clock(rq);
|
2020-02-22 00:52:10 +00:00
|
|
|
thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));
|
2020-02-22 00:52:13 +00:00
|
|
|
update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure);
|
2008-01-25 20:08:29 +00:00
|
|
|
curr->sched_class->task_tick(rq, curr, 0);
|
2015-04-14 11:19:42 +00:00
|
|
|
calc_global_load_tick(rq);
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
psi_task_tick(rq);
|
2016-10-04 14:04:35 +00:00
|
|
|
|
|
|
|
rq_unlock(rq, &rf);
|
2006-12-10 10:20:22 +00:00
|
|
|
|
2010-09-17 09:28:50 +00:00
|
|
|
perf_event_task_tick();
|
2009-05-23 16:28:55 +00:00
|
|
|
|
2006-12-10 10:20:23 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2011-10-03 22:09:01 +00:00
|
|
|
rq->idle_balance = idle_cpu(cpu);
|
2014-01-06 11:34:38 +00:00
|
|
|
trigger_load_balance(rq);
|
2006-12-10 10:20:23 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2013-05-03 01:39:05 +00:00
|
|
|
#ifdef CONFIG_NO_HZ_FULL
|
2018-02-21 04:17:27 +00:00
|
|
|
|
|
|
|
struct tick_work {
|
|
|
|
int cpu;
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
atomic_t state;
|
2018-02-21 04:17:27 +00:00
|
|
|
struct delayed_work work;
|
|
|
|
};
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
/* Values for ->state, see diagram below. */
|
|
|
|
#define TICK_SCHED_REMOTE_OFFLINE 0
|
|
|
|
#define TICK_SCHED_REMOTE_OFFLINING 1
|
|
|
|
#define TICK_SCHED_REMOTE_RUNNING 2
|
|
|
|
|
|
|
|
/*
|
|
|
|
* State diagram for ->state:
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* TICK_SCHED_REMOTE_OFFLINE
|
|
|
|
* | ^
|
|
|
|
* | |
|
|
|
|
* | | sched_tick_remote()
|
|
|
|
* | |
|
|
|
|
* | |
|
|
|
|
* +--TICK_SCHED_REMOTE_OFFLINING
|
|
|
|
* | ^
|
|
|
|
* | |
|
|
|
|
* sched_tick_start() | | sched_tick_stop()
|
|
|
|
* | |
|
|
|
|
* V |
|
|
|
|
* TICK_SCHED_REMOTE_RUNNING
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Other transitions get WARN_ON_ONCE(), except that sched_tick_remote()
|
|
|
|
* and sched_tick_start() are happy to leave the state in RUNNING.
|
|
|
|
*/
|
2018-02-21 04:17:27 +00:00
|
|
|
|
|
|
|
static struct tick_work __percpu *tick_work_cpu;
|
|
|
|
|
|
|
|
static void sched_tick_remote(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct delayed_work *dwork = to_delayed_work(work);
|
|
|
|
struct tick_work *twork = container_of(dwork, struct tick_work, work);
|
|
|
|
int cpu = twork->cpu;
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2018-06-28 16:29:41 +00:00
|
|
|
struct task_struct *curr;
|
2018-02-21 04:17:27 +00:00
|
|
|
struct rq_flags rf;
|
2018-06-28 16:29:41 +00:00
|
|
|
u64 delta;
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
int os;
|
2018-02-21 04:17:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle the tick only if it appears the remote CPU is running in full
|
|
|
|
* dynticks mode. The check is racy by nature, but missing a tick or
|
|
|
|
* having one too much is no big deal because the scheduler tick updates
|
|
|
|
* statistics and checks timeslices in a time-independent way, regardless
|
|
|
|
* of when exactly it is running.
|
|
|
|
*/
|
2020-01-11 09:53:38 +00:00
|
|
|
if (!tick_nohz_tick_stopped_cpu(cpu))
|
2018-06-28 16:29:41 +00:00
|
|
|
goto out_requeue;
|
2018-02-21 04:17:27 +00:00
|
|
|
|
2018-06-28 16:29:41 +00:00
|
|
|
rq_lock_irq(rq, &rf);
|
|
|
|
curr = rq->curr;
|
2020-01-11 09:53:38 +00:00
|
|
|
if (cpu_is_offline(cpu))
|
2018-06-28 16:29:41 +00:00
|
|
|
goto out_unlock;
|
2018-02-21 04:17:27 +00:00
|
|
|
|
2018-06-28 16:29:41 +00:00
|
|
|
update_rq_clock(rq);
|
|
|
|
|
2020-01-11 09:53:38 +00:00
|
|
|
if (!is_idle_task(curr)) {
|
|
|
|
/*
|
|
|
|
* Make sure the next tick runs within a reasonable
|
|
|
|
* amount of time.
|
|
|
|
*/
|
|
|
|
delta = rq_clock_task(rq) - curr->se.exec_start;
|
|
|
|
WARN_ON_ONCE(delta > (u64)NSEC_PER_SEC * 3);
|
|
|
|
}
|
2018-06-28 16:29:41 +00:00
|
|
|
curr->sched_class->task_tick(rq, curr, 0);
|
|
|
|
|
2020-01-11 09:53:39 +00:00
|
|
|
calc_load_nohz_remote(rq);
|
2018-06-28 16:29:41 +00:00
|
|
|
out_unlock:
|
|
|
|
rq_unlock_irq(rq, &rf);
|
|
|
|
out_requeue:
|
2020-01-11 09:53:39 +00:00
|
|
|
|
2018-02-21 04:17:27 +00:00
|
|
|
/*
|
|
|
|
* Run the remote tick once per second (1Hz). This arbitrary
|
|
|
|
* frequency is large enough to avoid overload but short enough
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
* to keep scheduler internal stats reasonably up to date. But
|
|
|
|
* first update state to reflect hotplug activity if required.
|
2018-02-21 04:17:27 +00:00
|
|
|
*/
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
os = atomic_fetch_add_unless(&twork->state, -1, TICK_SCHED_REMOTE_RUNNING);
|
|
|
|
WARN_ON_ONCE(os == TICK_SCHED_REMOTE_OFFLINE);
|
|
|
|
if (os == TICK_SCHED_REMOTE_RUNNING)
|
|
|
|
queue_delayed_work(system_unbound_wq, dwork, HZ);
|
2018-02-21 04:17:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sched_tick_start(int cpu)
|
|
|
|
{
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
int os;
|
2018-02-21 04:17:27 +00:00
|
|
|
struct tick_work *twork;
|
|
|
|
|
|
|
|
if (housekeeping_cpu(cpu, HK_FLAG_TICK))
|
|
|
|
return;
|
|
|
|
|
|
|
|
WARN_ON_ONCE(!tick_work_cpu);
|
|
|
|
|
|
|
|
twork = per_cpu_ptr(tick_work_cpu, cpu);
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_RUNNING);
|
|
|
|
WARN_ON_ONCE(os == TICK_SCHED_REMOTE_RUNNING);
|
|
|
|
if (os == TICK_SCHED_REMOTE_OFFLINE) {
|
|
|
|
twork->cpu = cpu;
|
|
|
|
INIT_DELAYED_WORK(&twork->work, sched_tick_remote);
|
|
|
|
queue_delayed_work(system_unbound_wq, &twork->work, HZ);
|
|
|
|
}
|
2018-02-21 04:17:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
static void sched_tick_stop(int cpu)
|
|
|
|
{
|
|
|
|
struct tick_work *twork;
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
int os;
|
2018-02-21 04:17:27 +00:00
|
|
|
|
|
|
|
if (housekeeping_cpu(cpu, HK_FLAG_TICK))
|
|
|
|
return;
|
|
|
|
|
|
|
|
WARN_ON_ONCE(!tick_work_cpu);
|
|
|
|
|
|
|
|
twork = per_cpu_ptr(tick_work_cpu, cpu);
|
time/tick-broadcast: Fix tick_broadcast_offline() lockdep complaint
The TASKS03 and TREE04 rcutorture scenarios produce the following
lockdep complaint:
------------------------------------------------------------------------
================================
WARNING: inconsistent lock state
5.2.0-rc1+ #513 Not tainted
--------------------------------
inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage.
migration/1/14 [HC0[0]:SC0[0]:HE1:SE1] takes:
(____ptrval____) (tick_broadcast_lock){?...}, at: tick_broadcast_offline+0xf/0x70
{IN-HARDIRQ-W} state was registered at:
lock_acquire+0xb0/0x1c0
_raw_spin_lock_irqsave+0x3c/0x50
tick_broadcast_switch_to_oneshot+0xd/0x40
tick_switch_to_oneshot+0x4f/0xd0
hrtimer_run_queues+0xf3/0x130
run_local_timers+0x1c/0x50
update_process_times+0x1c/0x50
tick_periodic+0x26/0xc0
tick_handle_periodic+0x1a/0x60
smp_apic_timer_interrupt+0x80/0x2a0
apic_timer_interrupt+0xf/0x20
_raw_spin_unlock_irqrestore+0x4e/0x60
rcu_nocb_gp_kthread+0x15d/0x590
kthread+0xf3/0x130
ret_from_fork+0x3a/0x50
irq event stamp: 171
hardirqs last enabled at (171): [<ffffffff8a201a37>] trace_hardirqs_on_thunk+0x1a/0x1c
hardirqs last disabled at (170): [<ffffffff8a201a53>] trace_hardirqs_off_thunk+0x1a/0x1c
softirqs last enabled at (0): [<ffffffff8a264ee0>] copy_process.part.56+0x650/0x1cb0
softirqs last disabled at (0): [<0000000000000000>] 0x0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(tick_broadcast_lock);
<Interrupt>
lock(tick_broadcast_lock);
*** DEADLOCK ***
1 lock held by migration/1/14:
#0: (____ptrval____) (clockevents_lock){+.+.}, at: tick_offline_cpu+0xf/0x30
stack backtrace:
CPU: 1 PID: 14 Comm: migration/1 Not tainted 5.2.0-rc1+ #513
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS Bochs 01/01/2011
Call Trace:
dump_stack+0x5e/0x8b
print_usage_bug+0x1fc/0x216
? print_shortest_lock_dependencies+0x1b0/0x1b0
mark_lock+0x1f2/0x280
__lock_acquire+0x1e0/0x18f0
? __lock_acquire+0x21b/0x18f0
? _raw_spin_unlock_irqrestore+0x4e/0x60
lock_acquire+0xb0/0x1c0
? tick_broadcast_offline+0xf/0x70
_raw_spin_lock+0x33/0x40
? tick_broadcast_offline+0xf/0x70
tick_broadcast_offline+0xf/0x70
tick_offline_cpu+0x16/0x30
take_cpu_down+0x7d/0xa0
multi_cpu_stop+0xa2/0xe0
? cpu_stop_queue_work+0xc0/0xc0
cpu_stopper_thread+0x6d/0x100
smpboot_thread_fn+0x169/0x240
kthread+0xf3/0x130
? sort_range+0x20/0x20
? kthread_cancel_delayed_work_sync+0x10/0x10
ret_from_fork+0x3a/0x50
------------------------------------------------------------------------
To reproduce, run the following rcutorture test:
tools/testing/selftests/rcutorture/bin/kvm.sh --duration 5 --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" --configs "TASKS03 TREE04"
It turns out that tick_broadcast_offline() was an innocent bystander.
After all, interrupts are supposed to be disabled throughout
take_cpu_down(), and therefore should have been disabled upon entry to
tick_offline_cpu() and thus to tick_broadcast_offline(). This suggests
that one of the CPU-hotplug notifiers was incorrectly enabling interrupts,
and leaving them enabled on return.
Some debugging code showed that the culprit was sched_cpu_dying().
It had irqs enabled after return from sched_tick_stop(). Which in turn
had irqs enabled after return from cancel_delayed_work_sync(). Which is a
wrapper around __cancel_work_timer(). Which can sleep in the case where
something else is concurrently trying to cancel the same delayed work,
and as Thomas Gleixner pointed out on IRC, sleeping is a decidedly bad
idea when you are invoked from take_cpu_down(), regardless of the state
you leave interrupts in upon return.
Code inspection located no reason why the delayed work absolutely
needed to be canceled from sched_tick_stop(): The work is not
bound to the outgoing CPU by design, given that the whole point is
to collect statistics without disturbing the outgoing CPU.
This commit therefore simply drops the cancel_delayed_work_sync() from
sched_tick_stop(). Instead, a new ->state field is added to the tick_work
structure so that the delayed-work handler function sched_tick_remote()
can avoid reposting itself. A cpu_is_offline() check is also added to
sched_tick_remote() to avoid mucking with the state of an offlined CPU
(though it does appear safe to do so). The sched_tick_start() and
sched_tick_stop() functions also update ->state, and sched_tick_start()
also schedules the delayed work if ->state indicates that it is not
already in flight.
Signed-off-by: Paul E. McKenney <paulmck@linux.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
[ paulmck: Apply Peter Zijlstra and Frederic Weisbecker atomics feedback. ]
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
2019-05-30 12:39:25 +00:00
|
|
|
/* There cannot be competing actions, but don't rely on stop-machine. */
|
|
|
|
os = atomic_xchg(&twork->state, TICK_SCHED_REMOTE_OFFLINING);
|
|
|
|
WARN_ON_ONCE(os != TICK_SCHED_REMOTE_RUNNING);
|
|
|
|
/* Don't cancel, as this would mess up the state machine. */
|
2018-02-21 04:17:27 +00:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_HOTPLUG_CPU */
|
|
|
|
|
|
|
|
int __init sched_tick_offload_init(void)
|
|
|
|
{
|
|
|
|
tick_work_cpu = alloc_percpu(struct tick_work);
|
|
|
|
BUG_ON(!tick_work_cpu);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !CONFIG_NO_HZ_FULL */
|
|
|
|
static inline void sched_tick_start(int cpu) { }
|
|
|
|
static inline void sched_tick_stop(int cpu) { }
|
2013-05-03 01:39:05 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-07-26 21:19:37 +00:00
|
|
|
#if defined(CONFIG_PREEMPTION) && (defined(CONFIG_DEBUG_PREEMPT) || \
|
2018-07-30 22:24:23 +00:00
|
|
|
defined(CONFIG_TRACE_PREEMPT_TOGGLE))
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
/*
|
|
|
|
* If the value passed in is equal to the current preempt count
|
|
|
|
* then we just disabled preemption. Start timing the latency.
|
|
|
|
*/
|
|
|
|
static inline void preempt_latency_start(int val)
|
|
|
|
{
|
|
|
|
if (preempt_count() == val) {
|
|
|
|
unsigned long ip = get_lock_parent_ip();
|
|
|
|
#ifdef CONFIG_DEBUG_PREEMPT
|
|
|
|
current->preempt_disable_ip = ip;
|
|
|
|
#endif
|
|
|
|
trace_preempt_off(CALLER_ADDR0, ip);
|
|
|
|
}
|
|
|
|
}
|
2009-01-23 00:01:40 +00:00
|
|
|
|
2014-04-17 08:18:42 +00:00
|
|
|
void preempt_count_add(int val)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-05-12 19:20:42 +00:00
|
|
|
#ifdef CONFIG_DEBUG_PREEMPT
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Underflow?
|
|
|
|
*/
|
2006-07-03 07:24:33 +00:00
|
|
|
if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0)))
|
|
|
|
return;
|
2008-05-12 19:20:42 +00:00
|
|
|
#endif
|
2013-09-10 10:15:23 +00:00
|
|
|
__preempt_count_add(val);
|
2008-05-12 19:20:42 +00:00
|
|
|
#ifdef CONFIG_DEBUG_PREEMPT
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Spinlock count overflowing soon?
|
|
|
|
*/
|
2006-12-10 10:20:38 +00:00
|
|
|
DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >=
|
|
|
|
PREEMPT_MASK - 10);
|
2008-05-12 19:20:42 +00:00
|
|
|
#endif
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_start(val);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2013-09-10 10:15:23 +00:00
|
|
|
EXPORT_SYMBOL(preempt_count_add);
|
2014-04-17 08:18:42 +00:00
|
|
|
NOKPROBE_SYMBOL(preempt_count_add);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
/*
|
|
|
|
* If the value passed in equals to the current preempt count
|
|
|
|
* then we just enabled preemption. Stop timing the latency.
|
|
|
|
*/
|
|
|
|
static inline void preempt_latency_stop(int val)
|
|
|
|
{
|
|
|
|
if (preempt_count() == val)
|
|
|
|
trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip());
|
|
|
|
}
|
|
|
|
|
2014-04-17 08:18:42 +00:00
|
|
|
void preempt_count_sub(int val)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-05-12 19:20:42 +00:00
|
|
|
#ifdef CONFIG_DEBUG_PREEMPT
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Underflow?
|
|
|
|
*/
|
2009-01-12 12:00:50 +00:00
|
|
|
if (DEBUG_LOCKS_WARN_ON(val > preempt_count()))
|
2006-07-03 07:24:33 +00:00
|
|
|
return;
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Is the spinlock portion underflowing?
|
|
|
|
*/
|
2006-07-03 07:24:33 +00:00
|
|
|
if (DEBUG_LOCKS_WARN_ON((val < PREEMPT_MASK) &&
|
|
|
|
!(preempt_count() & PREEMPT_MASK)))
|
|
|
|
return;
|
2008-05-12 19:20:42 +00:00
|
|
|
#endif
|
2006-07-03 07:24:33 +00:00
|
|
|
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_stop(val);
|
2013-09-10 10:15:23 +00:00
|
|
|
__preempt_count_sub(val);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2013-09-10 10:15:23 +00:00
|
|
|
EXPORT_SYMBOL(preempt_count_sub);
|
2014-04-17 08:18:42 +00:00
|
|
|
NOKPROBE_SYMBOL(preempt_count_sub);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
#else
|
|
|
|
static inline void preempt_latency_start(int val) { }
|
|
|
|
static inline void preempt_latency_stop(int val) { }
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-03 22:37:48 +00:00
|
|
|
static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_DEBUG_PREEMPT
|
|
|
|
return p->preempt_disable_ip;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2007-07-09 16:51:59 +00:00
|
|
|
* Print scheduling while atomic bug:
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2007-07-09 16:51:59 +00:00
|
|
|
static noinline void __schedule_bug(struct task_struct *prev)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
/* Save this before calling printk(), since that will clobber it */
|
|
|
|
unsigned long preempt_disable_ip = get_preempt_disable_ip(current);
|
|
|
|
|
2011-12-22 21:39:30 +00:00
|
|
|
if (oops_in_progress)
|
|
|
|
return;
|
|
|
|
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n",
|
|
|
|
prev->comm, prev->pid, preempt_count());
|
2007-10-24 16:23:50 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
debug_show_held_locks(prev);
|
2008-05-23 16:05:58 +00:00
|
|
|
print_modules();
|
2007-07-09 16:51:59 +00:00
|
|
|
if (irqs_disabled())
|
|
|
|
print_irqtrace_events(prev);
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
|
|
|
|
&& in_atomic_preempt_off()) {
|
2014-02-07 19:58:39 +00:00
|
|
|
pr_err("Preemption disabled at:");
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
print_ip_sym(preempt_disable_ip);
|
2014-02-07 19:58:39 +00:00
|
|
|
pr_cont("\n");
|
|
|
|
}
|
2016-06-03 20:10:18 +00:00
|
|
|
if (panic_on_warn)
|
|
|
|
panic("scheduling while atomic\n");
|
|
|
|
|
2012-03-29 00:10:47 +00:00
|
|
|
dump_stack();
|
2013-01-21 06:47:39 +00:00
|
|
|
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
|
|
|
* Various schedule()-time debugging checks and statistics:
|
|
|
|
*/
|
2019-08-26 20:14:23 +00:00
|
|
|
static inline void schedule_debug(struct task_struct *prev, bool preempt)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2014-09-12 13:16:19 +00:00
|
|
|
#ifdef CONFIG_SCHED_STACK_END_CHECK
|
2016-06-01 09:55:07 +00:00
|
|
|
if (task_stack_end_corrupted(prev))
|
|
|
|
panic("corrupted stack end detected inside scheduler\n");
|
2014-09-12 13:16:19 +00:00
|
|
|
#endif
|
2015-09-28 16:02:03 +00:00
|
|
|
|
2019-08-26 20:14:23 +00:00
|
|
|
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
|
|
|
|
if (!preempt && prev->state && prev->non_block_count) {
|
|
|
|
printk(KERN_ERR "BUG: scheduling in a non-blocking section: %s/%d/%i\n",
|
|
|
|
prev->comm, prev->pid, prev->non_block_count);
|
|
|
|
dump_stack();
|
|
|
|
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-09-28 15:57:39 +00:00
|
|
|
if (unlikely(in_atomic_preempt_off())) {
|
2007-07-09 16:51:59 +00:00
|
|
|
__schedule_bug(prev);
|
2015-09-28 15:57:39 +00:00
|
|
|
preempt_count_set(PREEMPT_DISABLED);
|
|
|
|
}
|
2011-05-24 15:31:09 +00:00
|
|
|
rcu_sleep_check();
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
profile_hit(SCHED_PROFILING, __builtin_return_address(0));
|
|
|
|
|
2016-06-17 17:43:24 +00:00
|
|
|
schedstat_inc(this_rq()->sched_count);
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 10:50:43 +00:00
|
|
|
static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
|
|
|
|
struct rq_flags *rf)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
const struct sched_class *class;
|
|
|
|
/*
|
|
|
|
* We must do the balancing pass before put_prev_task(), such
|
|
|
|
* that when we release the rq->lock the task is in the same
|
|
|
|
* state as before we took rq->lock.
|
|
|
|
*
|
|
|
|
* We can terminate the balance pass as soon as we know there is
|
|
|
|
* a runnable task of @class priority or higher.
|
|
|
|
*/
|
|
|
|
for_class_range(class, prev->sched_class, &idle_sched_class) {
|
|
|
|
if (class->balance(rq, prev, rf))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
put_prev_task(rq, prev);
|
|
|
|
}
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
|
|
|
* Pick up the highest-prio task:
|
|
|
|
*/
|
|
|
|
static inline struct task_struct *
|
2016-09-21 13:38:10 +00:00
|
|
|
pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
2017-01-19 17:44:08 +00:00
|
|
|
const struct sched_class *class;
|
2007-07-09 16:51:59 +00:00
|
|
|
struct task_struct *p;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
2017-03-01 09:51:47 +00:00
|
|
|
* Optimization: we know that if all tasks are in the fair class we can
|
|
|
|
* call that function directly, but only if the @prev task wasn't of a
|
|
|
|
* higher scheduling class, because otherwise those loose the
|
|
|
|
* opportunity to pull in more work from other CPUs.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2017-03-01 09:51:47 +00:00
|
|
|
if (likely((prev->sched_class == &idle_sched_class ||
|
|
|
|
prev->sched_class == &fair_sched_class) &&
|
|
|
|
rq->nr_running == rq->cfs.h_nr_running)) {
|
|
|
|
|
2019-11-08 13:15:57 +00:00
|
|
|
p = pick_next_task_fair(rq, prev, rf);
|
2014-04-24 10:00:47 +00:00
|
|
|
if (unlikely(p == RETRY_TASK))
|
2019-05-29 20:36:44 +00:00
|
|
|
goto restart;
|
2014-04-24 10:00:47 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Assumes fair_sched_class->next == idle_sched_class */
|
2019-11-08 13:15:57 +00:00
|
|
|
if (!p) {
|
2019-11-08 13:15:56 +00:00
|
|
|
put_prev_task(rq, prev);
|
2019-11-08 13:15:58 +00:00
|
|
|
p = pick_next_task_idle(rq);
|
2019-11-08 13:15:56 +00:00
|
|
|
}
|
2014-04-24 10:00:47 +00:00
|
|
|
|
|
|
|
return p;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-05-29 20:36:44 +00:00
|
|
|
restart:
|
2020-04-21 10:50:43 +00:00
|
|
|
put_prev_task_balance(rq, prev, rf);
|
2019-05-29 20:36:44 +00:00
|
|
|
|
2010-09-22 11:53:15 +00:00
|
|
|
for_each_class(class) {
|
2019-11-08 13:15:58 +00:00
|
|
|
p = class->pick_next_task(rq);
|
2019-05-29 20:36:44 +00:00
|
|
|
if (p)
|
2007-07-09 16:51:59 +00:00
|
|
|
return p;
|
|
|
|
}
|
2010-09-22 11:53:15 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* The idle class should always have a runnable task: */
|
|
|
|
BUG();
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
2011-06-22 17:47:00 +00:00
|
|
|
* __schedule() is the main scheduler function.
|
2012-08-04 08:49:47 +00:00
|
|
|
*
|
|
|
|
* The main means of driving the scheduler and thus entering this function are:
|
|
|
|
*
|
|
|
|
* 1. Explicit blocking: mutex, semaphore, waitqueue, etc.
|
|
|
|
*
|
|
|
|
* 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return
|
|
|
|
* paths. For example, see arch/x86/entry_64.S.
|
|
|
|
*
|
|
|
|
* To drive preemption between tasks, the scheduler sets the flag in timer
|
|
|
|
* interrupt handler scheduler_tick().
|
|
|
|
*
|
|
|
|
* 3. Wakeups don't really cause entry into schedule(). They add a
|
|
|
|
* task to the run-queue and that's it.
|
|
|
|
*
|
|
|
|
* Now, if the new task added to the run-queue preempts the current
|
|
|
|
* task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
|
|
|
|
* called on the nearest possible occasion:
|
|
|
|
*
|
2019-07-26 21:19:37 +00:00
|
|
|
* - If the kernel is preemptible (CONFIG_PREEMPTION=y):
|
2012-08-04 08:49:47 +00:00
|
|
|
*
|
|
|
|
* - in syscall or exception context, at the next outmost
|
|
|
|
* preempt_enable(). (this might be as soon as the wake_up()'s
|
|
|
|
* spin_unlock()!)
|
|
|
|
*
|
|
|
|
* - in IRQ context, return from interrupt-handler to
|
|
|
|
* preemptible context
|
|
|
|
*
|
2019-07-26 21:19:37 +00:00
|
|
|
* - If the kernel is not preemptible (CONFIG_PREEMPTION is not set)
|
2012-08-04 08:49:47 +00:00
|
|
|
* then at the next:
|
|
|
|
*
|
|
|
|
* - cond_resched() call
|
|
|
|
* - explicit schedule() call
|
|
|
|
* - return from syscall or exception to user-space
|
|
|
|
* - return from interrupt-handler to user-space
|
2015-01-28 00:24:09 +00:00
|
|
|
*
|
2015-05-12 14:41:49 +00:00
|
|
|
* WARNING: must be called with preemption disabled!
|
2007-07-09 16:51:59 +00:00
|
|
|
*/
|
sched/core: More notrace annotations
preempt_schedule_common() is marked notrace, but it does not use
_notrace() preempt_count functions and __schedule() is also not marked
notrace, which means that its perfectly possible to end up in the
tracer from preempt_schedule_common().
Steve says:
| Yep, there's some history to this. This was originally the issue that
| caused function tracing to go into infinite recursion. But now we have
| preempt_schedule_notrace(), which is used by the function tracer, and
| that function must not be traced till preemption is disabled.
|
| Now if function tracing is running and we take an interrupt when
| NEED_RESCHED is set, it calls
|
| preempt_schedule_common() (not traced)
|
| But then that calls preempt_disable() (traced)
|
| function tracer calls preempt_disable_notrace() followed by
| preempt_enable_notrace() which will see NEED_RESCHED set, and it will
| call preempt_schedule_notrace(), which stops the recursion, but
| still calls __schedule() here, and that means when we return, we call
| the __schedule() from preempt_schedule_common().
|
| That said, I prefer this patch. Preemption is disabled before calling
| __schedule(), and we get rid of a one round recursion with the
| scheduler.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-28 16:52:36 +00:00
|
|
|
static void __sched notrace __schedule(bool preempt)
|
2007-07-09 16:51:59 +00:00
|
|
|
{
|
|
|
|
struct task_struct *prev, *next;
|
2008-02-15 17:56:36 +00:00
|
|
|
unsigned long *switch_count;
|
2016-09-21 13:38:10 +00:00
|
|
|
struct rq_flags rf;
|
2007-07-09 16:51:59 +00:00
|
|
|
struct rq *rq;
|
2008-07-18 16:01:23 +00:00
|
|
|
int cpu;
|
2007-07-09 16:51:59 +00:00
|
|
|
|
|
|
|
cpu = smp_processor_id();
|
|
|
|
rq = cpu_rq(cpu);
|
|
|
|
prev = rq->curr;
|
|
|
|
|
2019-08-26 20:14:23 +00:00
|
|
|
schedule_debug(prev, preempt);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-07-18 16:01:23 +00:00
|
|
|
if (sched_feat(HRTICK))
|
2008-05-12 19:20:55 +00:00
|
|
|
hrtick_clear(rq);
|
2008-01-25 20:08:29 +00:00
|
|
|
|
2015-10-07 16:10:48 +00:00
|
|
|
local_irq_disable();
|
2017-04-11 22:50:41 +00:00
|
|
|
rcu_note_context_switch(preempt);
|
2015-10-07 16:10:48 +00:00
|
|
|
|
2013-08-12 16:14:00 +00:00
|
|
|
/*
|
|
|
|
* Make sure that signal_pending_state()->signal_pending() below
|
|
|
|
* can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
|
|
|
|
* done by the caller to avoid the race with signal_wake_up().
|
2018-01-29 20:20:12 +00:00
|
|
|
*
|
|
|
|
* The membarrier system call requires a full memory barrier
|
|
|
|
* after coming from user-space, before storing to rq->curr.
|
2013-08-12 16:14:00 +00:00
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock(rq, &rf);
|
locking: Introduce smp_mb__after_spinlock()
Since its inception, our understanding of ACQUIRE, esp. as applied to
spinlocks, has changed somewhat. Also, I wonder if, with a simple
change, we cannot make it provide more.
The problem with the comment is that the STORE done by spin_lock isn't
itself ordered by the ACQUIRE, and therefore a later LOAD can pass over
it and cross with any prior STORE, rendering the default WMB
insufficient (pointed out by Alan).
Now, this is only really a problem on PowerPC and ARM64, both of
which already defined smp_mb__before_spinlock() as a smp_mb().
At the same time, we can get a much stronger construct if we place
that same barrier _inside_ the spin_lock(). In that case we upgrade
the RCpc spinlock to an RCsc. That would make all schedule() calls
fully transitive against one another.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-09-05 09:37:53 +00:00
|
|
|
smp_mb__after_spinlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Promote REQ to ACT */
|
|
|
|
rq->clock_update_flags <<= 1;
|
2017-02-21 13:40:35 +00:00
|
|
|
update_rq_clock(rq);
|
2015-01-05 10:18:11 +00:00
|
|
|
|
2010-05-19 12:57:11 +00:00
|
|
|
switch_count = &prev->nivcsw;
|
2015-09-28 16:05:34 +00:00
|
|
|
if (!preempt && prev->state) {
|
2019-01-03 23:28:48 +00:00
|
|
|
if (signal_pending_state(prev->state, prev)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
prev->state = TASK_RUNNING;
|
2010-06-08 19:40:37 +00:00
|
|
|
} else {
|
2017-02-21 13:40:35 +00:00
|
|
|
deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);
|
2011-04-05 15:23:50 +00:00
|
|
|
|
2016-12-07 20:48:41 +00:00
|
|
|
if (prev->in_iowait) {
|
|
|
|
atomic_inc(&rq->nr_iowait);
|
|
|
|
delayacct_blkio_start();
|
|
|
|
}
|
2010-06-08 19:40:37 +00:00
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
switch_count = &prev->nvcsw;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2016-09-21 13:38:10 +00:00
|
|
|
next = pick_next_task(rq, prev, &rf);
|
2010-12-08 10:05:42 +00:00
|
|
|
clear_tsk_need_resched(prev);
|
2013-08-14 12:55:31 +00:00
|
|
|
clear_preempt_need_resched();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (likely(prev != next)) {
|
|
|
|
rq->nr_switches++;
|
tasks, sched/core: RCUify the assignment of rq->curr
The current task on the runqueue is currently read with rcu_dereference().
To obtain ordinary RCU semantics for an rcu_dereference() of rq->curr it needs
to be paired with rcu_assign_pointer() of rq->curr. Which provides the
memory barrier necessary to order assignments to the task_struct
and the assignment to rq->curr.
Unfortunately the assignment of rq->curr in __schedule is a hot path,
and it has already been show that additional barriers in that code
will reduce the performance of the scheduler. So I will attempt to
describe below why you can effectively have ordinary RCU semantics
without any additional barriers.
The assignment of rq->curr in init_idle is a slow path called once
per cpu and that can use rcu_assign_pointer() without any concerns.
As I write this there are effectively two users of rcu_dereference() on
rq->curr. There is the membarrier code in kernel/sched/membarrier.c
that only looks at "->mm" after the rcu_dereference(). Then there is
task_numa_compare() in kernel/sched/fair.c. My best reading of the
code shows that task_numa_compare only access: "->flags",
"->cpus_ptr", "->numa_group", "->numa_faults[]",
"->total_numa_faults", and "->se.cfs_rq".
The code in __schedule() essentially does:
rq_lock(...);
smp_mb__after_spinlock();
next = pick_next_task(...);
rq->curr = next;
context_switch(prev, next);
At the start of the function the rq_lock/smp_mb__after_spinlock
pair provides a full memory barrier. Further there is a full memory barrier
in context_switch().
This means that any task that has already run and modified itself (the
common case) has already seen two memory barriers before __schedule()
runs and begins executing. A task that modifies itself then sees a
third full memory barrier pair with the rq_lock();
For a brand new task that is enqueued with wake_up_new_task() there
are the memory barriers present from the taking and release the
pi_lock and the rq_lock as the processes is enqueued as well as the
full memory barrier at the start of __schedule() assuming __schedule()
happens on the same cpu.
This means that by the time we reach the assignment of rq->curr
except for values on the task struct modified in pick_next_task
the code has the same guarantees as if it used rcu_assign_pointer().
Reading through all of the implementations of pick_next_task it
appears pick_next_task is limited to modifying the task_struct fields
"->se", "->rt", "->dl". These fields are the sched_entity structures
of the varies schedulers.
Further "->se.cfs_rq" is only changed in cgroup attach/move operations
initialized by userspace.
Unless I have missed something this means that in practice that the
users of "rcu_dereference(rq->curr)" get normal RCU semantics of
rcu_dereference() for the fields the care about, despite the
assignment of rq->curr in __schedule() ot using rcu_assign_pointer.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Chris Metcalf <cmetcalf@ezchip.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Kirill Tkhai <tkhai@yandex.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russell King - ARM Linux admin <linux@armlinux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20190903200603.GW2349@hirez.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-09-14 12:35:02 +00:00
|
|
|
/*
|
|
|
|
* RCU users of rcu_dereference(rq->curr) may not see
|
|
|
|
* changes to task_struct made by pick_next_task().
|
|
|
|
*/
|
|
|
|
RCU_INIT_POINTER(rq->curr, next);
|
membarrier: Provide expedited private command
Implement MEMBARRIER_CMD_PRIVATE_EXPEDITED with IPIs using cpumask built
from all runqueues for which current thread's mm is the same as the
thread calling sys_membarrier. It executes faster than the non-expedited
variant (no blocking). It also works on NOHZ_FULL configurations.
Scheduler-wise, it requires a memory barrier before and after context
switching between processes (which have different mm). The memory
barrier before context switch is already present. For the barrier after
context switch:
* Our TSO archs can do RELEASE without being a full barrier. Look at
x86 spin_unlock() being a regular STORE for example. But for those
archs, all atomics imply smp_mb and all of them have atomic ops in
switch_mm() for mm_cpumask(), and on x86 the CR3 load acts as a full
barrier.
* From all weakly ordered machines, only ARM64 and PPC can do RELEASE,
the rest does indeed do smp_mb(), so there the spin_unlock() is a full
barrier and we're good.
* ARM64 has a very heavy barrier in switch_to(), which suffices.
* PPC just removed its barrier from switch_to(), but appears to be
talking about adding something to switch_mm(). So add a
smp_mb__after_unlock_lock() for now, until this is settled on the PPC
side.
Changes since v3:
- Properly document the memory barriers provided by each architecture.
Changes since v2:
- Address comments from Peter Zijlstra,
- Add smp_mb__after_unlock_lock() after finish_lock_switch() in
finish_task_switch() to add the memory barrier we need after storing
to rq->curr. This is much simpler than the previous approach relying
on atomic_dec_and_test() in mmdrop(), which actually added a memory
barrier in the common case of switching between userspace processes.
- Return -EINVAL when MEMBARRIER_CMD_SHARED is used on a nohz_full
kernel, rather than having the whole membarrier system call returning
-ENOSYS. Indeed, CMD_PRIVATE_EXPEDITED is compatible with nohz_full.
Adapt the CMD_QUERY mask accordingly.
Changes since v1:
- move membarrier code under kernel/sched/ because it uses the
scheduler runqueue,
- only add the barrier when we switch from a kernel thread. The case
where we switch from a user-space thread is already handled by
the atomic_dec_and_test() in mmdrop().
- add a comment to mmdrop() documenting the requirement on the implicit
memory barrier.
CC: Peter Zijlstra <peterz@infradead.org>
CC: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
CC: Boqun Feng <boqun.feng@gmail.com>
CC: Andrew Hunter <ahh@google.com>
CC: Maged Michael <maged.michael@gmail.com>
CC: gromer@google.com
CC: Avi Kivity <avi@scylladb.com>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <paulus@samba.org>
CC: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Dave Watson <davejwatson@fb.com>
2017-07-28 20:40:40 +00:00
|
|
|
/*
|
|
|
|
* The membarrier system call requires each architecture
|
|
|
|
* to have a full memory barrier after updating
|
2018-01-29 20:20:12 +00:00
|
|
|
* rq->curr, before returning to user-space.
|
|
|
|
*
|
|
|
|
* Here are the schemes providing that barrier on the
|
|
|
|
* various architectures:
|
|
|
|
* - mm ? switch_mm() : mmdrop() for x86, s390, sparc, PowerPC.
|
|
|
|
* switch_mm() rely on membarrier_arch_switch_mm() on PowerPC.
|
|
|
|
* - finish_lock_switch() for weakly-ordered
|
|
|
|
* architectures where spin_unlock is a full barrier,
|
|
|
|
* - switch_to() for arm64 (weakly-ordered, spin_unlock
|
|
|
|
* is a RELEASE barrier),
|
membarrier: Provide expedited private command
Implement MEMBARRIER_CMD_PRIVATE_EXPEDITED with IPIs using cpumask built
from all runqueues for which current thread's mm is the same as the
thread calling sys_membarrier. It executes faster than the non-expedited
variant (no blocking). It also works on NOHZ_FULL configurations.
Scheduler-wise, it requires a memory barrier before and after context
switching between processes (which have different mm). The memory
barrier before context switch is already present. For the barrier after
context switch:
* Our TSO archs can do RELEASE without being a full barrier. Look at
x86 spin_unlock() being a regular STORE for example. But for those
archs, all atomics imply smp_mb and all of them have atomic ops in
switch_mm() for mm_cpumask(), and on x86 the CR3 load acts as a full
barrier.
* From all weakly ordered machines, only ARM64 and PPC can do RELEASE,
the rest does indeed do smp_mb(), so there the spin_unlock() is a full
barrier and we're good.
* ARM64 has a very heavy barrier in switch_to(), which suffices.
* PPC just removed its barrier from switch_to(), but appears to be
talking about adding something to switch_mm(). So add a
smp_mb__after_unlock_lock() for now, until this is settled on the PPC
side.
Changes since v3:
- Properly document the memory barriers provided by each architecture.
Changes since v2:
- Address comments from Peter Zijlstra,
- Add smp_mb__after_unlock_lock() after finish_lock_switch() in
finish_task_switch() to add the memory barrier we need after storing
to rq->curr. This is much simpler than the previous approach relying
on atomic_dec_and_test() in mmdrop(), which actually added a memory
barrier in the common case of switching between userspace processes.
- Return -EINVAL when MEMBARRIER_CMD_SHARED is used on a nohz_full
kernel, rather than having the whole membarrier system call returning
-ENOSYS. Indeed, CMD_PRIVATE_EXPEDITED is compatible with nohz_full.
Adapt the CMD_QUERY mask accordingly.
Changes since v1:
- move membarrier code under kernel/sched/ because it uses the
scheduler runqueue,
- only add the barrier when we switch from a kernel thread. The case
where we switch from a user-space thread is already handled by
the atomic_dec_and_test() in mmdrop().
- add a comment to mmdrop() documenting the requirement on the implicit
memory barrier.
CC: Peter Zijlstra <peterz@infradead.org>
CC: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
CC: Boqun Feng <boqun.feng@gmail.com>
CC: Andrew Hunter <ahh@google.com>
CC: Maged Michael <maged.michael@gmail.com>
CC: gromer@google.com
CC: Avi Kivity <avi@scylladb.com>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <paulus@samba.org>
CC: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Tested-by: Dave Watson <davejwatson@fb.com>
2017-07-28 20:40:40 +00:00
|
|
|
*/
|
2005-04-16 22:20:36 +00:00
|
|
|
++*switch_count;
|
|
|
|
|
2020-03-16 19:13:31 +00:00
|
|
|
psi_sched_switch(prev, next, !task_on_rq_queued(prev));
|
|
|
|
|
2015-09-28 16:06:56 +00:00
|
|
|
trace_sched_switch(preempt, prev, next);
|
2017-02-01 10:46:42 +00:00
|
|
|
|
|
|
|
/* Also unlocks the rq: */
|
|
|
|
rq = context_switch(rq, prev, next, &rf);
|
2015-06-11 12:46:54 +00:00
|
|
|
} else {
|
2016-09-21 13:38:13 +00:00
|
|
|
rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irq(rq, &rf);
|
2015-06-11 12:46:54 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-06-11 12:46:37 +00:00
|
|
|
balance_callback(rq);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2011-06-22 17:47:00 +00:00
|
|
|
|
2016-09-13 16:37:29 +00:00
|
|
|
void __noreturn do_task_dead(void)
|
|
|
|
{
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Causes final put_task_struct in finish_task_switch(): */
|
2018-04-30 12:51:01 +00:00
|
|
|
set_special_state(TASK_DEAD);
|
2017-02-01 10:46:42 +00:00
|
|
|
|
|
|
|
/* Tell freezer to ignore us: */
|
|
|
|
current->flags |= PF_NOFREEZE;
|
|
|
|
|
2016-09-13 16:37:29 +00:00
|
|
|
__schedule(false);
|
|
|
|
BUG();
|
2017-02-01 10:46:42 +00:00
|
|
|
|
|
|
|
/* Avoid "noreturn function does return" - but don't continue if BUG() is a NOP: */
|
2016-09-13 16:37:29 +00:00
|
|
|
for (;;)
|
2017-02-01 10:46:42 +00:00
|
|
|
cpu_relax();
|
2016-09-13 16:37:29 +00:00
|
|
|
}
|
|
|
|
|
2011-06-22 17:47:01 +00:00
|
|
|
static inline void sched_submit_work(struct task_struct *tsk)
|
|
|
|
{
|
2019-08-16 16:06:26 +00:00
|
|
|
if (!tsk->state)
|
2011-06-22 17:47:01 +00:00
|
|
|
return;
|
2019-03-13 16:55:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If a worker went to sleep, notify and ask workqueue whether
|
|
|
|
* it wants to wake up a task to maintain concurrency.
|
|
|
|
* As this function is called inside the schedule() context,
|
|
|
|
* we disable preemption to avoid it calling schedule() again
|
2020-03-27 23:29:59 +00:00
|
|
|
* in the possible wakeup of a kworker and because wq_worker_sleeping()
|
|
|
|
* requires it.
|
2019-03-13 16:55:48 +00:00
|
|
|
*/
|
2019-10-22 16:25:58 +00:00
|
|
|
if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
|
2019-03-13 16:55:48 +00:00
|
|
|
preempt_disable();
|
2019-10-22 16:25:58 +00:00
|
|
|
if (tsk->flags & PF_WQ_WORKER)
|
|
|
|
wq_worker_sleeping(tsk);
|
|
|
|
else
|
|
|
|
io_wq_worker_sleeping(tsk);
|
2019-03-13 16:55:48 +00:00
|
|
|
preempt_enable_no_resched();
|
|
|
|
}
|
|
|
|
|
2019-08-16 16:06:26 +00:00
|
|
|
if (tsk_is_pi_blocked(tsk))
|
|
|
|
return;
|
|
|
|
|
2011-06-22 17:47:01 +00:00
|
|
|
/*
|
|
|
|
* If we are going to sleep and we have plugged IO queued,
|
|
|
|
* make sure to submit it to avoid deadlocks.
|
|
|
|
*/
|
|
|
|
if (blk_needs_flush_plug(tsk))
|
|
|
|
blk_schedule_flush_plug(tsk);
|
|
|
|
}
|
|
|
|
|
2019-03-13 16:55:48 +00:00
|
|
|
static void sched_update_worker(struct task_struct *tsk)
|
|
|
|
{
|
2019-10-22 16:25:58 +00:00
|
|
|
if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
|
|
|
|
if (tsk->flags & PF_WQ_WORKER)
|
|
|
|
wq_worker_running(tsk);
|
|
|
|
else
|
|
|
|
io_wq_worker_running(tsk);
|
|
|
|
}
|
2019-03-13 16:55:48 +00:00
|
|
|
}
|
|
|
|
|
2014-05-01 22:44:38 +00:00
|
|
|
asmlinkage __visible void __sched schedule(void)
|
2011-06-22 17:47:00 +00:00
|
|
|
{
|
2011-06-22 17:47:01 +00:00
|
|
|
struct task_struct *tsk = current;
|
|
|
|
|
|
|
|
sched_submit_work(tsk);
|
2015-01-28 00:24:09 +00:00
|
|
|
do {
|
2015-05-12 14:41:49 +00:00
|
|
|
preempt_disable();
|
2015-09-28 16:05:34 +00:00
|
|
|
__schedule(false);
|
2015-05-12 14:41:49 +00:00
|
|
|
sched_preempt_enable_no_resched();
|
2015-01-28 00:24:09 +00:00
|
|
|
} while (need_resched());
|
2019-03-13 16:55:48 +00:00
|
|
|
sched_update_worker(tsk);
|
2011-06-22 17:47:00 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
EXPORT_SYMBOL(schedule);
|
|
|
|
|
sched/core: Call __schedule() from do_idle() without enabling preemption
I finally got around to creating trampolines for dynamically allocated
ftrace_ops with using synchronize_rcu_tasks(). For users of the ftrace
function hook callbacks, like perf, that allocate the ftrace_ops
descriptor via kmalloc() and friends, ftrace was not able to optimize
the functions being traced to use a trampoline because they would also
need to be allocated dynamically. The problem is that they cannot be
freed when CONFIG_PREEMPT is set, as there's no way to tell if a task
was preempted on the trampoline. That was before Paul McKenney
implemented synchronize_rcu_tasks() that would make sure all tasks
(except idle) have scheduled out or have entered user space.
While testing this, I triggered this bug:
BUG: unable to handle kernel paging request at ffffffffa0230077
...
RIP: 0010:0xffffffffa0230077
...
Call Trace:
schedule+0x5/0xe0
schedule_preempt_disabled+0x18/0x30
do_idle+0x172/0x220
What happened was that the idle task was preempted on the trampoline.
As synchronize_rcu_tasks() ignores the idle thread, there's nothing
that lets ftrace know that the idle task was preempted on a trampoline.
The idle task shouldn't need to ever enable preemption. The idle task
is simply a loop that calls schedule or places the cpu into idle mode.
In fact, having preemption enabled is inefficient, because it can
happen when idle is just about to call schedule anyway, which would
cause schedule to be called twice. Once for when the interrupt came in
and was returning back to normal context, and then again in the normal
path that the idle loop is running in, which would be pointless, as it
had already scheduled.
The only reason schedule_preempt_disable() enables preemption is to be
able to call sched_submit_work(), which requires preemption enabled. As
this is a nop when the task is in the RUNNING state, and idle is always
in the running state, there's no reason that idle needs to enable
preemption. But that means it cannot use schedule_preempt_disable() as
other callers of that function require calling sched_submit_work().
Adding a new function local to kernel/sched/ that allows idle to call
the scheduler without enabling preemption, fixes the
synchronize_rcu_tasks() issue, as well as removes the pointless spurious
schedule calls caused by interrupts happening in the brief window where
preemption is enabled just before it calls schedule.
Reviewed: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20170414084809.3dacde2a@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-04-14 12:48:09 +00:00
|
|
|
/*
|
|
|
|
* synchronize_rcu_tasks() makes sure that no task is stuck in preempted
|
|
|
|
* state (have scheduled out non-voluntarily) by making sure that all
|
|
|
|
* tasks have either left the run queue or have gone into user space.
|
|
|
|
* As idle tasks do not do either, they must not ever be preempted
|
|
|
|
* (schedule out non-voluntarily).
|
|
|
|
*
|
|
|
|
* schedule_idle() is similar to schedule_preempt_disable() except that it
|
|
|
|
* never enables preemption because it does not call sched_submit_work().
|
|
|
|
*/
|
|
|
|
void __sched schedule_idle(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* As this skips calling sched_submit_work(), which the idle task does
|
|
|
|
* regardless because that function is a nop when the task is in a
|
|
|
|
* TASK_RUNNING state, make sure this isn't used someplace that the
|
|
|
|
* current task can be in any other state. Note, idle is always in the
|
|
|
|
* TASK_RUNNING state.
|
|
|
|
*/
|
|
|
|
WARN_ON_ONCE(current->state);
|
|
|
|
do {
|
|
|
|
__schedule(false);
|
|
|
|
} while (need_resched());
|
|
|
|
}
|
|
|
|
|
2012-11-27 18:33:25 +00:00
|
|
|
#ifdef CONFIG_CONTEXT_TRACKING
|
2014-05-01 22:44:38 +00:00
|
|
|
asmlinkage __visible void __sched schedule_user(void)
|
2012-07-11 18:26:37 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If we come here after a random call to set_need_resched(),
|
|
|
|
* or we have been woken up remotely but the IPI has not yet arrived,
|
|
|
|
* we haven't yet exited the RCU idle mode. Do it here manually until
|
|
|
|
* we find a better solution.
|
2014-12-03 23:37:08 +00:00
|
|
|
*
|
|
|
|
* NB: There are buggy callers of this function. Ideally we
|
2015-03-04 17:06:33 +00:00
|
|
|
* should warn if prev_state != CONTEXT_USER, but that will trigger
|
2014-12-03 23:37:08 +00:00
|
|
|
* too frequently to make sense yet.
|
2012-07-11 18:26:37 +00:00
|
|
|
*/
|
2014-12-03 23:37:08 +00:00
|
|
|
enum ctx_state prev_state = exception_enter();
|
2012-07-11 18:26:37 +00:00
|
|
|
schedule();
|
2014-12-03 23:37:08 +00:00
|
|
|
exception_exit(prev_state);
|
2012-07-11 18:26:37 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-03-21 11:09:35 +00:00
|
|
|
/**
|
|
|
|
* schedule_preempt_disabled - called with preemption disabled
|
|
|
|
*
|
|
|
|
* Returns with preemption disabled. Note: preempt_count must be 1
|
|
|
|
*/
|
|
|
|
void __sched schedule_preempt_disabled(void)
|
|
|
|
{
|
2011-03-21 12:32:17 +00:00
|
|
|
sched_preempt_enable_no_resched();
|
2011-03-21 11:09:35 +00:00
|
|
|
schedule();
|
|
|
|
preempt_disable();
|
|
|
|
}
|
|
|
|
|
2015-02-16 18:20:07 +00:00
|
|
|
static void __sched notrace preempt_schedule_common(void)
|
2015-01-22 17:08:04 +00:00
|
|
|
{
|
|
|
|
do {
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
/*
|
|
|
|
* Because the function tracer can trace preempt_count_sub()
|
|
|
|
* and it also uses preempt_enable/disable_notrace(), if
|
|
|
|
* NEED_RESCHED is set, the preempt_enable_notrace() called
|
|
|
|
* by the function tracer will call this function again and
|
|
|
|
* cause infinite recursion.
|
|
|
|
*
|
|
|
|
* Preemption must be disabled here before the function
|
|
|
|
* tracer can trace. Break up preempt_disable() into two
|
|
|
|
* calls. One to disable preemption without fear of being
|
|
|
|
* traced. The other to still record the preemption latency,
|
|
|
|
* which can also be traced by the function tracer.
|
|
|
|
*/
|
sched/core: More notrace annotations
preempt_schedule_common() is marked notrace, but it does not use
_notrace() preempt_count functions and __schedule() is also not marked
notrace, which means that its perfectly possible to end up in the
tracer from preempt_schedule_common().
Steve says:
| Yep, there's some history to this. This was originally the issue that
| caused function tracing to go into infinite recursion. But now we have
| preempt_schedule_notrace(), which is used by the function tracer, and
| that function must not be traced till preemption is disabled.
|
| Now if function tracing is running and we take an interrupt when
| NEED_RESCHED is set, it calls
|
| preempt_schedule_common() (not traced)
|
| But then that calls preempt_disable() (traced)
|
| function tracer calls preempt_disable_notrace() followed by
| preempt_enable_notrace() which will see NEED_RESCHED set, and it will
| call preempt_schedule_notrace(), which stops the recursion, but
| still calls __schedule() here, and that means when we return, we call
| the __schedule() from preempt_schedule_common().
|
| That said, I prefer this patch. Preemption is disabled before calling
| __schedule(), and we get rid of a one round recursion with the
| scheduler.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-28 16:52:36 +00:00
|
|
|
preempt_disable_notrace();
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_start(1);
|
2015-09-28 16:05:34 +00:00
|
|
|
__schedule(true);
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_stop(1);
|
sched/core: More notrace annotations
preempt_schedule_common() is marked notrace, but it does not use
_notrace() preempt_count functions and __schedule() is also not marked
notrace, which means that its perfectly possible to end up in the
tracer from preempt_schedule_common().
Steve says:
| Yep, there's some history to this. This was originally the issue that
| caused function tracing to go into infinite recursion. But now we have
| preempt_schedule_notrace(), which is used by the function tracer, and
| that function must not be traced till preemption is disabled.
|
| Now if function tracing is running and we take an interrupt when
| NEED_RESCHED is set, it calls
|
| preempt_schedule_common() (not traced)
|
| But then that calls preempt_disable() (traced)
|
| function tracer calls preempt_disable_notrace() followed by
| preempt_enable_notrace() which will see NEED_RESCHED set, and it will
| call preempt_schedule_notrace(), which stops the recursion, but
| still calls __schedule() here, and that means when we return, we call
| the __schedule() from preempt_schedule_common().
|
| That said, I prefer this patch. Preemption is disabled before calling
| __schedule(), and we get rid of a one round recursion with the
| scheduler.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-28 16:52:36 +00:00
|
|
|
preempt_enable_no_resched_notrace();
|
2015-01-22 17:08:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check again in case we missed a preemption opportunity
|
|
|
|
* between schedule and now.
|
|
|
|
*/
|
|
|
|
} while (need_resched());
|
|
|
|
}
|
|
|
|
|
2019-07-26 21:19:37 +00:00
|
|
|
#ifdef CONFIG_PREEMPTION
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2019-09-23 14:36:12 +00:00
|
|
|
* This is the entry point to schedule() from in-kernel preemption
|
|
|
|
* off of preempt_enable.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2014-05-01 22:44:38 +00:00
|
|
|
asmlinkage __visible void __sched notrace preempt_schedule(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If there is a non-zero preempt_count or interrupts are disabled,
|
2007-12-05 14:46:09 +00:00
|
|
|
* we do not want to preempt the current task. Just return..
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2013-06-19 21:56:22 +00:00
|
|
|
if (likely(!preemptible()))
|
2005-04-16 22:20:36 +00:00
|
|
|
return;
|
|
|
|
|
2015-01-22 17:08:04 +00:00
|
|
|
preempt_schedule_common();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2014-04-17 08:17:05 +00:00
|
|
|
NOKPROBE_SYMBOL(preempt_schedule);
|
2005-04-16 22:20:36 +00:00
|
|
|
EXPORT_SYMBOL(preempt_schedule);
|
2014-10-05 20:23:22 +00:00
|
|
|
|
|
|
|
/**
|
2015-06-04 15:39:08 +00:00
|
|
|
* preempt_schedule_notrace - preempt_schedule called by tracing
|
2014-10-05 20:23:22 +00:00
|
|
|
*
|
|
|
|
* The tracing infrastructure uses preempt_enable_notrace to prevent
|
|
|
|
* recursion and tracing preempt enabling caused by the tracing
|
|
|
|
* infrastructure itself. But as tracing can happen in areas coming
|
|
|
|
* from userspace or just about to enter userspace, a preempt enable
|
|
|
|
* can occur before user_exit() is called. This will cause the scheduler
|
|
|
|
* to be called when the system is still in usermode.
|
|
|
|
*
|
|
|
|
* To prevent this, the preempt_enable_notrace will use this function
|
|
|
|
* instead of preempt_schedule() to exit user context if needed before
|
|
|
|
* calling the scheduler.
|
|
|
|
*/
|
2015-06-04 15:39:08 +00:00
|
|
|
asmlinkage __visible void __sched notrace preempt_schedule_notrace(void)
|
2014-10-05 20:23:22 +00:00
|
|
|
{
|
|
|
|
enum ctx_state prev_ctx;
|
|
|
|
|
|
|
|
if (likely(!preemptible()))
|
|
|
|
return;
|
|
|
|
|
|
|
|
do {
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
/*
|
|
|
|
* Because the function tracer can trace preempt_count_sub()
|
|
|
|
* and it also uses preempt_enable/disable_notrace(), if
|
|
|
|
* NEED_RESCHED is set, the preempt_enable_notrace() called
|
|
|
|
* by the function tracer will call this function again and
|
|
|
|
* cause infinite recursion.
|
|
|
|
*
|
|
|
|
* Preemption must be disabled here before the function
|
|
|
|
* tracer can trace. Break up preempt_disable() into two
|
|
|
|
* calls. One to disable preemption without fear of being
|
|
|
|
* traced. The other to still record the preemption latency,
|
|
|
|
* which can also be traced by the function tracer.
|
|
|
|
*/
|
2015-09-28 16:09:19 +00:00
|
|
|
preempt_disable_notrace();
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_start(1);
|
2014-10-05 20:23:22 +00:00
|
|
|
/*
|
|
|
|
* Needs preempt disabled in case user_exit() is traced
|
|
|
|
* and the tracer calls preempt_enable_notrace() causing
|
|
|
|
* an infinite recursion.
|
|
|
|
*/
|
|
|
|
prev_ctx = exception_enter();
|
2015-09-28 16:05:34 +00:00
|
|
|
__schedule(true);
|
2014-10-05 20:23:22 +00:00
|
|
|
exception_exit(prev_ctx);
|
|
|
|
|
sched/core: Add preempt checks in preempt_schedule() code
While testing the tracer preemptoff, I hit this strange trace:
<...>-259 0...1 0us : schedule <-worker_thread
<...>-259 0d..1 0us : rcu_note_context_switch <-__schedule
<...>-259 0d..1 0us : rcu_sched_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : rcu_preempt_qs <-rcu_note_context_switch
<...>-259 0d..1 0us : _raw_spin_lock <-__schedule
<...>-259 0d..1 0us : preempt_count_add <-_raw_spin_lock
<...>-259 0d..2 0us : do_raw_spin_lock <-_raw_spin_lock
<...>-259 0d..2 1us : deactivate_task <-__schedule
<...>-259 0d..2 1us : update_rq_clock.part.84 <-deactivate_task
<...>-259 0d..2 1us : dequeue_task_fair <-deactivate_task
<...>-259 0d..2 1us : dequeue_entity <-dequeue_task_fair
<...>-259 0d..2 1us : update_curr <-dequeue_entity
<...>-259 0d..2 1us : update_min_vruntime <-update_curr
<...>-259 0d..2 1us : cpuacct_charge <-update_curr
<...>-259 0d..2 1us : __rcu_read_lock <-cpuacct_charge
<...>-259 0d..2 1us : __rcu_read_unlock <-cpuacct_charge
<...>-259 0d..2 1us : clear_buddies <-dequeue_entity
<...>-259 0d..2 1us : account_entity_dequeue <-dequeue_entity
<...>-259 0d..2 2us : update_min_vruntime <-dequeue_entity
<...>-259 0d..2 2us : update_cfs_shares <-dequeue_entity
<...>-259 0d..2 2us : hrtick_update <-dequeue_task_fair
<...>-259 0d..2 2us : wq_worker_sleeping <-__schedule
<...>-259 0d..2 2us : kthread_data <-wq_worker_sleeping
<...>-259 0d..2 2us : pick_next_task_fair <-__schedule
<...>-259 0d..2 2us : check_cfs_rq_runtime <-pick_next_task_fair
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : pick_next_entity <-pick_next_task_fair
<...>-259 0d..2 2us : clear_buddies <-pick_next_entity
<...>-259 0d..2 2us : set_next_entity <-pick_next_task_fair
<...>-259 0d..2 3us : put_prev_entity <-pick_next_task_fair
<...>-259 0d..2 3us : check_cfs_rq_runtime <-put_prev_entity
<...>-259 0d..2 3us : set_next_entity <-pick_next_task_fair
gnome-sh-1031 0d..2 3us : finish_task_switch <-__schedule
gnome-sh-1031 0d..2 3us : _raw_spin_unlock_irq <-finish_task_switch
gnome-sh-1031 0d..2 3us : do_raw_spin_unlock <-_raw_spin_unlock_irq
gnome-sh-1031 0...2 3us!: preempt_count_sub <-_raw_spin_unlock_irq
gnome-sh-1031 0...1 582us : do_raw_spin_lock <-_raw_spin_lock
gnome-sh-1031 0...1 583us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 583us : do_raw_spin_unlock <-_raw_spin_unlock
gnome-sh-1031 0...1 583us : preempt_count_sub <-_raw_spin_unlock
gnome-sh-1031 0...1 584us : _raw_spin_unlock <-drm_gem_object_lookup
gnome-sh-1031 0...1 584us+: trace_preempt_on <-drm_gem_object_lookup
gnome-sh-1031 0...1 603us : <stack trace>
=> preempt_count_sub
=> _raw_spin_unlock
=> drm_gem_object_lookup
=> i915_gem_madvise_ioctl
=> drm_ioctl
=> do_vfs_ioctl
=> SyS_ioctl
=> entry_SYSCALL_64_fastpath
As I'm tracing preemption disabled, it seemed incorrect that the trace
would go across a schedule and report not being in the scheduler.
Looking into this I discovered the problem.
schedule() calls preempt_disable() but the preempt_schedule() calls
preempt_enable_notrace(). What happened above was that the gnome-shell
task was preempted on another CPU, migrated over to the idle cpu. The
tracer stared with idle calling schedule(), which called
preempt_disable(), but then gnome-shell finished, and it enabled
preemption with preempt_enable_notrace() that does stop the trace, even
though preemption was enabled.
The purpose of the preempt_disable_notrace() in the preempt_schedule()
is to prevent function tracing from going into an infinite loop.
Because function tracing can trace the preempt_enable/disable() calls
that are traced. The problem with function tracing is:
NEED_RESCHED set
preempt_schedule()
preempt_disable()
preempt_count_inc()
function trace (before incrementing preempt count)
preempt_disable_notrace()
preempt_enable_notrace()
sees NEED_RESCHED set
preempt_schedule() (repeat)
Now by breaking out the preempt off/on tracing into their own code:
preempt_disable_check() and preempt_enable_check(), we can add these to
the preempt_schedule() code. As preemption would then be disabled, even
if they were to be traced by the function tracer, the disabled
preemption would prevent the recursion.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160321112339.6dc78ad6@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-03-21 15:23:39 +00:00
|
|
|
preempt_latency_stop(1);
|
2015-09-28 16:09:19 +00:00
|
|
|
preempt_enable_no_resched_notrace();
|
2014-10-05 20:23:22 +00:00
|
|
|
} while (need_resched());
|
|
|
|
}
|
2015-06-04 15:39:08 +00:00
|
|
|
EXPORT_SYMBOL_GPL(preempt_schedule_notrace);
|
2014-10-05 20:23:22 +00:00
|
|
|
|
2019-07-26 21:19:37 +00:00
|
|
|
#endif /* CONFIG_PREEMPTION */
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
2019-09-23 14:36:12 +00:00
|
|
|
* This is the entry point to schedule() from kernel preemption
|
2005-04-16 22:20:36 +00:00
|
|
|
* off of irq context.
|
|
|
|
* Note, that this is called and return with irqs disabled. This will
|
|
|
|
* protect us against recursive calling from irq.
|
|
|
|
*/
|
2014-05-01 22:44:38 +00:00
|
|
|
asmlinkage __visible void __sched preempt_schedule_irq(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2013-02-24 11:59:30 +00:00
|
|
|
enum ctx_state prev_state;
|
2008-01-25 20:08:33 +00:00
|
|
|
|
2006-07-10 11:43:52 +00:00
|
|
|
/* Catch callers which need to be fixed */
|
2013-08-14 12:55:31 +00:00
|
|
|
BUG_ON(preempt_count() || !irqs_disabled());
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-02-24 11:59:30 +00:00
|
|
|
prev_state = exception_enter();
|
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
do {
|
2015-09-28 16:09:19 +00:00
|
|
|
preempt_disable();
|
2007-10-15 15:00:14 +00:00
|
|
|
local_irq_enable();
|
2015-09-28 16:05:34 +00:00
|
|
|
__schedule(true);
|
2007-10-15 15:00:14 +00:00
|
|
|
local_irq_disable();
|
2015-09-28 16:09:19 +00:00
|
|
|
sched_preempt_enable_no_resched();
|
2009-03-06 11:40:20 +00:00
|
|
|
} while (need_resched());
|
2013-02-24 11:59:30 +00:00
|
|
|
|
|
|
|
exception_exit(prev_state);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2017-06-20 10:06:13 +00:00
|
|
|
int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,
|
2005-09-10 07:26:11 +00:00
|
|
|
void *key)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2009-09-15 17:14:42 +00:00
|
|
|
return try_to_wake_up(curr->private, mode, wake_flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(default_wake_function);
|
|
|
|
|
2006-06-27 09:54:51 +00:00
|
|
|
#ifdef CONFIG_RT_MUTEXES
|
|
|
|
|
2017-03-23 14:56:11 +00:00
|
|
|
static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
|
|
|
|
{
|
|
|
|
if (pi_task)
|
|
|
|
prio = min(prio, pi_task->prio);
|
|
|
|
|
|
|
|
return prio;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int rt_effective_prio(struct task_struct *p, int prio)
|
|
|
|
{
|
|
|
|
struct task_struct *pi_task = rt_mutex_get_top_task(p);
|
|
|
|
|
|
|
|
return __rt_effective_prio(pi_task, prio);
|
|
|
|
}
|
|
|
|
|
2006-06-27 09:54:51 +00:00
|
|
|
/*
|
|
|
|
* rt_mutex_setprio - set the current priority of a task
|
2017-03-23 14:56:11 +00:00
|
|
|
* @p: task to boost
|
|
|
|
* @pi_task: donor task
|
2006-06-27 09:54:51 +00:00
|
|
|
*
|
|
|
|
* This function changes the 'effective' priority of a task. It does
|
|
|
|
* not touch ->normal_prio like __setscheduler().
|
|
|
|
*
|
2014-02-07 19:58:42 +00:00
|
|
|
* Used by the rt_mutex code to implement priority inheritance
|
|
|
|
* logic. Call site only calls if the priority of the task changed.
|
2006-06-27 09:54:51 +00:00
|
|
|
*/
|
2017-03-23 14:56:11 +00:00
|
|
|
void rt_mutex_setprio(struct task_struct *p, struct task_struct *pi_task)
|
2006-06-27 09:54:51 +00:00
|
|
|
{
|
2017-03-23 14:56:11 +00:00
|
|
|
int prio, oldprio, queued, running, queue_flag =
|
2017-02-21 13:47:02 +00:00
|
|
|
DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK;
|
2010-02-17 08:05:48 +00:00
|
|
|
const struct sched_class *prev_class;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
2006-06-27 09:54:51 +00:00
|
|
|
|
2017-03-23 14:56:11 +00:00
|
|
|
/* XXX used to be waiter->prio, not waiter->task->prio */
|
|
|
|
prio = __rt_effective_prio(pi_task, p->normal_prio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If nothing changed; bail early.
|
|
|
|
*/
|
|
|
|
if (p->pi_top_task == pi_task && prio == p->prio && !dl_prio(prio))
|
|
|
|
return;
|
2006-06-27 09:54:51 +00:00
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = __task_rq_lock(p, &rf);
|
2016-10-03 14:28:37 +00:00
|
|
|
update_rq_clock(rq);
|
2017-03-23 14:56:11 +00:00
|
|
|
/*
|
|
|
|
* Set under pi_lock && rq->lock, such that the value can be used under
|
|
|
|
* either lock.
|
|
|
|
*
|
|
|
|
* Note that there is loads of tricky to make this pointer cache work
|
|
|
|
* right. rt_mutex_slowunlock()+rt_mutex_postunlock() work together to
|
|
|
|
* ensure a task is de-boosted (pi_task is set to NULL) before the
|
|
|
|
* task is allowed to run again (and can exit). This ensures the pointer
|
|
|
|
* points to a blocked task -- which guaratees the task is present.
|
|
|
|
*/
|
|
|
|
p->pi_top_task = pi_task;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For FIFO/RR we only need to set prio, if that matches we're done.
|
|
|
|
*/
|
|
|
|
if (prio == p->prio && !dl_prio(prio))
|
|
|
|
goto out_unlock;
|
2006-06-27 09:54:51 +00:00
|
|
|
|
2011-06-06 18:07:38 +00:00
|
|
|
/*
|
|
|
|
* Idle task boosting is a nono in general. There is one
|
|
|
|
* exception, when PREEMPT_RT and NOHZ is active:
|
|
|
|
*
|
|
|
|
* The idle task calls get_next_timer_interrupt() and holds
|
|
|
|
* the timer wheel base->lock on the CPU and another CPU wants
|
|
|
|
* to access the timer (probably to cancel it). We can safely
|
|
|
|
* ignore the boosting request, as the idle CPU runs this code
|
|
|
|
* with interrupts disabled and will complete the lock
|
|
|
|
* protected section without being interrupted. So there is no
|
|
|
|
* real need to boost.
|
|
|
|
*/
|
|
|
|
if (unlikely(p == rq->idle)) {
|
|
|
|
WARN_ON(p != rq->curr);
|
|
|
|
WARN_ON(p->pi_blocked_on);
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
|
|
|
|
2017-03-23 14:56:12 +00:00
|
|
|
trace_sched_pi_setprio(p, pi_task);
|
2007-05-09 03:27:06 +00:00
|
|
|
oldprio = p->prio;
|
2016-01-18 14:27:07 +00:00
|
|
|
|
|
|
|
if (oldprio == prio)
|
|
|
|
queue_flag &= ~DEQUEUE_MOVE;
|
|
|
|
|
2010-02-17 08:05:48 +00:00
|
|
|
prev_class = p->sched_class;
|
2014-08-20 09:47:32 +00:00
|
|
|
queued = task_on_rq_queued(p);
|
2007-12-18 14:21:13 +00:00
|
|
|
running = task_current(rq, p);
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2016-01-18 14:27:07 +00:00
|
|
|
dequeue_task(rq, p, queue_flag);
|
2008-03-10 18:01:20 +00:00
|
|
|
if (running)
|
2014-09-12 13:41:40 +00:00
|
|
|
put_prev_task(rq, p);
|
2007-07-09 16:51:59 +00:00
|
|
|
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
/*
|
|
|
|
* Boosting condition are:
|
|
|
|
* 1. -rt task is running and holds mutex A
|
|
|
|
* --> -dl task blocks on mutex A
|
|
|
|
*
|
|
|
|
* 2. -dl task is running and holds mutex A
|
|
|
|
* --> -dl task blocks on mutex A and could preempt the
|
|
|
|
* running task
|
|
|
|
*/
|
|
|
|
if (dl_prio(prio)) {
|
2014-06-06 16:52:06 +00:00
|
|
|
if (!dl_prio(p->normal_prio) ||
|
|
|
|
(pi_task && dl_entity_preempt(&pi_task->dl, &p->dl))) {
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
p->dl.dl_boosted = 1;
|
2016-01-18 14:27:07 +00:00
|
|
|
queue_flag |= ENQUEUE_REPLENISH;
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
} else
|
|
|
|
p->dl.dl_boosted = 0;
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
p->sched_class = &dl_sched_class;
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
} else if (rt_prio(prio)) {
|
|
|
|
if (dl_prio(oldprio))
|
|
|
|
p->dl.dl_boosted = 0;
|
|
|
|
if (oldprio < prio)
|
2016-01-18 14:27:07 +00:00
|
|
|
queue_flag |= ENQUEUE_HEAD;
|
2007-07-09 16:51:59 +00:00
|
|
|
p->sched_class = &rt_sched_class;
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
} else {
|
|
|
|
if (dl_prio(oldprio))
|
|
|
|
p->dl.dl_boosted = 0;
|
2015-02-19 00:23:56 +00:00
|
|
|
if (rt_prio(oldprio))
|
|
|
|
p->rt.timeout = 0;
|
2007-07-09 16:51:59 +00:00
|
|
|
p->sched_class = &fair_sched_class;
|
sched/deadline: Add SCHED_DEADLINE inheritance logic
Some method to deal with rt-mutexes and make sched_dl interact with
the current PI-coded is needed, raising all but trivial issues, that
needs (according to us) to be solved with some restructuring of
the pi-code (i.e., going toward a proxy execution-ish implementation).
This is under development, in the meanwhile, as a temporary solution,
what this commits does is:
- ensure a pi-lock owner with waiters is never throttled down. Instead,
when it runs out of runtime, it immediately gets replenished and it's
deadline is postponed;
- the scheduling parameters (relative deadline and default runtime)
used for that replenishments --during the whole period it holds the
pi-lock-- are the ones of the waiting task with earliest deadline.
Acting this way, we provide some kind of boosting to the lock-owner,
still by using the existing (actually, slightly modified by the previous
commit) pi-architecture.
We would stress the fact that this is only a surely needed, all but
clean solution to the problem. In the end it's only a way to re-start
discussion within the community. So, as always, comments, ideas, rants,
etc.. are welcome! :-)
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Added !RT_MUTEXES build fix. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-11-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:44 +00:00
|
|
|
}
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2006-06-27 09:54:51 +00:00
|
|
|
p->prio = prio;
|
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2016-01-18 14:27:07 +00:00
|
|
|
enqueue_task(rq, p, queue_flag);
|
2016-09-12 07:47:52 +00:00
|
|
|
if (running)
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, p);
|
2008-01-25 20:08:22 +00:00
|
|
|
|
2011-01-17 16:03:27 +00:00
|
|
|
check_class_changed(rq, p, prev_class, oldprio);
|
2011-06-06 18:07:38 +00:00
|
|
|
out_unlock:
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Avoid rq from going away on us: */
|
|
|
|
preempt_disable();
|
2015-07-31 19:28:18 +00:00
|
|
|
__task_rq_unlock(rq, &rf);
|
2015-06-11 12:46:39 +00:00
|
|
|
|
|
|
|
balance_callback(rq);
|
|
|
|
preempt_enable();
|
2006-06-27 09:54:51 +00:00
|
|
|
}
|
2017-03-23 14:56:11 +00:00
|
|
|
#else
|
|
|
|
static inline int rt_effective_prio(struct task_struct *p, int prio)
|
|
|
|
{
|
|
|
|
return prio;
|
|
|
|
}
|
2006-06-27 09:54:51 +00:00
|
|
|
#endif
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2006-07-03 07:25:41 +00:00
|
|
|
void set_user_nice(struct task_struct *p, long nice)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2016-09-20 20:06:01 +00:00
|
|
|
bool queued, running;
|
2019-12-19 14:03:14 +00:00
|
|
|
int old_prio;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2006-07-03 07:25:42 +00:00
|
|
|
struct rq *rq;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-02-11 07:34:50 +00:00
|
|
|
if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE)
|
2005-04-16 22:20:36 +00:00
|
|
|
return;
|
|
|
|
/*
|
|
|
|
* We have to be careful, if called from sys_setpriority(),
|
|
|
|
* the task might be in the middle of scheduling on another CPU.
|
|
|
|
*/
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2016-10-03 14:44:25 +00:00
|
|
|
update_rq_clock(rq);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* The RT priorities are set via sched_setscheduler(), but we still
|
|
|
|
* allow the 'normal' nice value to be set - but as expected
|
|
|
|
* it wont have any effect on scheduling until the task is
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
* SCHED_DEADLINE, SCHED_FIFO or SCHED_RR:
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (task_has_dl_policy(p) || task_has_rt_policy(p)) {
|
2005-04-16 22:20:36 +00:00
|
|
|
p->static_prio = NICE_TO_PRIO(nice);
|
|
|
|
goto out_unlock;
|
|
|
|
}
|
2014-08-20 09:47:32 +00:00
|
|
|
queued = task_on_rq_queued(p);
|
2016-09-20 20:06:01 +00:00
|
|
|
running = task_current(rq, p);
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2017-02-21 13:47:02 +00:00
|
|
|
dequeue_task(rq, p, DEQUEUE_SAVE | DEQUEUE_NOCLOCK);
|
2016-09-20 20:06:01 +00:00
|
|
|
if (running)
|
|
|
|
put_prev_task(rq, p);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
p->static_prio = NICE_TO_PRIO(nice);
|
2017-05-17 09:50:45 +00:00
|
|
|
set_load_weight(p, true);
|
2006-06-27 09:54:51 +00:00
|
|
|
old_prio = p->prio;
|
|
|
|
p->prio = effective_prio(p);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-12-03 16:01:06 +00:00
|
|
|
if (queued)
|
2017-02-21 13:23:38 +00:00
|
|
|
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
|
2016-09-20 20:06:01 +00:00
|
|
|
if (running)
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, p);
|
2019-12-03 16:01:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the task increased its priority or is running and
|
|
|
|
* lowered its priority, then reschedule its CPU:
|
|
|
|
*/
|
|
|
|
p->sched_class->prio_changed(rq, p, old_prio);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
out_unlock:
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(set_user_nice);
|
|
|
|
|
2005-05-01 15:59:00 +00:00
|
|
|
/*
|
|
|
|
* can_nice - check if a task can reduce its nice value
|
|
|
|
* @p: task
|
|
|
|
* @nice: nice value
|
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
int can_nice(const struct task_struct *p, const int nice)
|
2005-05-01 15:59:00 +00:00
|
|
|
{
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Convert nice value [19,-20] to rlimit style value [1,40]: */
|
2014-05-08 09:33:49 +00:00
|
|
|
int nice_rlim = nice_to_rlimit(nice);
|
2006-07-03 07:25:40 +00:00
|
|
|
|
2010-03-05 21:42:54 +00:00
|
|
|
return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) ||
|
2005-05-01 15:59:00 +00:00
|
|
|
capable(CAP_SYS_NICE));
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef __ARCH_WANT_SYS_NICE
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sys_nice - change the priority of the current process.
|
|
|
|
* @increment: priority increment
|
|
|
|
*
|
|
|
|
* sys_setpriority is a more generic, but much slower function that
|
|
|
|
* does similar things.
|
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE1(nice, int, increment)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:40 +00:00
|
|
|
long nice, retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Setpriority might change our priority at the same moment.
|
|
|
|
* We don't have to worry. Conceptually one call occurs first
|
|
|
|
* and we have a single winner.
|
|
|
|
*/
|
2014-05-08 09:35:15 +00:00
|
|
|
increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH);
|
2014-01-28 03:00:45 +00:00
|
|
|
nice = task_nice(current) + increment;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-05-08 09:35:15 +00:00
|
|
|
nice = clamp_val(nice, MIN_NICE, MAX_NICE);
|
2005-05-01 15:59:00 +00:00
|
|
|
if (increment < 0 && !can_nice(current, nice))
|
|
|
|
return -EPERM;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
retval = security_task_setnice(current, nice);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
set_user_nice(current, nice);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**
|
|
|
|
* task_prio - return the priority value of a given task.
|
|
|
|
* @p: the task in question.
|
|
|
|
*
|
2013-07-12 18:45:47 +00:00
|
|
|
* Return: The priority value as seen by users in /proc.
|
2005-04-16 22:20:36 +00:00
|
|
|
* RT tasks are offset by -200. Normal tasks are centered
|
|
|
|
* around 0, value goes from -16 to +15.
|
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
int task_prio(const struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
return p->prio - MAX_RT_PRIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-01 10:46:42 +00:00
|
|
|
* idle_cpu - is a given CPU idle currently?
|
2005-04-16 22:20:36 +00:00
|
|
|
* @cpu: the processor in question.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 1 if the CPU is currently idle. 0 otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
int idle_cpu(int cpu)
|
|
|
|
{
|
2011-09-15 13:32:06 +00:00
|
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
|
|
|
|
if (rq->curr != rq->idle)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (rq->nr_running)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
if (!llist_empty(&rq->wake_list))
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2018-05-09 16:39:48 +00:00
|
|
|
/**
|
|
|
|
* available_idle_cpu - is a given CPU idle for enqueuing work.
|
|
|
|
* @cpu: the CPU in question.
|
|
|
|
*
|
|
|
|
* Return: 1 if the CPU is currently idle. 0 otherwise.
|
|
|
|
*/
|
|
|
|
int available_idle_cpu(int cpu)
|
|
|
|
{
|
|
|
|
if (!idle_cpu(cpu))
|
|
|
|
return 0;
|
|
|
|
|
2018-05-02 20:52:10 +00:00
|
|
|
if (vcpu_is_preempted(cpu))
|
|
|
|
return 0;
|
|
|
|
|
2011-09-15 13:32:06 +00:00
|
|
|
return 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-01 10:46:42 +00:00
|
|
|
* idle_task - return the idle task for a given CPU.
|
2005-04-16 22:20:36 +00:00
|
|
|
* @cpu: the processor in question.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Return: The idle task for the CPU @cpu.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *idle_task(int cpu)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
return cpu_rq(cpu)->idle;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* find_process_by_pid - find a process with a matching PID value.
|
|
|
|
* @pid: the pid in question.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* The task of @pid, if found. %NULL otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2007-10-15 15:00:13 +00:00
|
|
|
static struct task_struct *find_process_by_pid(pid_t pid)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2007-10-19 06:40:16 +00:00
|
|
|
return pid ? find_task_by_vpid(pid) : current;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2014-07-23 15:28:26 +00:00
|
|
|
/*
|
|
|
|
* sched_setparam() passes in -1 for its policy, to let the functions
|
|
|
|
* it calls know not to change it.
|
|
|
|
*/
|
|
|
|
#define SETPARAM_POLICY -1
|
|
|
|
|
2014-02-07 19:58:42 +00:00
|
|
|
static void __setscheduler_params(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
int policy = attr->sched_policy;
|
|
|
|
|
2014-07-23 15:28:26 +00:00
|
|
|
if (policy == SETPARAM_POLICY)
|
2014-01-15 15:33:20 +00:00
|
|
|
policy = p->policy;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
p->policy = policy;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (dl_policy(policy))
|
|
|
|
__setparam_dl(p, attr);
|
2014-01-15 15:33:20 +00:00
|
|
|
else if (fair_policy(policy))
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
p->static_prio = NICE_TO_PRIO(attr->sched_nice);
|
|
|
|
|
2014-01-15 15:33:20 +00:00
|
|
|
/*
|
|
|
|
* __sched_setscheduler() ensures attr->sched_priority == 0 when
|
|
|
|
* !rt_policy. Always setting this ensures that things like
|
|
|
|
* getparam()/getattr() don't report silly values for !rt tasks.
|
|
|
|
*/
|
|
|
|
p->rt_priority = attr->sched_priority;
|
sched: Fix broken setscheduler()
I decided to run my tests on linux-next, and my wakeup_rt tracer was
broken. After running a bisect, I found that the problem commit was:
linux-next commit c365c292d059
"sched: Consider pi boosting in setscheduler()"
And the reason the wake_rt tracer test was failing, was because it had
no RT task to trace. I first noticed this when running with
sched_switch event and saw that my RT task still had normal SCHED_OTHER
priority. Looking at the problem commit, I found:
- p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
With no
+ p->normal_prio = normal_prio(p);
+ p->prio = rt_mutex_getprio(p);
Reading what the commit is suppose to do, I realize that the p->prio
can't be set if the task is boosted with a higher prio, but the
p->normal_prio still needs to be set regardless, otherwise, when the
task is deboosted, it wont get the new priority.
The p->prio has to be set before "check_class_changed()" is called,
otherwise the class wont be changed.
Also added fix to newprio to include a check for deadline policy that
was missing. This change was suggested by Juri Lelli.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: SebastianAndrzej Siewior <bigeasy@linutronix.de>
Cc: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140306120438.638bfe94@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-03-11 23:24:20 +00:00
|
|
|
p->normal_prio = normal_prio(p);
|
2017-05-17 09:50:45 +00:00
|
|
|
set_load_weight(p, true);
|
2014-02-07 19:58:42 +00:00
|
|
|
}
|
2014-01-15 15:33:20 +00:00
|
|
|
|
2014-02-07 19:58:42 +00:00
|
|
|
/* Actually do priority change: must hold pi & rq lock. */
|
|
|
|
static void __setscheduler(struct rq *rq, struct task_struct *p,
|
2015-05-05 17:49:49 +00:00
|
|
|
const struct sched_attr *attr, bool keep_boost)
|
2014-02-07 19:58:42 +00:00
|
|
|
{
|
2019-06-21 08:42:07 +00:00
|
|
|
/*
|
|
|
|
* If params can't change scheduling class changes aren't allowed
|
|
|
|
* either.
|
|
|
|
*/
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_KEEP_PARAMS)
|
|
|
|
return;
|
|
|
|
|
2014-02-07 19:58:42 +00:00
|
|
|
__setscheduler_params(p, attr);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
sched: Fix broken setscheduler()
I decided to run my tests on linux-next, and my wakeup_rt tracer was
broken. After running a bisect, I found that the problem commit was:
linux-next commit c365c292d059
"sched: Consider pi boosting in setscheduler()"
And the reason the wake_rt tracer test was failing, was because it had
no RT task to trace. I first noticed this when running with
sched_switch event and saw that my RT task still had normal SCHED_OTHER
priority. Looking at the problem commit, I found:
- p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
With no
+ p->normal_prio = normal_prio(p);
+ p->prio = rt_mutex_getprio(p);
Reading what the commit is suppose to do, I realize that the p->prio
can't be set if the task is boosted with a higher prio, but the
p->normal_prio still needs to be set regardless, otherwise, when the
task is deboosted, it wont get the new priority.
The p->prio has to be set before "check_class_changed()" is called,
otherwise the class wont be changed.
Also added fix to newprio to include a check for deadline policy that
was missing. This change was suggested by Juri Lelli.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: SebastianAndrzej Siewior <bigeasy@linutronix.de>
Cc: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140306120438.638bfe94@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-03-11 23:24:20 +00:00
|
|
|
/*
|
2015-05-05 17:49:49 +00:00
|
|
|
* Keep a potential priority boosting if called from
|
|
|
|
* sched_setscheduler().
|
sched: Fix broken setscheduler()
I decided to run my tests on linux-next, and my wakeup_rt tracer was
broken. After running a bisect, I found that the problem commit was:
linux-next commit c365c292d059
"sched: Consider pi boosting in setscheduler()"
And the reason the wake_rt tracer test was failing, was because it had
no RT task to trace. I first noticed this when running with
sched_switch event and saw that my RT task still had normal SCHED_OTHER
priority. Looking at the problem commit, I found:
- p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
With no
+ p->normal_prio = normal_prio(p);
+ p->prio = rt_mutex_getprio(p);
Reading what the commit is suppose to do, I realize that the p->prio
can't be set if the task is boosted with a higher prio, but the
p->normal_prio still needs to be set regardless, otherwise, when the
task is deboosted, it wont get the new priority.
The p->prio has to be set before "check_class_changed()" is called,
otherwise the class wont be changed.
Also added fix to newprio to include a check for deadline policy that
was missing. This change was suggested by Juri Lelli.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: SebastianAndrzej Siewior <bigeasy@linutronix.de>
Cc: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140306120438.638bfe94@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-03-11 23:24:20 +00:00
|
|
|
*/
|
2017-03-23 14:56:11 +00:00
|
|
|
p->prio = normal_prio(p);
|
2015-05-05 17:49:49 +00:00
|
|
|
if (keep_boost)
|
2017-03-23 14:56:11 +00:00
|
|
|
p->prio = rt_effective_prio(p, p->prio);
|
sched: Fix broken setscheduler()
I decided to run my tests on linux-next, and my wakeup_rt tracer was
broken. After running a bisect, I found that the problem commit was:
linux-next commit c365c292d059
"sched: Consider pi boosting in setscheduler()"
And the reason the wake_rt tracer test was failing, was because it had
no RT task to trace. I first noticed this when running with
sched_switch event and saw that my RT task still had normal SCHED_OTHER
priority. Looking at the problem commit, I found:
- p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
With no
+ p->normal_prio = normal_prio(p);
+ p->prio = rt_mutex_getprio(p);
Reading what the commit is suppose to do, I realize that the p->prio
can't be set if the task is boosted with a higher prio, but the
p->normal_prio still needs to be set regardless, otherwise, when the
task is deboosted, it wont get the new priority.
The p->prio has to be set before "check_class_changed()" is called,
otherwise the class wont be changed.
Also added fix to newprio to include a check for deadline policy that
was missing. This change was suggested by Juri Lelli.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: SebastianAndrzej Siewior <bigeasy@linutronix.de>
Cc: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140306120438.638bfe94@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-03-11 23:24:20 +00:00
|
|
|
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (dl_prio(p->prio))
|
|
|
|
p->sched_class = &dl_sched_class;
|
|
|
|
else if (rt_prio(p->prio))
|
2009-11-10 19:12:01 +00:00
|
|
|
p->sched_class = &rt_sched_class;
|
|
|
|
else
|
|
|
|
p->sched_class = &fair_sched_class;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
|
2008-11-13 23:39:19 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Check the target process has a UID that matches the current process's:
|
2008-11-13 23:39:19 +00:00
|
|
|
*/
|
|
|
|
static bool check_same_owner(struct task_struct *p)
|
|
|
|
{
|
|
|
|
const struct cred *cred = current_cred(), *pcred;
|
|
|
|
bool match;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
pcred = __task_cred(p);
|
2012-02-03 02:54:02 +00:00
|
|
|
match = (uid_eq(cred->euid, pcred->euid) ||
|
|
|
|
uid_eq(cred->euid, pcred->uid));
|
2008-11-13 23:39:19 +00:00
|
|
|
rcu_read_unlock();
|
|
|
|
return match;
|
|
|
|
}
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
static int __sched_setscheduler(struct task_struct *p,
|
|
|
|
const struct sched_attr *attr,
|
2015-06-11 12:46:38 +00:00
|
|
|
bool user, bool pi)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
sched: Fix broken setscheduler()
I decided to run my tests on linux-next, and my wakeup_rt tracer was
broken. After running a bisect, I found that the problem commit was:
linux-next commit c365c292d059
"sched: Consider pi boosting in setscheduler()"
And the reason the wake_rt tracer test was failing, was because it had
no RT task to trace. I first noticed this when running with
sched_switch event and saw that my RT task still had normal SCHED_OTHER
priority. Looking at the problem commit, I found:
- p->normal_prio = normal_prio(p);
- p->prio = rt_mutex_getprio(p);
With no
+ p->normal_prio = normal_prio(p);
+ p->prio = rt_mutex_getprio(p);
Reading what the commit is suppose to do, I realize that the p->prio
can't be set if the task is boosted with a higher prio, but the
p->normal_prio still needs to be set regardless, otherwise, when the
task is deboosted, it wont get the new priority.
The p->prio has to be set before "check_class_changed()" is called,
otherwise the class wont be changed.
Also added fix to newprio to include a check for deadline policy that
was missing. This change was suggested by Juri Lelli.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: SebastianAndrzej Siewior <bigeasy@linutronix.de>
Cc: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20140306120438.638bfe94@gandalf.local.home
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2014-03-11 23:24:20 +00:00
|
|
|
int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 :
|
|
|
|
MAX_RT_PRIO - 1 - attr->sched_priority;
|
2014-08-20 09:47:32 +00:00
|
|
|
int retval, oldprio, oldpolicy = -1, queued, running;
|
2015-05-05 17:49:49 +00:00
|
|
|
int new_effective_prio, policy = attr->sched_policy;
|
2010-02-17 08:05:48 +00:00
|
|
|
const struct sched_class *prev_class;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2009-06-15 15:17:47 +00:00
|
|
|
int reset_on_fork;
|
2017-02-21 13:47:02 +00:00
|
|
|
int queue_flags = DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq *rq;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2017-03-09 15:18:42 +00:00
|
|
|
/* The pi code expects interrupts enabled */
|
|
|
|
BUG_ON(pi && in_interrupt());
|
2005-04-16 22:20:36 +00:00
|
|
|
recheck:
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Double check policy once rq lock held: */
|
2009-06-15 15:17:47 +00:00
|
|
|
if (policy < 0) {
|
|
|
|
reset_on_fork = p->sched_reset_on_fork;
|
2005-04-16 22:20:36 +00:00
|
|
|
policy = oldpolicy = p->policy;
|
2009-06-15 15:17:47 +00:00
|
|
|
} else {
|
2014-01-15 16:05:04 +00:00
|
|
|
reset_on_fork = !!(attr->sched_flags & SCHED_FLAG_RESET_ON_FORK);
|
2009-06-15 15:17:47 +00:00
|
|
|
|
2015-09-09 15:00:41 +00:00
|
|
|
if (!valid_policy(policy))
|
2009-06-15 15:17:47 +00:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2017-12-04 10:23:20 +00:00
|
|
|
if (attr->sched_flags & ~(SCHED_FLAG_ALL | SCHED_FLAG_SUGOV))
|
2014-01-15 16:05:04 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* Valid priorities for SCHED_FIFO and SCHED_RR are
|
2007-07-09 16:51:59 +00:00
|
|
|
* 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL,
|
|
|
|
* SCHED_BATCH and SCHED_IDLE is 0.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2014-01-15 16:15:13 +00:00
|
|
|
if ((p->mm && attr->sched_priority > MAX_USER_RT_PRIO-1) ||
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
(!p->mm && attr->sched_priority > MAX_RT_PRIO-1))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if ((dl_policy(policy) && !__checkparam_dl(attr)) ||
|
|
|
|
(rt_policy(policy) != (attr->sched_priority != 0)))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
[PATCH] Changing RT priority without CAP_SYS_NICE
Presently, a process without the capability CAP_SYS_NICE can not change
its own policy, which is OK.
But it can also not decrease its RT priority (if scheduled with policy
SCHED_RR or SCHED_FIFO), which is what this patch changes.
The rationale is the same as for the nice value: a process should be
able to require less priority for itself. Increasing the priority is
still not allowed.
This is for example useful if you give a multithreaded user process a RT
priority, and the process would like to organize its internal threads
using priorities also. Then you can give the process the highest
priority needed N, and the process starts its threads with lower
priorities: N-1, N-2...
The POSIX norm says that the permissions are implementation specific, so
I think we can do that.
In a sense, it makes the permissions consistent whatever the policy is:
with this patch, process scheduled by SCHED_FIFO, SCHED_RR and
SCHED_OTHER can all decrease their priority.
From: Ingo Molnar <mingo@elte.hu>
cleaned up and merged to -mm.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-25 21:57:32 +00:00
|
|
|
/*
|
|
|
|
* Allow unprivileged RT tasks to decrease priority:
|
|
|
|
*/
|
2008-06-23 03:55:38 +00:00
|
|
|
if (user && !capable(CAP_SYS_NICE)) {
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
if (fair_policy(policy)) {
|
2014-01-28 03:00:45 +00:00
|
|
|
if (attr->sched_nice < task_nice(p) &&
|
2014-01-16 16:54:25 +00:00
|
|
|
!can_nice(p, attr->sched_nice))
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
if (rt_policy(policy)) {
|
2010-06-10 23:09:44 +00:00
|
|
|
unsigned long rlim_rtprio =
|
|
|
|
task_rlimit(p, RLIMIT_RTPRIO);
|
2006-09-29 09:00:50 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Can't set/change the rt policy: */
|
2006-09-29 09:00:50 +00:00
|
|
|
if (policy != p->policy && !rlim_rtprio)
|
|
|
|
return -EPERM;
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Can't increase priority: */
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
if (attr->sched_priority > p->rt_priority &&
|
|
|
|
attr->sched_priority > rlim_rtprio)
|
2006-09-29 09:00:50 +00:00
|
|
|
return -EPERM;
|
|
|
|
}
|
2011-02-17 23:37:07 +00:00
|
|
|
|
2014-03-03 11:09:21 +00:00
|
|
|
/*
|
|
|
|
* Can't set/change SCHED_DEADLINE policy at all for now
|
|
|
|
* (safest behavior); in the future we would like to allow
|
|
|
|
* unprivileged DL tasks to increase their relative deadline
|
|
|
|
* or reduce their runtime (both ways reducing utilization)
|
|
|
|
*/
|
|
|
|
if (dl_policy(policy))
|
|
|
|
return -EPERM;
|
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
2011-02-17 23:37:07 +00:00
|
|
|
* Treat SCHED_IDLE as nice 20. Only allow a switch to
|
|
|
|
* SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
|
2007-07-09 16:51:59 +00:00
|
|
|
*/
|
2018-11-05 11:21:55 +00:00
|
|
|
if (task_has_idle_policy(p) && !idle_policy(policy)) {
|
2014-01-28 03:00:45 +00:00
|
|
|
if (!can_nice(p, task_nice(p)))
|
2011-02-17 23:37:07 +00:00
|
|
|
return -EPERM;
|
|
|
|
}
|
2006-09-29 09:00:48 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Can't change other user's priorities: */
|
2008-11-13 23:39:19 +00:00
|
|
|
if (!check_same_owner(p))
|
[PATCH] Changing RT priority without CAP_SYS_NICE
Presently, a process without the capability CAP_SYS_NICE can not change
its own policy, which is OK.
But it can also not decrease its RT priority (if scheduled with policy
SCHED_RR or SCHED_FIFO), which is what this patch changes.
The rationale is the same as for the nice value: a process should be
able to require less priority for itself. Increasing the priority is
still not allowed.
This is for example useful if you give a multithreaded user process a RT
priority, and the process would like to organize its internal threads
using priorities also. Then you can give the process the highest
priority needed N, and the process starts its threads with lower
priorities: N-1, N-2...
The POSIX norm says that the permissions are implementation specific, so
I think we can do that.
In a sense, it makes the permissions consistent whatever the policy is:
with this patch, process scheduled by SCHED_FIFO, SCHED_RR and
SCHED_OTHER can all decrease their priority.
From: Ingo Molnar <mingo@elte.hu>
cleaned up and merged to -mm.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-25 21:57:32 +00:00
|
|
|
return -EPERM;
|
2009-06-15 15:17:47 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Normal users shall not reset the sched_reset_on_fork flag: */
|
2009-06-15 15:17:47 +00:00
|
|
|
if (p->sched_reset_on_fork && !reset_on_fork)
|
|
|
|
return -EPERM;
|
[PATCH] Changing RT priority without CAP_SYS_NICE
Presently, a process without the capability CAP_SYS_NICE can not change
its own policy, which is OK.
But it can also not decrease its RT priority (if scheduled with policy
SCHED_RR or SCHED_FIFO), which is what this patch changes.
The rationale is the same as for the nice value: a process should be
able to require less priority for itself. Increasing the priority is
still not allowed.
This is for example useful if you give a multithreaded user process a RT
priority, and the process would like to organize its internal threads
using priorities also. Then you can give the process the highest
priority needed N, and the process starts its threads with lower
priorities: N-1, N-2...
The POSIX norm says that the permissions are implementation specific, so
I think we can do that.
In a sense, it makes the permissions consistent whatever the policy is:
with this patch, process scheduled by SCHED_FIFO, SCHED_RR and
SCHED_OTHER can all decrease their priority.
From: Ingo Molnar <mingo@elte.hu>
cleaned up and merged to -mm.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-25 21:57:32 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-08-03 16:33:03 +00:00
|
|
|
if (user) {
|
2017-12-04 10:23:20 +00:00
|
|
|
if (attr->sched_flags & SCHED_FLAG_SUGOV)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2010-10-14 19:21:18 +00:00
|
|
|
retval = security_task_setscheduler(p);
|
2008-08-03 16:33:03 +00:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
/* Update task specific "requested" clamps */
|
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP) {
|
|
|
|
retval = uclamp_validate(p, attr);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2019-07-19 14:00:00 +00:00
|
|
|
if (pi)
|
|
|
|
cpuset_read_lock();
|
|
|
|
|
2006-06-27 09:54:51 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Make sure no PI-waiters arrive (or leave) while we are
|
2006-06-27 09:54:51 +00:00
|
|
|
* changing the priority of the task:
|
2011-04-05 15:23:51 +00:00
|
|
|
*
|
2011-03-31 01:57:33 +00:00
|
|
|
* To be able to change p->policy safely, the appropriate
|
2005-04-16 22:20:36 +00:00
|
|
|
* runqueue lock must be held.
|
|
|
|
*/
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2016-10-03 14:28:37 +00:00
|
|
|
update_rq_clock(rq);
|
2010-06-08 09:40:42 +00:00
|
|
|
|
2010-09-22 11:53:15 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Changing the policy of the stop threads its a very bad idea:
|
2010-09-22 11:53:15 +00:00
|
|
|
*/
|
|
|
|
if (p == rq->stop) {
|
2019-07-19 13:59:54 +00:00
|
|
|
retval = -EINVAL;
|
|
|
|
goto unlock;
|
2010-09-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
|
sched: Leave sched_setscheduler() earlier if possible, do not disturb SCHED_FIFO tasks
sched_setscheduler() (in sched.c) is called in order of changing the
scheduling policy and/or the real-time priority of a task. Thus,
if we find out that neither of those are actually being modified, it
is possible to return earlier and save the overhead of a full
deactivate+activate cycle of the task in question.
Beside that, if we have more than one SCHED_FIFO task with the same
priority on the same rq (which means they share the same priority queue)
having one of them changing its position in the priority queue because of
a sched_setscheduler (as it happens by means of the deactivate+activate)
that does not actually change the priority violates POSIX which states,
for SCHED_FIFO:
"If a thread whose policy or priority has been modified by
pthread_setschedprio() is a running thread or is runnable, the effect on
its position in the thread list depends on the direction of the
modification, as follows: a. <...> b. If the priority is unchanged, the
thread does not change position in the thread list. c. <...>"
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_08.html
(ed: And the POSIX specification here does, briefly and somewhat unexpectedly,
match what common sense tells us as well. )
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1300971618.3960.82.camel@Palantir>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-03-24 13:00:18 +00:00
|
|
|
/*
|
2014-02-07 19:58:40 +00:00
|
|
|
* If not changing anything there's no need to proceed further,
|
|
|
|
* but store a possible modification of reset_on_fork.
|
sched: Leave sched_setscheduler() earlier if possible, do not disturb SCHED_FIFO tasks
sched_setscheduler() (in sched.c) is called in order of changing the
scheduling policy and/or the real-time priority of a task. Thus,
if we find out that neither of those are actually being modified, it
is possible to return earlier and save the overhead of a full
deactivate+activate cycle of the task in question.
Beside that, if we have more than one SCHED_FIFO task with the same
priority on the same rq (which means they share the same priority queue)
having one of them changing its position in the priority queue because of
a sched_setscheduler (as it happens by means of the deactivate+activate)
that does not actually change the priority violates POSIX which states,
for SCHED_FIFO:
"If a thread whose policy or priority has been modified by
pthread_setschedprio() is a running thread or is runnable, the effect on
its position in the thread list depends on the direction of the
modification, as follows: a. <...> b. If the priority is unchanged, the
thread does not change position in the thread list. c. <...>"
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_08.html
(ed: And the POSIX specification here does, briefly and somewhat unexpectedly,
match what common sense tells us as well. )
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1300971618.3960.82.camel@Palantir>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-03-24 13:00:18 +00:00
|
|
|
*/
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
if (unlikely(policy == p->policy)) {
|
2014-01-28 03:00:45 +00:00
|
|
|
if (fair_policy(policy) && attr->sched_nice != task_nice(p))
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
goto change;
|
|
|
|
if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
|
|
|
|
goto change;
|
2014-11-26 00:44:04 +00:00
|
|
|
if (dl_policy(policy) && dl_param_changed(p, attr))
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
goto change;
|
2019-06-21 08:42:07 +00:00
|
|
|
if (attr->sched_flags & SCHED_FLAG_UTIL_CLAMP)
|
|
|
|
goto change;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2014-02-07 19:58:40 +00:00
|
|
|
p->sched_reset_on_fork = reset_on_fork;
|
2019-07-19 13:59:54 +00:00
|
|
|
retval = 0;
|
|
|
|
goto unlock;
|
sched: Leave sched_setscheduler() earlier if possible, do not disturb SCHED_FIFO tasks
sched_setscheduler() (in sched.c) is called in order of changing the
scheduling policy and/or the real-time priority of a task. Thus,
if we find out that neither of those are actually being modified, it
is possible to return earlier and save the overhead of a full
deactivate+activate cycle of the task in question.
Beside that, if we have more than one SCHED_FIFO task with the same
priority on the same rq (which means they share the same priority queue)
having one of them changing its position in the priority queue because of
a sched_setscheduler (as it happens by means of the deactivate+activate)
that does not actually change the priority violates POSIX which states,
for SCHED_FIFO:
"If a thread whose policy or priority has been modified by
pthread_setschedprio() is a running thread or is runnable, the effect on
its position in the thread list depends on the direction of the
modification, as follows: a. <...> b. If the priority is unchanged, the
thread does not change position in the thread list. c. <...>"
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_08.html
(ed: And the POSIX specification here does, briefly and somewhat unexpectedly,
match what common sense tells us as well. )
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1300971618.3960.82.camel@Palantir>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-03-24 13:00:18 +00:00
|
|
|
}
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
change:
|
sched: Leave sched_setscheduler() earlier if possible, do not disturb SCHED_FIFO tasks
sched_setscheduler() (in sched.c) is called in order of changing the
scheduling policy and/or the real-time priority of a task. Thus,
if we find out that neither of those are actually being modified, it
is possible to return earlier and save the overhead of a full
deactivate+activate cycle of the task in question.
Beside that, if we have more than one SCHED_FIFO task with the same
priority on the same rq (which means they share the same priority queue)
having one of them changing its position in the priority queue because of
a sched_setscheduler (as it happens by means of the deactivate+activate)
that does not actually change the priority violates POSIX which states,
for SCHED_FIFO:
"If a thread whose policy or priority has been modified by
pthread_setschedprio() is a running thread or is runnable, the effect on
its position in the thread list depends on the direction of the
modification, as follows: a. <...> b. If the priority is unchanged, the
thread does not change position in the thread list. c. <...>"
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_08.html
(ed: And the POSIX specification here does, briefly and somewhat unexpectedly,
match what common sense tells us as well. )
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <1300971618.3960.82.camel@Palantir>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-03-24 13:00:18 +00:00
|
|
|
|
2010-06-08 09:40:42 +00:00
|
|
|
if (user) {
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2010-06-08 09:40:42 +00:00
|
|
|
/*
|
|
|
|
* Do not allow realtime tasks into groups that have no runtime
|
|
|
|
* assigned.
|
|
|
|
*/
|
|
|
|
if (rt_bandwidth_enabled() && rt_policy(policy) &&
|
2011-01-13 03:54:50 +00:00
|
|
|
task_group(p)->rt_bandwidth.rt_runtime == 0 &&
|
|
|
|
!task_group_is_autogroup(task_group(p))) {
|
2019-07-19 13:59:54 +00:00
|
|
|
retval = -EPERM;
|
|
|
|
goto unlock;
|
2010-06-08 09:40:42 +00:00
|
|
|
}
|
|
|
|
#endif
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2017-12-04 10:23:20 +00:00
|
|
|
if (dl_bandwidth_enabled() && dl_policy(policy) &&
|
|
|
|
!(attr->sched_flags & SCHED_FLAG_SUGOV)) {
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
cpumask_t *span = rq->rd->span;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't allow tasks with an affinity mask smaller than
|
|
|
|
* the entire root_domain to become SCHED_DEADLINE. We
|
|
|
|
* will also fail if there's no bandwidth available.
|
|
|
|
*/
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_subset(span, p->cpus_ptr) ||
|
2013-12-17 09:03:34 +00:00
|
|
|
rq->rd->dl_bw.bw == 0) {
|
2019-07-19 13:59:54 +00:00
|
|
|
retval = -EPERM;
|
|
|
|
goto unlock;
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2010-06-08 09:40:42 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Re-check policy now with rq lock held: */
|
2005-04-16 22:20:36 +00:00
|
|
|
if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) {
|
|
|
|
policy = oldpolicy = -1;
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2019-07-19 14:00:00 +00:00
|
|
|
if (pi)
|
|
|
|
cpuset_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
goto recheck;
|
|
|
|
}
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If setscheduling to SCHED_DEADLINE (or changing the parameters
|
|
|
|
* of a SCHED_DEADLINE task) we need to check if enough bandwidth
|
|
|
|
* is available.
|
|
|
|
*/
|
2017-06-21 18:22:01 +00:00
|
|
|
if ((dl_policy(policy) || dl_task(p)) && sched_dl_overflow(p, policy, attr)) {
|
2019-07-19 13:59:54 +00:00
|
|
|
retval = -EBUSY;
|
|
|
|
goto unlock;
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
}
|
|
|
|
|
2014-02-07 19:58:42 +00:00
|
|
|
p->sched_reset_on_fork = reset_on_fork;
|
|
|
|
oldprio = p->prio;
|
|
|
|
|
2015-06-11 12:46:38 +00:00
|
|
|
if (pi) {
|
|
|
|
/*
|
|
|
|
* Take priority boosted tasks into account. If the new
|
|
|
|
* effective priority is unchanged, we just store the new
|
|
|
|
* normal parameters and do not touch the scheduler class and
|
|
|
|
* the runqueue. This will be done when the task deboost
|
|
|
|
* itself.
|
|
|
|
*/
|
2017-03-23 14:56:11 +00:00
|
|
|
new_effective_prio = rt_effective_prio(p, newprio);
|
2016-01-18 14:27:07 +00:00
|
|
|
if (new_effective_prio == oldprio)
|
|
|
|
queue_flags &= ~DEQUEUE_MOVE;
|
2014-02-07 19:58:42 +00:00
|
|
|
}
|
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
queued = task_on_rq_queued(p);
|
2007-12-18 14:21:13 +00:00
|
|
|
running = task_current(rq, p);
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2016-01-18 14:27:07 +00:00
|
|
|
dequeue_task(rq, p, queue_flags);
|
2008-03-10 18:01:20 +00:00
|
|
|
if (running)
|
2014-09-12 13:41:40 +00:00
|
|
|
put_prev_task(rq, p);
|
2007-10-15 15:00:08 +00:00
|
|
|
|
2010-02-17 08:05:48 +00:00
|
|
|
prev_class = p->sched_class;
|
2019-06-21 08:42:07 +00:00
|
|
|
|
2015-06-11 12:46:38 +00:00
|
|
|
__setscheduler(rq, p, attr, pi);
|
2019-06-21 08:42:07 +00:00
|
|
|
__setscheduler_uclamp(p, attr);
|
2007-10-15 15:00:08 +00:00
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued) {
|
2014-02-07 19:58:41 +00:00
|
|
|
/*
|
|
|
|
* We enqueue to tail when the priority of a task is
|
|
|
|
* increased (user space view).
|
|
|
|
*/
|
2016-01-18 14:27:07 +00:00
|
|
|
if (oldprio < p->prio)
|
|
|
|
queue_flags |= ENQUEUE_HEAD;
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
|
2016-01-18 14:27:07 +00:00
|
|
|
enqueue_task(rq, p, queue_flags);
|
2014-02-07 19:58:41 +00:00
|
|
|
}
|
2016-09-12 07:47:52 +00:00
|
|
|
if (running)
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, p);
|
2008-01-25 20:08:22 +00:00
|
|
|
|
2011-01-17 16:03:27 +00:00
|
|
|
check_class_changed(rq, p, prev_class, oldprio);
|
2017-02-01 10:46:42 +00:00
|
|
|
|
|
|
|
/* Avoid rq from going away on us: */
|
|
|
|
preempt_disable();
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2006-06-27 09:54:51 +00:00
|
|
|
|
2019-07-19 14:00:00 +00:00
|
|
|
if (pi) {
|
|
|
|
cpuset_read_unlock();
|
2015-06-11 12:46:38 +00:00
|
|
|
rt_mutex_adjust_pi(p);
|
2019-07-19 14:00:00 +00:00
|
|
|
}
|
2006-06-27 09:55:02 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Run balance callbacks after we've adjusted the PI chain: */
|
2015-06-11 12:46:39 +00:00
|
|
|
balance_callback(rq);
|
|
|
|
preempt_enable();
|
2006-06-27 09:55:02 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
2019-07-19 13:59:54 +00:00
|
|
|
|
|
|
|
unlock:
|
|
|
|
task_rq_unlock(rq, p, &rf);
|
2019-07-19 14:00:00 +00:00
|
|
|
if (pi)
|
|
|
|
cpuset_read_unlock();
|
2019-07-19 13:59:54 +00:00
|
|
|
return retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2008-06-23 03:55:38 +00:00
|
|
|
|
2014-01-15 16:05:04 +00:00
|
|
|
static int _sched_setscheduler(struct task_struct *p, int policy,
|
|
|
|
const struct sched_param *param, bool check)
|
|
|
|
{
|
|
|
|
struct sched_attr attr = {
|
|
|
|
.sched_policy = policy,
|
|
|
|
.sched_priority = param->sched_priority,
|
|
|
|
.sched_nice = PRIO_TO_NICE(p->static_prio),
|
|
|
|
};
|
|
|
|
|
2014-07-23 15:28:26 +00:00
|
|
|
/* Fixup the legacy SCHED_RESET_ON_FORK hack. */
|
|
|
|
if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) {
|
2014-01-15 16:05:04 +00:00
|
|
|
attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
|
|
|
|
policy &= ~SCHED_RESET_ON_FORK;
|
|
|
|
attr.sched_policy = policy;
|
|
|
|
}
|
|
|
|
|
2015-06-11 12:46:38 +00:00
|
|
|
return __sched_setscheduler(p, &attr, check, true);
|
2014-01-15 16:05:04 +00:00
|
|
|
}
|
2008-06-23 03:55:38 +00:00
|
|
|
/**
|
|
|
|
* sched_setscheduler - change the scheduling policy and/or RT priority of a thread.
|
|
|
|
* @p: the task in question.
|
|
|
|
* @policy: new policy.
|
|
|
|
* @param: structure containing the new RT priority.
|
|
|
|
*
|
2013-07-12 18:45:47 +00:00
|
|
|
* Return: 0 on success. An error code otherwise.
|
|
|
|
*
|
2008-06-23 03:55:38 +00:00
|
|
|
* NOTE that the task may be already dead.
|
|
|
|
*/
|
|
|
|
int sched_setscheduler(struct task_struct *p, int policy,
|
2010-10-20 23:01:12 +00:00
|
|
|
const struct sched_param *param)
|
2008-06-23 03:55:38 +00:00
|
|
|
{
|
2014-01-15 16:05:04 +00:00
|
|
|
return _sched_setscheduler(p, policy, param, true);
|
2008-06-23 03:55:38 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
EXPORT_SYMBOL_GPL(sched_setscheduler);
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
int sched_setattr(struct task_struct *p, const struct sched_attr *attr)
|
|
|
|
{
|
2015-06-11 12:46:38 +00:00
|
|
|
return __sched_setscheduler(p, attr, true, true);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(sched_setattr);
|
|
|
|
|
2017-12-04 10:23:20 +00:00
|
|
|
int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
|
|
|
|
{
|
|
|
|
return __sched_setscheduler(p, attr, false, true);
|
|
|
|
}
|
|
|
|
|
2008-06-23 03:55:38 +00:00
|
|
|
/**
|
|
|
|
* sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
|
|
|
|
* @p: the task in question.
|
|
|
|
* @policy: new policy.
|
|
|
|
* @param: structure containing the new RT priority.
|
|
|
|
*
|
|
|
|
* Just like sched_setscheduler, only don't bother checking if the
|
|
|
|
* current context has permission. For example, this is needed in
|
|
|
|
* stop_machine(): we create temporary high priority worker threads,
|
|
|
|
* but our caller might not have that capability.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success. An error code otherwise.
|
2008-06-23 03:55:38 +00:00
|
|
|
*/
|
|
|
|
int sched_setscheduler_nocheck(struct task_struct *p, int policy,
|
2010-10-20 23:01:12 +00:00
|
|
|
const struct sched_param *param)
|
2008-06-23 03:55:38 +00:00
|
|
|
{
|
2014-01-15 16:05:04 +00:00
|
|
|
return _sched_setscheduler(p, policy, param, false);
|
2008-06-23 03:55:38 +00:00
|
|
|
}
|
2015-09-02 08:28:44 +00:00
|
|
|
EXPORT_SYMBOL_GPL(sched_setscheduler_nocheck);
|
2008-06-23 03:55:38 +00:00
|
|
|
|
2005-09-10 07:26:11 +00:00
|
|
|
static int
|
|
|
|
do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
struct sched_param lparam;
|
|
|
|
struct task_struct *p;
|
2006-07-03 07:25:41 +00:00
|
|
|
int retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (!param || pid < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
|
|
|
|
return -EFAULT;
|
2006-09-29 09:00:48 +00:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
retval = -ESRCH;
|
2005-04-16 22:20:36 +00:00
|
|
|
p = find_process_by_pid(pid);
|
2019-07-19 14:00:00 +00:00
|
|
|
if (likely(p))
|
|
|
|
get_task_struct(p);
|
2006-09-29 09:00:48 +00:00
|
|
|
rcu_read_unlock();
|
2006-07-03 07:25:41 +00:00
|
|
|
|
2019-07-19 14:00:00 +00:00
|
|
|
if (likely(p)) {
|
|
|
|
retval = sched_setscheduler(p, policy, &lparam);
|
|
|
|
put_task_struct(p);
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
/*
|
|
|
|
* Mimics kernel/events/core.c perf_copy_attr().
|
|
|
|
*/
|
2017-02-01 10:46:42 +00:00
|
|
|
static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *attr)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
{
|
|
|
|
u32 size;
|
|
|
|
int ret;
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Zero the full structure, so that a short copy will be nice: */
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
memset(attr, 0, sizeof(*attr));
|
|
|
|
|
|
|
|
ret = get_user(size, &uattr->size);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* ABI compatibility quirk: */
|
|
|
|
if (!size)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
size = SCHED_ATTR_SIZE_VER0;
|
2019-10-01 01:10:54 +00:00
|
|
|
if (size < SCHED_ATTR_SIZE_VER0 || size > PAGE_SIZE)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
goto err_size;
|
|
|
|
|
2019-10-01 01:10:54 +00:00
|
|
|
ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size);
|
|
|
|
if (ret) {
|
|
|
|
if (ret == -E2BIG)
|
|
|
|
goto err_size;
|
|
|
|
return ret;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
}
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
if ((attr->sched_flags & SCHED_FLAG_UTIL_CLAMP) &&
|
|
|
|
size < SCHED_ATTR_SIZE_VER1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* XXX: Do we want to be lenient like existing syscalls; or do we want
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
* to be strict and return an error on out-of-bounds values?
|
|
|
|
*/
|
2014-02-11 07:34:50 +00:00
|
|
|
attr->sched_nice = clamp(attr->sched_nice, MIN_NICE, MAX_NICE);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2014-05-09 14:54:28 +00:00
|
|
|
return 0;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
|
|
|
err_size:
|
|
|
|
put_user(sizeof(*attr), &uattr->size);
|
2014-05-09 14:54:28 +00:00
|
|
|
return -E2BIG;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* sys_sched_setscheduler - set/change the scheduler policy and RT priority
|
|
|
|
* @pid: the pid in question.
|
|
|
|
* @policy: new policy.
|
|
|
|
* @param: structure containing the new RT priority.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success. An error code otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2017-02-01 10:46:42 +00:00
|
|
|
SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, struct sched_param __user *, param)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-01-19 01:43:03 +00:00
|
|
|
if (policy < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return do_sched_setscheduler(pid, policy, param);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sys_sched_setparam - set/change the RT priority of a thread
|
|
|
|
* @pid: the pid in question.
|
|
|
|
* @param: structure containing the new RT priority.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success. An error code otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2014-07-23 15:28:26 +00:00
|
|
|
return do_sched_setscheduler(pid, SETPARAM_POLICY, param);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
/**
|
|
|
|
* sys_sched_setattr - same as above, but with extended sched_attr
|
|
|
|
* @pid: the pid in question.
|
2014-01-14 15:10:39 +00:00
|
|
|
* @uattr: structure containing the extended parameters.
|
2014-04-17 16:59:15 +00:00
|
|
|
* @flags: for future extension.
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
*/
|
2014-02-14 16:19:29 +00:00
|
|
|
SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
|
|
|
|
unsigned int, flags)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
{
|
|
|
|
struct sched_attr attr;
|
|
|
|
struct task_struct *p;
|
|
|
|
int retval;
|
|
|
|
|
2014-02-14 16:19:29 +00:00
|
|
|
if (!uattr || pid < 0 || flags)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-05-09 14:54:15 +00:00
|
|
|
retval = sched_copy_attr(uattr, &attr);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2014-06-02 20:38:34 +00:00
|
|
|
if ((int)attr.sched_policy < 0)
|
2014-05-09 08:49:03 +00:00
|
|
|
return -EINVAL;
|
2019-06-21 08:42:06 +00:00
|
|
|
if (attr.sched_flags & SCHED_FLAG_KEEP_POLICY)
|
|
|
|
attr.sched_policy = SETPARAM_POLICY;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
retval = -ESRCH;
|
|
|
|
p = find_process_by_pid(pid);
|
2019-06-21 08:42:07 +00:00
|
|
|
if (likely(p))
|
|
|
|
get_task_struct(p);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
if (likely(p)) {
|
|
|
|
retval = sched_setattr(p, &attr);
|
|
|
|
put_task_struct(p);
|
|
|
|
}
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* sys_sched_getscheduler - get the policy (scheduling class) of a thread
|
|
|
|
* @pid: the pid in question.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: On success, the policy of the thread. Otherwise, a negative error
|
|
|
|
* code.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *p;
|
2007-10-15 15:00:14 +00:00
|
|
|
int retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (pid < 0)
|
2007-10-15 15:00:14 +00:00
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
retval = -ESRCH;
|
2009-12-09 10:14:58 +00:00
|
|
|
rcu_read_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
if (p) {
|
|
|
|
retval = security_task_getscheduler(p);
|
|
|
|
if (!retval)
|
2009-06-15 15:17:47 +00:00
|
|
|
retval = p->policy
|
|
|
|
| (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2009-12-09 10:14:58 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-06-15 15:17:47 +00:00
|
|
|
* sys_sched_getparam - get the RT priority of a thread
|
2005-04-16 22:20:36 +00:00
|
|
|
* @pid: the pid in question.
|
|
|
|
* @param: structure containing the RT priority.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: On success, 0 and the RT priority is in @param. Otherwise, an error
|
|
|
|
* code.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2014-05-12 20:50:34 +00:00
|
|
|
struct sched_param lp = { .sched_priority = 0 };
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *p;
|
2007-10-15 15:00:14 +00:00
|
|
|
int retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (!param || pid < 0)
|
2007-10-15 15:00:14 +00:00
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-12-09 10:14:58 +00:00
|
|
|
rcu_read_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
retval = -ESRCH;
|
|
|
|
if (!p)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
retval = security_task_getscheduler(p);
|
|
|
|
if (retval)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2014-05-12 20:50:34 +00:00
|
|
|
if (task_has_rt_policy(p))
|
|
|
|
lp.sched_priority = p->rt_priority;
|
2009-12-09 10:14:58 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This one might sleep, we cannot do it with a spinlock held ...
|
|
|
|
*/
|
|
|
|
retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0;
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
out_unlock:
|
2009-12-09 10:14:58 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2019-09-04 07:55:32 +00:00
|
|
|
/*
|
|
|
|
* Copy the kernel size attribute structure (which might be larger
|
|
|
|
* than what user-space knows about) to user-space.
|
|
|
|
*
|
|
|
|
* Note that all cases are valid: user-space buffer can be larger or
|
|
|
|
* smaller than the kernel-space buffer. The usual case is that both
|
|
|
|
* have the same size.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sched_attr_copy_to_user(struct sched_attr __user *uattr,
|
|
|
|
struct sched_attr *kattr,
|
|
|
|
unsigned int usize)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
{
|
2019-09-04 07:55:32 +00:00
|
|
|
unsigned int ksize = sizeof(*kattr);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
Remove 'type' argument from access_ok() function
Nobody has actually used the type (VERIFY_READ vs VERIFY_WRITE) argument
of the user address range verification function since we got rid of the
old racy i386-only code to walk page tables by hand.
It existed because the original 80386 would not honor the write protect
bit when in kernel mode, so you had to do COW by hand before doing any
user access. But we haven't supported that in a long time, and these
days the 'type' argument is a purely historical artifact.
A discussion about extending 'user_access_begin()' to do the range
checking resulted this patch, because there is no way we're going to
move the old VERIFY_xyz interface to that model. And it's best done at
the end of the merge window when I've done most of my merges, so let's
just get this done once and for all.
This patch was mostly done with a sed-script, with manual fix-ups for
the cases that weren't of the trivial 'access_ok(VERIFY_xyz' form.
There were a couple of notable cases:
- csky still had the old "verify_area()" name as an alias.
- the iter_iov code had magical hardcoded knowledge of the actual
values of VERIFY_{READ,WRITE} (not that they mattered, since nothing
really used it)
- microblaze used the type argument for a debug printout
but other than those oddities this should be a total no-op patch.
I tried to fix up all architectures, did fairly extensive grepping for
access_ok() uses, and the changes are trivial, but I may have missed
something. Any missed conversion should be trivially fixable, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2019-01-04 02:57:57 +00:00
|
|
|
if (!access_ok(uattr, usize))
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/*
|
2019-09-04 07:55:32 +00:00
|
|
|
* sched_getattr() ABI forwards and backwards compatibility:
|
|
|
|
*
|
|
|
|
* If usize == ksize then we just copy everything to user-space and all is good.
|
|
|
|
*
|
|
|
|
* If usize < ksize then we only copy as much as user-space has space for,
|
|
|
|
* this keeps ABI compatibility as well. We skip the rest.
|
|
|
|
*
|
|
|
|
* If usize > ksize then user-space is using a newer version of the ABI,
|
|
|
|
* which part the kernel doesn't know about. Just ignore it - tooling can
|
|
|
|
* detect the kernel's knowledge of attributes from the attr->size value
|
|
|
|
* which is set to ksize in this case.
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
*/
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr->size = min(usize, ksize);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2019-09-04 07:55:32 +00:00
|
|
|
if (copy_to_user(uattr, kattr, kattr->size))
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
2014-05-09 14:54:33 +00:00
|
|
|
return 0;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
* sys_sched_getattr - similar to sched_getparam, but with sched_attr
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
* @pid: the pid in question.
|
2014-01-14 15:10:39 +00:00
|
|
|
* @uattr: structure containing the extended parameters.
|
2019-10-01 01:10:54 +00:00
|
|
|
* @usize: sizeof(attr) for fwd/bwd comp.
|
2014-04-17 16:59:15 +00:00
|
|
|
* @flags: for future extension.
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
*/
|
2014-02-14 16:19:29 +00:00
|
|
|
SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
|
2019-09-04 07:55:32 +00:00
|
|
|
unsigned int, usize, unsigned int, flags)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
{
|
2019-09-04 07:55:32 +00:00
|
|
|
struct sched_attr kattr = { };
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
struct task_struct *p;
|
|
|
|
int retval;
|
|
|
|
|
2019-09-04 07:55:32 +00:00
|
|
|
if (!uattr || pid < 0 || usize > PAGE_SIZE ||
|
|
|
|
usize < SCHED_ATTR_SIZE_VER0 || flags)
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
retval = -ESRCH;
|
|
|
|
if (!p)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
retval = security_task_getscheduler(p);
|
|
|
|
if (retval)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr.sched_policy = p->policy;
|
2014-01-15 16:05:04 +00:00
|
|
|
if (p->sched_reset_on_fork)
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (task_has_dl_policy(p))
|
2019-09-04 07:55:32 +00:00
|
|
|
__getparam_dl(p, &kattr);
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
else if (task_has_rt_policy(p))
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr.sched_priority = p->rt_priority;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
else
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr.sched_nice = task_nice(p);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
2019-06-21 08:42:07 +00:00
|
|
|
#ifdef CONFIG_UCLAMP_TASK
|
2019-09-04 07:55:32 +00:00
|
|
|
kattr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value;
|
|
|
|
kattr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value;
|
2019-06-21 08:42:07 +00:00
|
|
|
#endif
|
|
|
|
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
2019-09-04 07:55:32 +00:00
|
|
|
return sched_attr_copy_to_user(uattr, &kattr, usize);
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
|
|
|
|
out_unlock:
|
|
|
|
rcu_read_unlock();
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:05:14 +00:00
|
|
|
long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-11-24 16:05:11 +00:00
|
|
|
cpumask_var_t cpus_allowed, new_mask;
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *p;
|
|
|
|
int retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2009-12-09 10:15:01 +00:00
|
|
|
rcu_read_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
if (!p) {
|
2009-12-09 10:15:01 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
|
2009-12-09 10:15:01 +00:00
|
|
|
/* Prevent p going away */
|
2005-04-16 22:20:36 +00:00
|
|
|
get_task_struct(p);
|
2009-12-09 10:15:01 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-03-19 20:45:20 +00:00
|
|
|
if (p->flags & PF_NO_SETAFFINITY) {
|
|
|
|
retval = -EINVAL;
|
|
|
|
goto out_put_task;
|
|
|
|
}
|
2008-11-24 16:05:11 +00:00
|
|
|
if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
|
|
|
|
retval = -ENOMEM;
|
|
|
|
goto out_put_task;
|
|
|
|
}
|
|
|
|
if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
|
|
|
|
retval = -ENOMEM;
|
|
|
|
goto out_free_cpus_allowed;
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
retval = -EPERM;
|
2012-07-26 12:05:21 +00:00
|
|
|
if (!check_same_owner(p)) {
|
|
|
|
rcu_read_lock();
|
|
|
|
if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) {
|
|
|
|
rcu_read_unlock();
|
2014-09-22 18:36:30 +00:00
|
|
|
goto out_free_new_mask;
|
2012-07-26 12:05:21 +00:00
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-10-14 19:21:18 +00:00
|
|
|
retval = security_task_setscheduler(p);
|
2006-06-23 09:03:59 +00:00
|
|
|
if (retval)
|
2014-09-22 18:36:30 +00:00
|
|
|
goto out_free_new_mask;
|
2006-06-23 09:03:59 +00:00
|
|
|
|
2013-12-17 09:03:34 +00:00
|
|
|
|
|
|
|
cpuset_cpus_allowed(p, cpus_allowed);
|
|
|
|
cpumask_and(new_mask, in_mask, cpus_allowed);
|
|
|
|
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
/*
|
|
|
|
* Since bandwidth control happens on root_domain basis,
|
|
|
|
* if admission test is enabled, we only admit -deadline
|
|
|
|
* tasks allowed to run on all the CPUs in the task's
|
|
|
|
* root_domain.
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_SMP
|
2014-09-22 18:36:36 +00:00
|
|
|
if (task_has_dl_policy(p) && dl_bandwidth_enabled()) {
|
|
|
|
rcu_read_lock();
|
|
|
|
if (!cpumask_subset(task_rq(p)->rd->span, new_mask)) {
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
retval = -EBUSY;
|
2014-09-22 18:36:36 +00:00
|
|
|
rcu_read_unlock();
|
2014-09-22 18:36:30 +00:00
|
|
|
goto out_free_new_mask;
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
}
|
2014-09-22 18:36:36 +00:00
|
|
|
rcu_read_unlock();
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
}
|
|
|
|
#endif
|
2010-10-17 19:46:10 +00:00
|
|
|
again:
|
2015-05-15 15:43:34 +00:00
|
|
|
retval = __set_cpus_allowed_ptr(p, new_mask, true);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-10-19 06:40:22 +00:00
|
|
|
if (!retval) {
|
2008-11-24 16:05:11 +00:00
|
|
|
cpuset_cpus_allowed(p, cpus_allowed);
|
|
|
|
if (!cpumask_subset(new_mask, cpus_allowed)) {
|
2007-10-19 06:40:22 +00:00
|
|
|
/*
|
|
|
|
* We must have raced with a concurrent cpuset
|
|
|
|
* update. Just reset the cpus_allowed to the
|
|
|
|
* cpuset's cpus_allowed
|
|
|
|
*/
|
2008-11-24 16:05:11 +00:00
|
|
|
cpumask_copy(new_mask, cpus_allowed);
|
2007-10-19 06:40:22 +00:00
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
}
|
2014-09-22 18:36:30 +00:00
|
|
|
out_free_new_mask:
|
2008-11-24 16:05:11 +00:00
|
|
|
free_cpumask_var(new_mask);
|
|
|
|
out_free_cpus_allowed:
|
|
|
|
free_cpumask_var(cpus_allowed);
|
|
|
|
out_put_task:
|
2005-04-16 22:20:36 +00:00
|
|
|
put_task_struct(p);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len,
|
2008-11-24 16:05:14 +00:00
|
|
|
struct cpumask *new_mask)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-11-24 16:05:14 +00:00
|
|
|
if (len < cpumask_size())
|
|
|
|
cpumask_clear(new_mask);
|
|
|
|
else if (len > cpumask_size())
|
|
|
|
len = cpumask_size();
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-01 10:46:42 +00:00
|
|
|
* sys_sched_setaffinity - set the CPU affinity of a process
|
2005-04-16 22:20:36 +00:00
|
|
|
* @pid: pid of the process
|
|
|
|
* @len: length in bytes of the bitmask pointed to by user_mask_ptr
|
2017-02-01 10:46:42 +00:00
|
|
|
* @user_mask_ptr: user-space pointer to the new CPU mask
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 0 on success. An error code otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
|
|
|
|
unsigned long __user *, user_mask_ptr)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2008-11-24 16:05:11 +00:00
|
|
|
cpumask_var_t new_mask;
|
2005-04-16 22:20:36 +00:00
|
|
|
int retval;
|
|
|
|
|
2008-11-24 16:05:11 +00:00
|
|
|
if (!alloc_cpumask_var(&new_mask, GFP_KERNEL))
|
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-11-24 16:05:11 +00:00
|
|
|
retval = get_user_cpu_mask(user_mask_ptr, len, new_mask);
|
|
|
|
if (retval == 0)
|
|
|
|
retval = sched_setaffinity(pid, new_mask);
|
|
|
|
free_cpumask_var(new_mask);
|
|
|
|
return retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2008-11-24 16:05:14 +00:00
|
|
|
long sched_getaffinity(pid_t pid, struct cpumask *mask)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *p;
|
2009-12-08 20:24:16 +00:00
|
|
|
unsigned long flags;
|
2005-04-16 22:20:36 +00:00
|
|
|
int retval;
|
|
|
|
|
2009-12-09 10:15:01 +00:00
|
|
|
rcu_read_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
retval = -ESRCH;
|
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
if (!p)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2006-06-23 09:03:59 +00:00
|
|
|
retval = security_task_getscheduler(p);
|
|
|
|
if (retval)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2011-04-05 15:23:45 +00:00
|
|
|
raw_spin_lock_irqsave(&p->pi_lock, flags);
|
2019-04-23 14:26:36 +00:00
|
|
|
cpumask_and(mask, &p->cpus_mask, cpu_active_mask);
|
2011-04-05 15:23:45 +00:00
|
|
|
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
out_unlock:
|
2009-12-09 10:15:01 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-08-09 09:16:46 +00:00
|
|
|
return retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-02-01 10:46:42 +00:00
|
|
|
* sys_sched_getaffinity - get the CPU affinity of a process
|
2005-04-16 22:20:36 +00:00
|
|
|
* @pid: pid of the process
|
|
|
|
* @len: length in bytes of the bitmask pointed to by user_mask_ptr
|
2017-02-01 10:46:42 +00:00
|
|
|
* @user_mask_ptr: user-space pointer to hold the current CPU mask
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
2016-06-26 21:13:23 +00:00
|
|
|
* Return: size of CPU mask copied to user_mask_ptr on success. An
|
|
|
|
* error code otherwise.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
|
|
|
|
unsigned long __user *, user_mask_ptr)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int ret;
|
2008-11-24 16:05:11 +00:00
|
|
|
cpumask_var_t mask;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2010-04-06 07:02:19 +00:00
|
|
|
if ((len * BITS_PER_BYTE) < nr_cpu_ids)
|
sched: sched_getaffinity(): Allow less than NR_CPUS length
[ Note, this commit changes the syscall ABI for > 1024 CPUs systems. ]
Recently, some distro decided to use NR_CPUS=4096 for mysterious reasons.
Unfortunately, glibc sched interface has the following definition:
# define __CPU_SETSIZE 1024
# define __NCPUBITS (8 * sizeof (__cpu_mask))
typedef unsigned long int __cpu_mask;
typedef struct
{
__cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;
It mean, if NR_CPUS is bigger than 1024, cpu_set_t makes an
ABI issue ...
More recently, Sharyathi Nagesh reported following test program makes
misterious syscall failure:
-----------------------------------------------------------------------
#define _GNU_SOURCE
#include<stdio.h>
#include<errno.h>
#include<sched.h>
int main()
{
cpu_set_t set;
if (sched_getaffinity(0, sizeof(cpu_set_t), &set) < 0)
printf("\n Call is failing with:%d", errno);
}
-----------------------------------------------------------------------
Because the kernel assumes len argument of sched_getaffinity() is bigger
than NR_CPUS. But now it is not correct.
Now we are faced with the following annoying dilemma, due to
the limitations of the glibc interface built in years ago:
(1) if we change glibc's __CPU_SETSIZE definition, we lost
binary compatibility of _all_ application.
(2) if we don't change it, we also lost binary compatibility of
Sharyathi's use case.
Then, I would propse to change the rule of the len argument of
sched_getaffinity().
Old:
len should be bigger than NR_CPUS
New:
len should be bigger than maximum possible cpu id
This creates the following behavior:
(A) In the real 4096 cpus machine, the above test program still
return -EINVAL.
(B) NR_CPUS=4096 but the machine have less than 1024 cpus (almost
all machines in the world), the above can run successfully.
Fortunatelly, BIG SGI machine is mainly used for HPC use case. It means
they can rebuild their programs.
IOW we hope they are not annoyed by this issue ...
Reported-by: Sharyathi Nagesh <sharyath@in.ibm.com>
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: Ulrich Drepper <drepper@redhat.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jack Steiner <steiner@sgi.com>
Cc: Russ Anderson <rja@sgi.com>
Cc: Mike Travis <travis@sgi.com>
LKML-Reference: <20100312161316.9520.A69D9226@jp.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-12 07:15:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
if (len & (sizeof(unsigned long)-1))
|
2005-04-16 22:20:36 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
2008-11-24 16:05:11 +00:00
|
|
|
if (!alloc_cpumask_var(&mask, GFP_KERNEL))
|
|
|
|
return -ENOMEM;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-11-24 16:05:11 +00:00
|
|
|
ret = sched_getaffinity(pid, mask);
|
|
|
|
if (ret == 0) {
|
2018-02-06 23:39:37 +00:00
|
|
|
unsigned int retlen = min(len, cpumask_size());
|
sched: sched_getaffinity(): Allow less than NR_CPUS length
[ Note, this commit changes the syscall ABI for > 1024 CPUs systems. ]
Recently, some distro decided to use NR_CPUS=4096 for mysterious reasons.
Unfortunately, glibc sched interface has the following definition:
# define __CPU_SETSIZE 1024
# define __NCPUBITS (8 * sizeof (__cpu_mask))
typedef unsigned long int __cpu_mask;
typedef struct
{
__cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;
It mean, if NR_CPUS is bigger than 1024, cpu_set_t makes an
ABI issue ...
More recently, Sharyathi Nagesh reported following test program makes
misterious syscall failure:
-----------------------------------------------------------------------
#define _GNU_SOURCE
#include<stdio.h>
#include<errno.h>
#include<sched.h>
int main()
{
cpu_set_t set;
if (sched_getaffinity(0, sizeof(cpu_set_t), &set) < 0)
printf("\n Call is failing with:%d", errno);
}
-----------------------------------------------------------------------
Because the kernel assumes len argument of sched_getaffinity() is bigger
than NR_CPUS. But now it is not correct.
Now we are faced with the following annoying dilemma, due to
the limitations of the glibc interface built in years ago:
(1) if we change glibc's __CPU_SETSIZE definition, we lost
binary compatibility of _all_ application.
(2) if we don't change it, we also lost binary compatibility of
Sharyathi's use case.
Then, I would propse to change the rule of the len argument of
sched_getaffinity().
Old:
len should be bigger than NR_CPUS
New:
len should be bigger than maximum possible cpu id
This creates the following behavior:
(A) In the real 4096 cpus machine, the above test program still
return -EINVAL.
(B) NR_CPUS=4096 but the machine have less than 1024 cpus (almost
all machines in the world), the above can run successfully.
Fortunatelly, BIG SGI machine is mainly used for HPC use case. It means
they can rebuild their programs.
IOW we hope they are not annoyed by this issue ...
Reported-by: Sharyathi Nagesh <sharyath@in.ibm.com>
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: Ulrich Drepper <drepper@redhat.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jack Steiner <steiner@sgi.com>
Cc: Russ Anderson <rja@sgi.com>
Cc: Mike Travis <travis@sgi.com>
LKML-Reference: <20100312161316.9520.A69D9226@jp.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-12 07:15:36 +00:00
|
|
|
|
|
|
|
if (copy_to_user(user_mask_ptr, mask, retlen))
|
2008-11-24 16:05:11 +00:00
|
|
|
ret = -EFAULT;
|
|
|
|
else
|
sched: sched_getaffinity(): Allow less than NR_CPUS length
[ Note, this commit changes the syscall ABI for > 1024 CPUs systems. ]
Recently, some distro decided to use NR_CPUS=4096 for mysterious reasons.
Unfortunately, glibc sched interface has the following definition:
# define __CPU_SETSIZE 1024
# define __NCPUBITS (8 * sizeof (__cpu_mask))
typedef unsigned long int __cpu_mask;
typedef struct
{
__cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;
It mean, if NR_CPUS is bigger than 1024, cpu_set_t makes an
ABI issue ...
More recently, Sharyathi Nagesh reported following test program makes
misterious syscall failure:
-----------------------------------------------------------------------
#define _GNU_SOURCE
#include<stdio.h>
#include<errno.h>
#include<sched.h>
int main()
{
cpu_set_t set;
if (sched_getaffinity(0, sizeof(cpu_set_t), &set) < 0)
printf("\n Call is failing with:%d", errno);
}
-----------------------------------------------------------------------
Because the kernel assumes len argument of sched_getaffinity() is bigger
than NR_CPUS. But now it is not correct.
Now we are faced with the following annoying dilemma, due to
the limitations of the glibc interface built in years ago:
(1) if we change glibc's __CPU_SETSIZE definition, we lost
binary compatibility of _all_ application.
(2) if we don't change it, we also lost binary compatibility of
Sharyathi's use case.
Then, I would propse to change the rule of the len argument of
sched_getaffinity().
Old:
len should be bigger than NR_CPUS
New:
len should be bigger than maximum possible cpu id
This creates the following behavior:
(A) In the real 4096 cpus machine, the above test program still
return -EINVAL.
(B) NR_CPUS=4096 but the machine have less than 1024 cpus (almost
all machines in the world), the above can run successfully.
Fortunatelly, BIG SGI machine is mainly used for HPC use case. It means
they can rebuild their programs.
IOW we hope they are not annoyed by this issue ...
Reported-by: Sharyathi Nagesh <sharyath@in.ibm.com>
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Acked-by: Ulrich Drepper <drepper@redhat.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jack Steiner <steiner@sgi.com>
Cc: Russ Anderson <rja@sgi.com>
Cc: Mike Travis <travis@sgi.com>
LKML-Reference: <20100312161316.9520.A69D9226@jp.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-03-12 07:15:36 +00:00
|
|
|
ret = retlen;
|
2008-11-24 16:05:11 +00:00
|
|
|
}
|
|
|
|
free_cpumask_var(mask);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2008-11-24 16:05:11 +00:00
|
|
|
return ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sys_sched_yield - yield the current processor to other threads.
|
|
|
|
*
|
2007-07-09 16:51:59 +00:00
|
|
|
* This function yields the current CPU to other tasks. If there are no
|
|
|
|
* other threads running on this CPU then this function will return.
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: 0.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2018-03-14 21:40:35 +00:00
|
|
|
static void do_sched_yield(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
|
|
|
|
2018-10-26 22:06:23 +00:00
|
|
|
rq = this_rq_lock_irq(&rf);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2016-06-17 17:43:24 +00:00
|
|
|
schedstat_inc(rq->yld_count);
|
2007-10-15 15:00:08 +00:00
|
|
|
current->sched_class->yield_task(rq);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we are going to call schedule() anyway, there's
|
|
|
|
* no need to preempt or enable interrupts:
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
preempt_disable();
|
|
|
|
rq_unlock(rq, &rf);
|
2011-03-21 12:32:17 +00:00
|
|
|
sched_preempt_enable_no_resched();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
schedule();
|
2018-03-14 21:40:35 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2018-03-14 21:40:35 +00:00
|
|
|
SYSCALL_DEFINE0(sched_yield)
|
|
|
|
{
|
|
|
|
do_sched_yield();
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-26 21:19:37 +00:00
|
|
|
#ifndef CONFIG_PREEMPTION
|
2008-01-25 20:08:28 +00:00
|
|
|
int __sched _cond_resched(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-07-15 09:52:04 +00:00
|
|
|
if (should_resched(0)) {
|
2015-01-22 17:08:04 +00:00
|
|
|
preempt_schedule_common();
|
2005-04-16 22:20:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2016-11-30 14:24:30 +00:00
|
|
|
rcu_all_qs();
|
2005-04-16 22:20:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2008-01-25 20:08:28 +00:00
|
|
|
EXPORT_SYMBOL(_cond_resched);
|
2016-09-19 10:57:53 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
2009-07-16 13:44:29 +00:00
|
|
|
* __cond_resched_lock() - if a reschedule is pending, drop the given lock,
|
2005-04-16 22:20:36 +00:00
|
|
|
* call schedule, and on return reacquire the lock.
|
|
|
|
*
|
2019-07-26 21:19:37 +00:00
|
|
|
* This works OK both with and without CONFIG_PREEMPTION. We do strange low-level
|
2005-04-16 22:20:36 +00:00
|
|
|
* operations here to prevent schedule() from being called twice (once via
|
|
|
|
* spin_unlock(), once by hand).
|
|
|
|
*/
|
2009-07-16 13:44:29 +00:00
|
|
|
int __cond_resched_lock(spinlock_t *lock)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-07-15 09:52:04 +00:00
|
|
|
int resched = should_resched(PREEMPT_LOCK_OFFSET);
|
2005-06-13 22:52:32 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
2009-07-20 17:16:29 +00:00
|
|
|
lockdep_assert_held(lock);
|
|
|
|
|
2014-06-20 23:49:01 +00:00
|
|
|
if (spin_needbreak(lock) || resched) {
|
2005-04-16 22:20:36 +00:00
|
|
|
spin_unlock(lock);
|
2009-07-10 12:57:57 +00:00
|
|
|
if (resched)
|
2015-01-22 17:08:04 +00:00
|
|
|
preempt_schedule_common();
|
2008-01-30 12:31:20 +00:00
|
|
|
else
|
|
|
|
cpu_relax();
|
2005-06-13 22:52:32 +00:00
|
|
|
ret = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
spin_lock(lock);
|
|
|
|
}
|
2005-06-13 22:52:32 +00:00
|
|
|
return ret;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2009-07-16 13:44:29 +00:00
|
|
|
EXPORT_SYMBOL(__cond_resched_lock);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* yield - yield the current processor to other threads.
|
|
|
|
*
|
2012-03-06 17:54:26 +00:00
|
|
|
* Do not ever use this function, there's a 99% chance you're doing it wrong.
|
|
|
|
*
|
|
|
|
* The scheduler is at all times free to pick the calling task as the most
|
|
|
|
* eligible task to run, if removing the yield() call from your code breaks
|
|
|
|
* it, its already broken.
|
|
|
|
*
|
|
|
|
* Typical broken usage is:
|
|
|
|
*
|
|
|
|
* while (!event)
|
2017-02-01 10:46:42 +00:00
|
|
|
* yield();
|
2012-03-06 17:54:26 +00:00
|
|
|
*
|
|
|
|
* where one assumes that yield() will let 'the other' process run that will
|
|
|
|
* make event true. If the current task is a SCHED_FIFO task that will never
|
|
|
|
* happen. Never use yield() as a progress guarantee!!
|
|
|
|
*
|
|
|
|
* If you want to use yield() to wait for something, use wait_event().
|
|
|
|
* If you want to use yield() to be 'nice' for others, use cond_resched().
|
|
|
|
* If you still want to use yield(), do not!
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
void __sched yield(void)
|
|
|
|
{
|
|
|
|
set_current_state(TASK_RUNNING);
|
2018-03-14 21:40:35 +00:00
|
|
|
do_sched_yield();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(yield);
|
|
|
|
|
2011-02-01 14:50:51 +00:00
|
|
|
/**
|
|
|
|
* yield_to - yield the current processor to another thread in
|
|
|
|
* your thread group, or accelerate that thread toward the
|
|
|
|
* processor it's on.
|
2011-03-18 16:34:53 +00:00
|
|
|
* @p: target task
|
|
|
|
* @preempt: whether task preemption is allowed or not
|
2011-02-01 14:50:51 +00:00
|
|
|
*
|
|
|
|
* It's the caller's job to ensure that the target task struct
|
|
|
|
* can't go away on us before we can do any checks.
|
|
|
|
*
|
2013-07-12 18:45:47 +00:00
|
|
|
* Return:
|
2013-01-22 07:39:13 +00:00
|
|
|
* true (>0) if we indeed boosted the target task.
|
|
|
|
* false (0) if we failed to boost the target.
|
|
|
|
* -ESRCH if there's no task to yield to.
|
2011-02-01 14:50:51 +00:00
|
|
|
*/
|
2014-05-23 10:20:42 +00:00
|
|
|
int __sched yield_to(struct task_struct *p, bool preempt)
|
2011-02-01 14:50:51 +00:00
|
|
|
{
|
|
|
|
struct task_struct *curr = current;
|
|
|
|
struct rq *rq, *p_rq;
|
|
|
|
unsigned long flags;
|
2013-02-05 11:37:51 +00:00
|
|
|
int yielded = 0;
|
2011-02-01 14:50:51 +00:00
|
|
|
|
|
|
|
local_irq_save(flags);
|
|
|
|
rq = this_rq();
|
|
|
|
|
|
|
|
again:
|
|
|
|
p_rq = task_rq(p);
|
2013-01-22 07:39:13 +00:00
|
|
|
/*
|
|
|
|
* If we're the only runnable task on the rq and target rq also
|
|
|
|
* has only one task, there's absolutely no point in yielding.
|
|
|
|
*/
|
|
|
|
if (rq->nr_running == 1 && p_rq->nr_running == 1) {
|
|
|
|
yielded = -ESRCH;
|
|
|
|
goto out_irq;
|
|
|
|
}
|
|
|
|
|
2011-02-01 14:50:51 +00:00
|
|
|
double_rq_lock(rq, p_rq);
|
2013-11-23 09:38:01 +00:00
|
|
|
if (task_rq(p) != p_rq) {
|
2011-02-01 14:50:51 +00:00
|
|
|
double_rq_unlock(rq, p_rq);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!curr->sched_class->yield_to_task)
|
2013-01-22 07:39:13 +00:00
|
|
|
goto out_unlock;
|
2011-02-01 14:50:51 +00:00
|
|
|
|
|
|
|
if (curr->sched_class != p->sched_class)
|
2013-01-22 07:39:13 +00:00
|
|
|
goto out_unlock;
|
2011-02-01 14:50:51 +00:00
|
|
|
|
|
|
|
if (task_running(p_rq, p) || p->state)
|
2013-01-22 07:39:13 +00:00
|
|
|
goto out_unlock;
|
2011-02-01 14:50:51 +00:00
|
|
|
|
|
|
|
yielded = curr->sched_class->yield_to_task(rq, p, preempt);
|
2011-03-02 00:28:21 +00:00
|
|
|
if (yielded) {
|
2016-06-17 17:43:24 +00:00
|
|
|
schedstat_inc(rq->yld_count);
|
2011-03-02 00:28:21 +00:00
|
|
|
/*
|
|
|
|
* Make p's CPU reschedule; pick_next_entity takes care of
|
|
|
|
* fairness.
|
|
|
|
*/
|
|
|
|
if (preempt && rq != p_rq)
|
2014-06-28 20:03:57 +00:00
|
|
|
resched_curr(p_rq);
|
2011-03-02 00:28:21 +00:00
|
|
|
}
|
2011-02-01 14:50:51 +00:00
|
|
|
|
2013-01-22 07:39:13 +00:00
|
|
|
out_unlock:
|
2011-02-01 14:50:51 +00:00
|
|
|
double_rq_unlock(rq, p_rq);
|
2013-01-22 07:39:13 +00:00
|
|
|
out_irq:
|
2011-02-01 14:50:51 +00:00
|
|
|
local_irq_restore(flags);
|
|
|
|
|
2013-01-22 07:39:13 +00:00
|
|
|
if (yielded > 0)
|
2011-02-01 14:50:51 +00:00
|
|
|
schedule();
|
|
|
|
|
|
|
|
return yielded;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(yield_to);
|
|
|
|
|
2016-10-28 16:58:10 +00:00
|
|
|
int io_schedule_prepare(void)
|
|
|
|
{
|
|
|
|
int old_iowait = current->in_iowait;
|
|
|
|
|
|
|
|
current->in_iowait = 1;
|
|
|
|
blk_schedule_flush_plug(current);
|
|
|
|
|
|
|
|
return old_iowait;
|
|
|
|
}
|
|
|
|
|
|
|
|
void io_schedule_finish(int token)
|
|
|
|
{
|
|
|
|
current->in_iowait = token;
|
|
|
|
}
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2007-12-05 14:46:09 +00:00
|
|
|
* This task is about to go to sleep on IO. Increment rq->nr_iowait so
|
2005-04-16 22:20:36 +00:00
|
|
|
* that process accounting knows that this is a task in IO wait state.
|
|
|
|
*/
|
|
|
|
long __sched io_schedule_timeout(long timeout)
|
|
|
|
{
|
2016-10-28 16:58:10 +00:00
|
|
|
int token;
|
2005-04-16 22:20:36 +00:00
|
|
|
long ret;
|
|
|
|
|
2016-10-28 16:58:10 +00:00
|
|
|
token = io_schedule_prepare();
|
2005-04-16 22:20:36 +00:00
|
|
|
ret = schedule_timeout(timeout);
|
2016-10-28 16:58:10 +00:00
|
|
|
io_schedule_finish(token);
|
sched: Prevent recursion in io_schedule()
io_schedule() calls blk_flush_plug() which, depending on the
contents of current->plug, can initiate arbitrary blk-io requests.
Note that this contrasts with blk_schedule_flush_plug() which requires
all non-trivial work to be handed off to a separate thread.
This makes it possible for io_schedule() to recurse, and initiating
block requests could possibly call mempool_alloc() which, in times of
memory pressure, uses io_schedule().
Apart from any stack usage issues, io_schedule() will not behave
correctly when called recursively as delayacct_blkio_start() does
not allow for repeated calls.
So:
- use ->in_iowait to detect recursion. Set it earlier, and restore
it to the old value.
- move the call to "raw_rq" after the call to blk_flush_plug().
As this is some sort of per-cpu thing, we want some chance that
we are on the right CPU
- When io_schedule() is called recurively, use blk_schedule_flush_plug()
which cannot further recurse.
- as this makes io_schedule() a lot more complex and as io_schedule()
must match io_schedule_timeout(), but all the changes in io_schedule_timeout()
and make io_schedule a simple wrapper for that.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
[ Moved the now rudimentary io_schedule() into sched.h. ]
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Tony Battersby <tonyb@cybernetics.com>
Link: http://lkml.kernel.org/r/20150213162600.059fffb2@notabene.brown
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-02-13 04:49:17 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
return ret;
|
|
|
|
}
|
sched: Prevent recursion in io_schedule()
io_schedule() calls blk_flush_plug() which, depending on the
contents of current->plug, can initiate arbitrary blk-io requests.
Note that this contrasts with blk_schedule_flush_plug() which requires
all non-trivial work to be handed off to a separate thread.
This makes it possible for io_schedule() to recurse, and initiating
block requests could possibly call mempool_alloc() which, in times of
memory pressure, uses io_schedule().
Apart from any stack usage issues, io_schedule() will not behave
correctly when called recursively as delayacct_blkio_start() does
not allow for repeated calls.
So:
- use ->in_iowait to detect recursion. Set it earlier, and restore
it to the old value.
- move the call to "raw_rq" after the call to blk_flush_plug().
As this is some sort of per-cpu thing, we want some chance that
we are on the right CPU
- When io_schedule() is called recurively, use blk_schedule_flush_plug()
which cannot further recurse.
- as this makes io_schedule() a lot more complex and as io_schedule()
must match io_schedule_timeout(), but all the changes in io_schedule_timeout()
and make io_schedule a simple wrapper for that.
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
[ Moved the now rudimentary io_schedule() into sched.h. ]
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Tony Battersby <tonyb@cybernetics.com>
Link: http://lkml.kernel.org/r/20150213162600.059fffb2@notabene.brown
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-02-13 04:49:17 +00:00
|
|
|
EXPORT_SYMBOL(io_schedule_timeout);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2019-06-03 09:13:38 +00:00
|
|
|
void __sched io_schedule(void)
|
2016-10-28 16:58:10 +00:00
|
|
|
{
|
|
|
|
int token;
|
|
|
|
|
|
|
|
token = io_schedule_prepare();
|
|
|
|
schedule();
|
|
|
|
io_schedule_finish(token);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(io_schedule);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/**
|
|
|
|
* sys_sched_get_priority_max - return maximum RT priority.
|
|
|
|
* @policy: scheduling class.
|
|
|
|
*
|
2013-07-12 18:45:47 +00:00
|
|
|
* Return: On success, this syscall returns the maximum
|
|
|
|
* rt_priority that can be used by a given scheduling class.
|
|
|
|
* On failure, a negative error code is returned.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
switch (policy) {
|
|
|
|
case SCHED_FIFO:
|
|
|
|
case SCHED_RR:
|
|
|
|
ret = MAX_USER_RT_PRIO-1;
|
|
|
|
break;
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
case SCHED_DEADLINE:
|
2005-04-16 22:20:36 +00:00
|
|
|
case SCHED_NORMAL:
|
2006-01-14 21:20:41 +00:00
|
|
|
case SCHED_BATCH:
|
2007-07-09 16:51:59 +00:00
|
|
|
case SCHED_IDLE:
|
2005-04-16 22:20:36 +00:00
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* sys_sched_get_priority_min - return minimum RT priority.
|
|
|
|
* @policy: scheduling class.
|
|
|
|
*
|
2013-07-12 18:45:47 +00:00
|
|
|
* Return: On success, this syscall returns the minimum
|
|
|
|
* rt_priority that can be used by a given scheduling class.
|
|
|
|
* On failure, a negative error code is returned.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2009-01-14 13:14:08 +00:00
|
|
|
SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
switch (policy) {
|
|
|
|
case SCHED_FIFO:
|
|
|
|
case SCHED_RR:
|
|
|
|
ret = 1;
|
|
|
|
break;
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
case SCHED_DEADLINE:
|
2005-04-16 22:20:36 +00:00
|
|
|
case SCHED_NORMAL:
|
2006-01-14 21:20:41 +00:00
|
|
|
case SCHED_BATCH:
|
2007-07-09 16:51:59 +00:00
|
|
|
case SCHED_IDLE:
|
2005-04-16 22:20:36 +00:00
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-09-19 22:17:46 +00:00
|
|
|
static int sched_rr_get_interval(pid_t pid, struct timespec64 *t)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *p;
|
2007-10-15 15:00:13 +00:00
|
|
|
unsigned int time_slice;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
2009-12-09 08:32:03 +00:00
|
|
|
struct rq *rq;
|
2007-10-15 15:00:14 +00:00
|
|
|
int retval;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
if (pid < 0)
|
2007-10-15 15:00:14 +00:00
|
|
|
return -EINVAL;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
retval = -ESRCH;
|
2009-12-09 10:15:11 +00:00
|
|
|
rcu_read_lock();
|
2005-04-16 22:20:36 +00:00
|
|
|
p = find_process_by_pid(pid);
|
|
|
|
if (!p)
|
|
|
|
goto out_unlock;
|
|
|
|
|
|
|
|
retval = security_task_getscheduler(p);
|
|
|
|
if (retval)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2014-01-27 10:54:13 +00:00
|
|
|
time_slice = 0;
|
|
|
|
if (p->sched_class->get_rr_interval)
|
|
|
|
time_slice = p->sched_class->get_rr_interval(rq, p);
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2007-10-15 15:00:13 +00:00
|
|
|
|
2009-12-09 10:15:11 +00:00
|
|
|
rcu_read_unlock();
|
2017-09-19 22:17:46 +00:00
|
|
|
jiffies_to_timespec64(time_slice, t);
|
|
|
|
return 0;
|
2007-10-15 15:00:14 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
out_unlock:
|
2009-12-09 10:15:11 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2017-12-03 21:19:00 +00:00
|
|
|
/**
|
|
|
|
* sys_sched_rr_get_interval - return the default timeslice of a process.
|
|
|
|
* @pid: pid of the process.
|
|
|
|
* @interval: userspace pointer to the timeslice value.
|
|
|
|
*
|
|
|
|
* this syscall writes the default timeslice value of a given process
|
|
|
|
* into the user-space timespec buffer. A value of '0' means infinity.
|
|
|
|
*
|
|
|
|
* Return: On success, 0 and the timeslice is in @interval. Otherwise,
|
|
|
|
* an error code.
|
|
|
|
*/
|
2017-09-19 22:17:46 +00:00
|
|
|
SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
|
2018-04-17 19:59:47 +00:00
|
|
|
struct __kernel_timespec __user *, interval)
|
2017-09-19 22:17:46 +00:00
|
|
|
{
|
|
|
|
struct timespec64 t;
|
|
|
|
int retval = sched_rr_get_interval(pid, &t);
|
|
|
|
|
|
|
|
if (retval == 0)
|
|
|
|
retval = put_timespec64(&t, interval);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2018-04-17 19:59:47 +00:00
|
|
|
#ifdef CONFIG_COMPAT_32BIT_TIME
|
2019-01-06 23:33:08 +00:00
|
|
|
SYSCALL_DEFINE2(sched_rr_get_interval_time32, pid_t, pid,
|
|
|
|
struct old_timespec32 __user *, interval)
|
2017-09-19 22:17:46 +00:00
|
|
|
{
|
|
|
|
struct timespec64 t;
|
|
|
|
int retval = sched_rr_get_interval(pid, &t);
|
|
|
|
|
|
|
|
if (retval == 0)
|
y2038: globally rename compat_time to old_time32
Christoph Hellwig suggested a slightly different path for handling
backwards compatibility with the 32-bit time_t based system calls:
Rather than simply reusing the compat_sys_* entry points on 32-bit
architectures unchanged, we get rid of those entry points and the
compat_time types by renaming them to something that makes more sense
on 32-bit architectures (which don't have a compat mode otherwise),
and then share the entry points under the new name with the 64-bit
architectures that use them for implementing the compatibility.
The following types and interfaces are renamed here, and moved
from linux/compat_time.h to linux/time32.h:
old new
--- ---
compat_time_t old_time32_t
struct compat_timeval struct old_timeval32
struct compat_timespec struct old_timespec32
struct compat_itimerspec struct old_itimerspec32
ns_to_compat_timeval() ns_to_old_timeval32()
get_compat_itimerspec64() get_old_itimerspec32()
put_compat_itimerspec64() put_old_itimerspec32()
compat_get_timespec64() get_old_timespec32()
compat_put_timespec64() put_old_timespec32()
As we already have aliases in place, this patch addresses only the
instances that are relevant to the system call interface in particular,
not those that occur in device drivers and other modules. Those
will get handled separately, while providing the 64-bit version
of the respective interfaces.
I'm not renaming the timex, rusage and itimerval structures, as we are
still debating what the new interface will look like, and whether we
will need a replacement at all.
This also doesn't change the names of the syscall entry points, which can
be done more easily when we actually switch over the 32-bit architectures
to use them, at that point we need to change COMPAT_SYSCALL_DEFINEx to
SYSCALL_DEFINEx with a new name, e.g. with a _time32 suffix.
Suggested-by: Christoph Hellwig <hch@infradead.org>
Link: https://lore.kernel.org/lkml/20180705222110.GA5698@infradead.org/
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2018-07-13 10:52:28 +00:00
|
|
|
retval = put_old_timespec32(&t, interval);
|
2017-09-19 22:17:46 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-01-25 20:08:02 +00:00
|
|
|
void sched_show_task(struct task_struct *p)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
|
|
|
unsigned long free = 0;
|
2012-11-07 21:35:32 +00:00
|
|
|
int ppid;
|
2017-02-03 11:22:54 +00:00
|
|
|
|
2016-11-02 10:50:29 +00:00
|
|
|
if (!try_get_task_stack(p))
|
|
|
|
return;
|
2017-08-07 08:44:23 +00:00
|
|
|
|
|
|
|
printk(KERN_INFO "%-15.15s %c", p->comm, task_state_to_char(p));
|
|
|
|
|
|
|
|
if (p->state == TASK_RUNNING)
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_CONT " running task ");
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_DEBUG_STACK_USAGE
|
2008-04-22 21:38:23 +00:00
|
|
|
free = stack_not_used(p);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2014-12-10 23:45:21 +00:00
|
|
|
ppid = 0;
|
2012-11-07 21:35:32 +00:00
|
|
|
rcu_read_lock();
|
2014-12-10 23:45:21 +00:00
|
|
|
if (pid_alive(p))
|
|
|
|
ppid = task_pid_nr(rcu_dereference(p->real_parent));
|
2012-11-07 21:35:32 +00:00
|
|
|
rcu_read_unlock();
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_CONT "%5lu %5d %6d 0x%08lx\n", free,
|
2012-11-07 21:35:32 +00:00
|
|
|
task_pid_nr(p), ppid,
|
2009-05-04 08:38:05 +00:00
|
|
|
(unsigned long)task_thread_info(p)->flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2013-04-30 22:27:22 +00:00
|
|
|
print_worker_info(KERN_INFO, p);
|
2008-01-25 20:08:34 +00:00
|
|
|
show_stack(p, NULL);
|
2016-11-02 10:50:29 +00:00
|
|
|
put_task_stack(p);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2017-08-30 17:40:17 +00:00
|
|
|
EXPORT_SYMBOL_GPL(sched_show_task);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2017-09-22 16:32:41 +00:00
|
|
|
static inline bool
|
|
|
|
state_filter_match(unsigned long state_filter, struct task_struct *p)
|
|
|
|
{
|
|
|
|
/* no filter, everything matches */
|
|
|
|
if (!state_filter)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/* filter, but doesn't match */
|
|
|
|
if (!(p->state & state_filter))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows
|
|
|
|
* TASK_KILLABLE).
|
|
|
|
*/
|
|
|
|
if (state_filter == TASK_UNINTERRUPTIBLE && p->state == TASK_IDLE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-07 04:35:59 +00:00
|
|
|
void show_state_filter(unsigned long state_filter)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *g, *p;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-11 19:21:47 +00:00
|
|
|
#if BITS_PER_LONG == 32
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_INFO
|
|
|
|
" task PC stack pid father\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
#else
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_INFO
|
|
|
|
" task PC stack pid father\n");
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
2011-07-17 18:47:54 +00:00
|
|
|
rcu_read_lock();
|
2014-08-13 19:19:53 +00:00
|
|
|
for_each_process_thread(g, p) {
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* reset the NMI-timeout, listing all files on a slow
|
2011-03-31 01:57:33 +00:00
|
|
|
* console might take a lot of time:
|
2016-06-09 12:20:05 +00:00
|
|
|
* Also, reset softlockup watchdogs on all CPUs, because
|
|
|
|
* another CPU might be blocked waiting for us to process
|
|
|
|
* an IPI.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
|
|
|
touch_nmi_watchdog();
|
2016-06-09 12:20:05 +00:00
|
|
|
touch_all_softlockup_watchdogs();
|
2017-09-22 16:32:41 +00:00
|
|
|
if (state_filter_match(state_filter, p))
|
2008-01-25 20:08:02 +00:00
|
|
|
sched_show_task(p);
|
2014-08-13 19:19:53 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
#ifdef CONFIG_SCHED_DEBUG
|
2016-04-04 13:42:02 +00:00
|
|
|
if (!state_filter)
|
|
|
|
sysrq_sched_debug_show();
|
2007-07-09 16:51:59 +00:00
|
|
|
#endif
|
2011-07-17 18:47:54 +00:00
|
|
|
rcu_read_unlock();
|
2006-12-07 04:35:59 +00:00
|
|
|
/*
|
|
|
|
* Only show locks if all tasks are dumped:
|
|
|
|
*/
|
2009-11-25 13:23:41 +00:00
|
|
|
if (!state_filter)
|
2006-12-07 04:35:59 +00:00
|
|
|
debug_show_all_locks();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2005-06-28 14:40:42 +00:00
|
|
|
/**
|
|
|
|
* init_idle - set up an idle thread for a given CPU
|
|
|
|
* @idle: task in question
|
2017-02-01 10:46:42 +00:00
|
|
|
* @cpu: CPU the idle task belongs to
|
2005-06-28 14:40:42 +00:00
|
|
|
*
|
|
|
|
* NOTE: this function does not set the idle thread's NEED_RESCHED
|
|
|
|
* flag, to make booting more robust.
|
|
|
|
*/
|
2013-06-19 18:53:51 +00:00
|
|
|
void init_idle(struct task_struct *idle, int cpu)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2006-07-03 07:25:42 +00:00
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2005-04-16 22:20:36 +00:00
|
|
|
unsigned long flags;
|
|
|
|
|
2019-10-01 09:18:37 +00:00
|
|
|
__sched_fork(0, idle);
|
|
|
|
|
2015-05-15 15:43:34 +00:00
|
|
|
raw_spin_lock_irqsave(&idle->pi_lock, flags);
|
|
|
|
raw_spin_lock(&rq->lock);
|
2008-11-12 19:05:50 +00:00
|
|
|
|
2009-12-16 17:04:35 +00:00
|
|
|
idle->state = TASK_RUNNING;
|
2007-07-09 16:51:59 +00:00
|
|
|
idle->se.exec_start = sched_clock();
|
2016-11-29 07:03:05 +00:00
|
|
|
idle->flags |= PF_IDLE;
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2016-03-09 22:08:18 +00:00
|
|
|
kasan_unpoison_task_stack(idle);
|
|
|
|
|
2015-08-13 21:09:29 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
/*
|
|
|
|
* Its possible that init_idle() gets called multiple times on a task,
|
|
|
|
* in that case do_set_cpus_allowed() will not do the right thing.
|
|
|
|
*
|
|
|
|
* And since this is boot we can forgo the serialization.
|
|
|
|
*/
|
|
|
|
set_cpus_allowed_common(idle, cpumask_of(cpu));
|
|
|
|
#endif
|
2010-09-16 15:50:31 +00:00
|
|
|
/*
|
|
|
|
* We're having a chicken and egg problem, even though we are
|
2017-02-01 10:46:42 +00:00
|
|
|
* holding rq->lock, the CPU isn't yet set to this CPU so the
|
2010-09-16 15:50:31 +00:00
|
|
|
* lockdep check in task_group() will fail.
|
|
|
|
*
|
|
|
|
* Similar case to sched_fork(). / Alternatively we could
|
|
|
|
* use task_rq_lock() here and obtain the other rq->lock.
|
|
|
|
*
|
|
|
|
* Silence PROVE_RCU
|
|
|
|
*/
|
|
|
|
rcu_read_lock();
|
2007-07-09 16:51:59 +00:00
|
|
|
__set_task_cpu(idle, cpu);
|
2010-09-16 15:50:31 +00:00
|
|
|
rcu_read_unlock();
|
2005-04-16 22:20:36 +00:00
|
|
|
|
tasks, sched/core: RCUify the assignment of rq->curr
The current task on the runqueue is currently read with rcu_dereference().
To obtain ordinary RCU semantics for an rcu_dereference() of rq->curr it needs
to be paired with rcu_assign_pointer() of rq->curr. Which provides the
memory barrier necessary to order assignments to the task_struct
and the assignment to rq->curr.
Unfortunately the assignment of rq->curr in __schedule is a hot path,
and it has already been show that additional barriers in that code
will reduce the performance of the scheduler. So I will attempt to
describe below why you can effectively have ordinary RCU semantics
without any additional barriers.
The assignment of rq->curr in init_idle is a slow path called once
per cpu and that can use rcu_assign_pointer() without any concerns.
As I write this there are effectively two users of rcu_dereference() on
rq->curr. There is the membarrier code in kernel/sched/membarrier.c
that only looks at "->mm" after the rcu_dereference(). Then there is
task_numa_compare() in kernel/sched/fair.c. My best reading of the
code shows that task_numa_compare only access: "->flags",
"->cpus_ptr", "->numa_group", "->numa_faults[]",
"->total_numa_faults", and "->se.cfs_rq".
The code in __schedule() essentially does:
rq_lock(...);
smp_mb__after_spinlock();
next = pick_next_task(...);
rq->curr = next;
context_switch(prev, next);
At the start of the function the rq_lock/smp_mb__after_spinlock
pair provides a full memory barrier. Further there is a full memory barrier
in context_switch().
This means that any task that has already run and modified itself (the
common case) has already seen two memory barriers before __schedule()
runs and begins executing. A task that modifies itself then sees a
third full memory barrier pair with the rq_lock();
For a brand new task that is enqueued with wake_up_new_task() there
are the memory barriers present from the taking and release the
pi_lock and the rq_lock as the processes is enqueued as well as the
full memory barrier at the start of __schedule() assuming __schedule()
happens on the same cpu.
This means that by the time we reach the assignment of rq->curr
except for values on the task struct modified in pick_next_task
the code has the same guarantees as if it used rcu_assign_pointer().
Reading through all of the implementations of pick_next_task it
appears pick_next_task is limited to modifying the task_struct fields
"->se", "->rt", "->dl". These fields are the sched_entity structures
of the varies schedulers.
Further "->se.cfs_rq" is only changed in cgroup attach/move operations
initialized by userspace.
Unless I have missed something this means that in practice that the
users of "rcu_dereference(rq->curr)" get normal RCU semantics of
rcu_dereference() for the fields the care about, despite the
assignment of rq->curr in __schedule() ot using rcu_assign_pointer.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Chris Metcalf <cmetcalf@ezchip.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Kirill Tkhai <tkhai@yandex.ru>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russell King - ARM Linux admin <linux@armlinux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20190903200603.GW2349@hirez.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-09-14 12:35:02 +00:00
|
|
|
rq->idle = idle;
|
|
|
|
rcu_assign_pointer(rq->curr, idle);
|
2014-08-20 09:47:32 +00:00
|
|
|
idle->on_rq = TASK_ON_RQ_QUEUED;
|
2015-08-13 21:09:29 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2011-04-05 15:23:40 +00:00
|
|
|
idle->on_cpu = 1;
|
2005-06-25 21:57:23 +00:00
|
|
|
#endif
|
2015-05-15 15:43:34 +00:00
|
|
|
raw_spin_unlock(&rq->lock);
|
|
|
|
raw_spin_unlock_irqrestore(&idle->pi_lock, flags);
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/* Set the preempt count _outside_ the spinlocks! */
|
2013-08-14 12:55:46 +00:00
|
|
|
init_idle_preempt_count(idle, cpu);
|
2008-08-04 06:54:26 +00:00
|
|
|
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
|
|
|
* The idle tasks have their own, simple scheduling class:
|
|
|
|
*/
|
|
|
|
idle->sched_class = &idle_sched_class;
|
ftrace: Fix memory leak with function graph and cpu hotplug
When the fuction graph tracer starts, it needs to make a special
stack for each task to save the real return values of the tasks.
All running tasks have this stack created, as well as any new
tasks.
On CPU hot plug, the new idle task will allocate a stack as well
when init_idle() is called. The problem is that cpu hotplug does
not create a new idle_task. Instead it uses the idle task that
existed when the cpu went down.
ftrace_graph_init_task() will add a new ret_stack to the task
that is given to it. Because a clone will make the task
have a stack of its parent it does not check if the task's
ret_stack is already NULL or not. When the CPU hotplug code
starts a CPU up again, it will allocate a new stack even
though one already existed for it.
The solution is to treat the idle_task specially. In fact, the
function_graph code already does, just not at init_idle().
Instead of using the ftrace_graph_init_task() for the idle task,
which that function expects the task to be a clone, have a
separate ftrace_graph_init_idle_task(). Also, we will create a
per_cpu ret_stack that is used by the idle task. When we call
ftrace_graph_init_idle_task() it will check if the idle task's
ret_stack is NULL, if it is, then it will assign it the per_cpu
ret_stack.
Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Suggested-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stable Tree <stable@kernel.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
2011-02-11 02:26:13 +00:00
|
|
|
ftrace_graph_init_idle_task(idle, cpu);
|
2013-05-15 20:16:32 +00:00
|
|
|
vtime_init_idle(idle, cpu);
|
2015-08-13 21:09:29 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2011-10-26 21:14:16 +00:00
|
|
|
sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu);
|
|
|
|
#endif
|
2007-11-09 21:39:38 +00:00
|
|
|
}
|
|
|
|
|
2017-06-14 17:19:23 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
|
2014-10-07 08:52:11 +00:00
|
|
|
int cpuset_cpumask_can_shrink(const struct cpumask *cur,
|
|
|
|
const struct cpumask *trial)
|
|
|
|
{
|
2017-06-21 18:22:01 +00:00
|
|
|
int ret = 1;
|
2014-10-07 08:52:11 +00:00
|
|
|
|
2015-01-28 03:53:55 +00:00
|
|
|
if (!cpumask_weight(cur))
|
|
|
|
return ret;
|
|
|
|
|
2017-06-21 18:22:01 +00:00
|
|
|
ret = dl_cpuset_cpumask_can_shrink(cur, trial);
|
2014-10-07 08:52:11 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-09-19 09:22:40 +00:00
|
|
|
int task_can_attach(struct task_struct *p,
|
|
|
|
const struct cpumask *cs_cpus_allowed)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Kthreads which disallow setaffinity shouldn't be moved
|
2017-02-01 10:46:42 +00:00
|
|
|
* to a new cpuset; we don't want to change their CPU
|
2014-09-19 09:22:40 +00:00
|
|
|
* affinity and isolating such threads by their set of
|
|
|
|
* allowed nodes is unnecessary. Thus, cpusets are not
|
|
|
|
* applicable for such threads. This prevents checking for
|
|
|
|
* success of set_cpus_allowed_ptr() on all attached tasks
|
2019-04-23 14:26:36 +00:00
|
|
|
* before cpus_mask may be changed.
|
2014-09-19 09:22:40 +00:00
|
|
|
*/
|
|
|
|
if (p->flags & PF_NO_SETAFFINITY) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dl_task(p) && !cpumask_intersects(task_rq(p)->rd->span,
|
2017-06-21 18:22:01 +00:00
|
|
|
cs_cpus_allowed))
|
|
|
|
ret = dl_task_can_attach(p, cs_cpus_allowed);
|
2014-09-19 09:22:40 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-02-01 12:10:18 +00:00
|
|
|
bool sched_smp_initialized __read_mostly;
|
2016-03-10 11:54:10 +00:00
|
|
|
|
2013-10-07 10:29:02 +00:00
|
|
|
#ifdef CONFIG_NUMA_BALANCING
|
|
|
|
/* Migrate current task p to target_cpu */
|
|
|
|
int migrate_task_to(struct task_struct *p, int target_cpu)
|
|
|
|
{
|
|
|
|
struct migration_arg arg = { p, target_cpu };
|
|
|
|
int curr_cpu = task_cpu(p);
|
|
|
|
|
|
|
|
if (curr_cpu == target_cpu)
|
|
|
|
return 0;
|
|
|
|
|
2019-04-23 14:26:36 +00:00
|
|
|
if (!cpumask_test_cpu(target_cpu, p->cpus_ptr))
|
2013-10-07 10:29:02 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* TODO: This is not properly updating schedstats */
|
|
|
|
|
2014-01-21 23:51:03 +00:00
|
|
|
trace_sched_move_numa(p, curr_cpu, target_cpu);
|
2013-10-07 10:29:02 +00:00
|
|
|
return stop_one_cpu(curr_cpu, migration_cpu_stop, &arg);
|
|
|
|
}
|
2013-10-07 10:29:33 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Requeue a task on a given node and accurately track the number of NUMA
|
|
|
|
* tasks on the runqueues
|
|
|
|
*/
|
|
|
|
void sched_setnuma(struct task_struct *p, int nid)
|
|
|
|
{
|
2014-08-20 09:47:32 +00:00
|
|
|
bool queued, running;
|
2015-07-31 19:28:18 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
2013-10-07 10:29:33 +00:00
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
rq = task_rq_lock(p, &rf);
|
2014-08-20 09:47:32 +00:00
|
|
|
queued = task_on_rq_queued(p);
|
2013-10-07 10:29:33 +00:00
|
|
|
running = task_current(rq, p);
|
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
sched/core: Fix task and run queue sched_info::run_delay inconsistencies
Mike Meyer reported the following bug:
> During evaluation of some performance data, it was discovered thread
> and run queue run_delay accounting data was inconsistent with the other
> accounting data that was collected. Further investigation found under
> certain circumstances execution time was leaking into the task and
> run queue accounting of run_delay.
>
> Consider the following sequence:
>
> a. thread is running.
> b. thread moves beween cgroups, changes scheduling class or priority.
> c. thread sleeps OR
> d. thread involuntarily gives up cpu.
>
> a. implies:
>
> thread->sched_info.last_queued = 0
>
> a. and b. results in the following:
>
> 1. dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
> delta = 0
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> 2. enqueue_task(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* thread is still on cpu at this point. */
> thread->sched_info.last_queued = task_rq(thread)->clock;
>
> c. results in:
>
> dequeue_task(rq, thread)
>
> sched_info_dequeued(rq, thread)
>
> /* delta is execution time not run_delay. */
> delta = task_rq(thread)->clock - thread->sched_info.last_queued
>
> sched_info_reset_dequeued(thread)
> thread->sched_info.last_queued = 0
>
> thread->sched_info.run_delay += delta
>
> Since thread was running between enqueue_task(rq, thread) and
> dequeue_task(rq, thread), the delta above is really execution
> time and not run_delay.
>
> d. results in:
>
> __sched_info_switch(thread, next_thread)
>
> sched_info_depart(rq, thread)
>
> sched_info_queued(rq, thread)
>
> /* last_queued not updated due to being non-zero */
> return
>
> Since thread was running between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread), the execution time
> between enqueue_task(rq, thread) and
> __sched_info_switch(thread, next_thread) now will become
> associated with run_delay due to when last_queued was last updated.
>
This alternative patch solves the problem by not calling
sched_info_{de,}queued() in {de,en}queue_task(). Therefore the
sched_info state is preserved and things work as expected.
By inlining the {de,en}queue_task() functions the new condition
becomes (mostly) a compile-time constant and we'll not emit any new
branch instructions.
It even shrinks the code (due to inlining {en,de}queue_task()):
$ size defconfig-build/kernel/sched/core.o defconfig-build/kernel/sched/core.o.orig
text data bss dec hex filename
64019 23378 2344 89741 15e8d defconfig-build/kernel/sched/core.o
64149 23378 2344 89871 15f0f defconfig-build/kernel/sched/core.o.orig
Reported-by: Mike Meyer <Mike.Meyer@Teradata.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/20150930154413.GO3604@twins.programming.kicks-ass.net
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2015-09-30 15:44:13 +00:00
|
|
|
dequeue_task(rq, p, DEQUEUE_SAVE);
|
2013-10-07 10:29:33 +00:00
|
|
|
if (running)
|
2014-09-12 13:41:40 +00:00
|
|
|
put_prev_task(rq, p);
|
2013-10-07 10:29:33 +00:00
|
|
|
|
|
|
|
p->numa_preferred_nid = nid;
|
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2017-02-21 13:23:38 +00:00
|
|
|
enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK);
|
2016-09-12 07:47:52 +00:00
|
|
|
if (running)
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, p);
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, p, &rf);
|
2013-10-07 10:29:33 +00:00
|
|
|
}
|
2015-06-11 12:46:50 +00:00
|
|
|
#endif /* CONFIG_NUMA_BALANCING */
|
2007-10-17 06:30:56 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
2006-12-10 10:20:11 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* Ensure that the idle task is using init_mm right before its CPU goes
|
2010-11-13 18:32:29 +00:00
|
|
|
* offline.
|
2006-12-10 10:20:11 +00:00
|
|
|
*/
|
2010-11-13 18:32:29 +00:00
|
|
|
void idle_task_exit(void)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2010-11-13 18:32:29 +00:00
|
|
|
struct mm_struct *mm = current->active_mm;
|
2008-11-24 16:05:11 +00:00
|
|
|
|
2010-11-13 18:32:29 +00:00
|
|
|
BUG_ON(cpu_online(smp_processor_id()));
|
2008-11-24 16:05:11 +00:00
|
|
|
|
2012-10-26 15:17:44 +00:00
|
|
|
if (mm != &init_mm) {
|
2017-06-09 18:49:15 +00:00
|
|
|
switch_mm(mm, &init_mm, current);
|
2018-04-05 23:25:12 +00:00
|
|
|
current->active_mm = &init_mm;
|
2012-10-26 15:17:44 +00:00
|
|
|
finish_arch_post_lock_switch();
|
|
|
|
}
|
2010-11-13 18:32:29 +00:00
|
|
|
mmdrop(mm);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-08-20 09:26:57 +00:00
|
|
|
* Since this CPU is going 'away' for a while, fold any nr_active delta
|
|
|
|
* we might have. Assumes we're called after migrate_tasks() so that the
|
2016-07-12 16:33:56 +00:00
|
|
|
* nr_active count is stable. We need to take the teardown thread which
|
|
|
|
* is calling this into account, so we hand in adjust = 1 to the load
|
|
|
|
* calculation.
|
2012-08-20 09:26:57 +00:00
|
|
|
*
|
|
|
|
* Also see the comment "Global load-average calculations".
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2012-08-20 09:26:57 +00:00
|
|
|
static void calc_load_migrate(struct rq *rq)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2016-07-12 16:33:56 +00:00
|
|
|
long delta = calc_load_fold_active(rq, 1);
|
2012-08-20 09:26:57 +00:00
|
|
|
if (delta)
|
|
|
|
atomic_long_add(delta, &calc_load_tasks);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-08-06 13:13:17 +00:00
|
|
|
static struct task_struct *__pick_migrate_task(struct rq *rq)
|
2014-02-12 09:49:30 +00:00
|
|
|
{
|
2019-08-06 13:13:17 +00:00
|
|
|
const struct sched_class *class;
|
|
|
|
struct task_struct *next;
|
2014-02-12 09:49:30 +00:00
|
|
|
|
2019-08-06 13:13:17 +00:00
|
|
|
for_each_class(class) {
|
2019-11-08 13:15:58 +00:00
|
|
|
next = class->pick_next_task(rq);
|
2019-08-06 13:13:17 +00:00
|
|
|
if (next) {
|
2019-11-08 10:11:52 +00:00
|
|
|
next->sched_class->put_prev_task(rq, next);
|
2019-08-06 13:13:17 +00:00
|
|
|
return next;
|
|
|
|
}
|
|
|
|
}
|
2014-02-12 09:49:30 +00:00
|
|
|
|
2019-08-06 13:13:17 +00:00
|
|
|
/* The idle class should always have a runnable task */
|
|
|
|
BUG();
|
|
|
|
}
|
2014-02-12 09:49:30 +00:00
|
|
|
|
2006-07-03 07:25:40 +00:00
|
|
|
/*
|
2010-11-13 18:32:29 +00:00
|
|
|
* Migrate all tasks from the rq, sleeping tasks will be migrated by
|
|
|
|
* try_to_wake_up()->select_task_rq().
|
|
|
|
*
|
|
|
|
* Called with rq->lock held even though we'er in stop_machine() and
|
|
|
|
* there's no concurrency possible, we hold the required locks anyway
|
|
|
|
* because of lock validation efforts.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
static void migrate_tasks(struct rq *dead_rq, struct rq_flags *rf)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2015-06-11 12:46:51 +00:00
|
|
|
struct rq *rq = dead_rq;
|
2010-11-13 18:32:29 +00:00
|
|
|
struct task_struct *next, *stop = rq->stop;
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags orf = *rf;
|
2010-11-13 18:32:29 +00:00
|
|
|
int dest_cpu;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
/*
|
2010-11-13 18:32:29 +00:00
|
|
|
* Fudge the rq selection such that the below task selection loop
|
|
|
|
* doesn't get stuck on the currently eligible stop task.
|
|
|
|
*
|
|
|
|
* We're currently inside stop_machine() and the rq is either stuck
|
|
|
|
* in the stop_machine_cpu_stop() loop, or we're executing this code,
|
|
|
|
* either way we should never end up calling schedule() until we're
|
|
|
|
* done here.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2010-11-13 18:32:29 +00:00
|
|
|
rq->stop = NULL;
|
2006-07-03 07:25:40 +00:00
|
|
|
|
2013-04-11 23:50:58 +00:00
|
|
|
/*
|
|
|
|
* put_prev_task() and pick_next_task() sched
|
|
|
|
* class method both need to have an up-to-date
|
|
|
|
* value of rq->clock[_task]
|
|
|
|
*/
|
|
|
|
update_rq_clock(rq);
|
|
|
|
|
2015-06-11 12:46:51 +00:00
|
|
|
for (;;) {
|
2010-11-13 18:32:29 +00:00
|
|
|
/*
|
|
|
|
* There's this thread running, bail when that's the only
|
2017-02-01 10:46:42 +00:00
|
|
|
* remaining thread:
|
2010-11-13 18:32:29 +00:00
|
|
|
*/
|
|
|
|
if (rq->nr_running == 1)
|
2007-07-09 16:51:59 +00:00
|
|
|
break;
|
2010-11-13 18:32:29 +00:00
|
|
|
|
2019-08-06 13:13:17 +00:00
|
|
|
next = __pick_migrate_task(rq);
|
2007-07-26 11:40:43 +00:00
|
|
|
|
2015-08-28 06:55:56 +00:00
|
|
|
/*
|
2019-04-23 14:26:36 +00:00
|
|
|
* Rules for changing task_struct::cpus_mask are holding
|
2015-08-28 06:55:56 +00:00
|
|
|
* both pi_lock and rq->lock, such that holding either
|
|
|
|
* stabilizes the mask.
|
|
|
|
*
|
|
|
|
* Drop rq->lock is not quite as disastrous as it usually is
|
|
|
|
* because !cpu_active at this point, which means load-balance
|
|
|
|
* will not interfere. Also, stop-machine.
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, rf);
|
2015-08-28 06:55:56 +00:00
|
|
|
raw_spin_lock(&next->pi_lock);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_relock(rq, rf);
|
2015-08-28 06:55:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we're inside stop-machine, _nothing_ should have
|
|
|
|
* changed the task, WARN if weird stuff happened, because in
|
|
|
|
* that case the above rq->lock drop is a fail too.
|
|
|
|
*/
|
|
|
|
if (WARN_ON(task_rq(next) != rq || !task_on_rq_queued(next))) {
|
|
|
|
raw_spin_unlock(&next->pi_lock);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-11-13 18:32:29 +00:00
|
|
|
/* Find suitable destination for @next, with force if needed. */
|
2015-06-11 12:46:51 +00:00
|
|
|
dest_cpu = select_fallback_rq(dead_rq->cpu, next);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq = __migrate_task(rq, rf, next, dest_cpu);
|
2015-06-11 12:46:51 +00:00
|
|
|
if (rq != dead_rq) {
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock(rq, rf);
|
2015-06-11 12:46:51 +00:00
|
|
|
rq = dead_rq;
|
2016-10-04 14:04:35 +00:00
|
|
|
*rf = orf;
|
|
|
|
rq_relock(rq, rf);
|
2015-06-11 12:46:51 +00:00
|
|
|
}
|
2015-08-28 06:55:56 +00:00
|
|
|
raw_spin_unlock(&next->pi_lock);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2009-04-11 08:43:41 +00:00
|
|
|
|
2010-11-13 18:32:29 +00:00
|
|
|
rq->stop = stop;
|
2009-04-11 08:43:41 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif /* CONFIG_HOTPLUG_CPU */
|
|
|
|
|
2017-02-01 12:10:18 +00:00
|
|
|
void set_rq_online(struct rq *rq)
|
2008-06-04 19:04:05 +00:00
|
|
|
{
|
|
|
|
if (!rq->online) {
|
|
|
|
const struct sched_class *class;
|
|
|
|
|
2008-11-24 16:05:05 +00:00
|
|
|
cpumask_set_cpu(rq->cpu, rq->rd->online);
|
2008-06-04 19:04:05 +00:00
|
|
|
rq->online = 1;
|
|
|
|
|
|
|
|
for_each_class(class) {
|
|
|
|
if (class->rq_online)
|
|
|
|
class->rq_online(rq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-01 12:10:18 +00:00
|
|
|
void set_rq_offline(struct rq *rq)
|
2008-06-04 19:04:05 +00:00
|
|
|
{
|
|
|
|
if (rq->online) {
|
|
|
|
const struct sched_class *class;
|
|
|
|
|
|
|
|
for_each_class(class) {
|
|
|
|
if (class->rq_offline)
|
|
|
|
class->rq_offline(rq);
|
|
|
|
}
|
|
|
|
|
2008-11-24 16:05:05 +00:00
|
|
|
cpumask_clear_cpu(rq->cpu, rq->rd->online);
|
2008-06-04 19:04:05 +00:00
|
|
|
rq->online = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/*
|
|
|
|
* used to mark begin/end of suspend/resume:
|
|
|
|
*/
|
|
|
|
static int num_cpus_frozen;
|
CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume
In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed
masks as and when necessary to ensure that the tasks belonging to the cpusets
have some place (online CPUs) to run on. And regular CPU hotplug is
destructive in the sense that the kernel doesn't remember the original cpuset
configurations set by the user, across hotplug operations.
However, suspend/resume (which uses CPU hotplug) is a special case in which
the kernel has the responsibility to restore the system (during resume), to
exactly the same state it was in before suspend.
In order to achieve that, do the following:
1. Don't modify cpusets during suspend/resume. At all.
In particular, don't move the tasks from one cpuset to another, and
don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets
during the CPU hotplug operations that are carried out in the
suspend/resume path.
2. However, cpusets and sched domains are related. We just want to avoid
altering cpusets alone. So, to keep the sched domains updated, build
a single sched domain (containing all active cpus) during each of the
CPU hotplug operations carried out in s/r path, effectively ignoring
the cpusets' cpus_allowed masks.
(Since userspace is frozen while doing all this, it will go unnoticed.)
3. During the last CPU online operation during resume, build the sched
domains by looking up the (unaltered) cpusets' cpus_allowed masks.
That will bring back the system to the same original state as it was in
before suspend.
Ultimately, this will not only solve the cpuset problem related to suspend
resume (ie., restores the cpusets to exactly what it was before suspend, by
not touching it at all) but also speeds up suspend/resume because we avoid
running cpuset update code for every CPU being offlined/onlined.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-05-24 14:16:26 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
2010-06-08 19:40:36 +00:00
|
|
|
* Update cpusets according to cpu_active mask. If cpusets are
|
|
|
|
* disabled, cpuset_update_active_cpus() becomes a simple wrapper
|
|
|
|
* around partition_sched_domains().
|
CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume
In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed
masks as and when necessary to ensure that the tasks belonging to the cpusets
have some place (online CPUs) to run on. And regular CPU hotplug is
destructive in the sense that the kernel doesn't remember the original cpuset
configurations set by the user, across hotplug operations.
However, suspend/resume (which uses CPU hotplug) is a special case in which
the kernel has the responsibility to restore the system (during resume), to
exactly the same state it was in before suspend.
In order to achieve that, do the following:
1. Don't modify cpusets during suspend/resume. At all.
In particular, don't move the tasks from one cpuset to another, and
don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets
during the CPU hotplug operations that are carried out in the
suspend/resume path.
2. However, cpusets and sched domains are related. We just want to avoid
altering cpusets alone. So, to keep the sched domains updated, build
a single sched domain (containing all active cpus) during each of the
CPU hotplug operations carried out in s/r path, effectively ignoring
the cpusets' cpus_allowed masks.
(Since userspace is frozen while doing all this, it will go unnoticed.)
3. During the last CPU online operation during resume, build the sched
domains by looking up the (unaltered) cpusets' cpus_allowed masks.
That will bring back the system to the same original state as it was in
before suspend.
Ultimately, this will not only solve the cpuset problem related to suspend
resume (ie., restores the cpusets to exactly what it was before suspend, by
not touching it at all) but also speeds up suspend/resume because we avoid
running cpuset update code for every CPU being offlined/onlined.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-05-24 14:16:26 +00:00
|
|
|
*
|
|
|
|
* If we come here as part of a suspend/resume, don't touch cpusets because we
|
|
|
|
* want to restore it back to its original state upon resume anyway.
|
2005-04-16 22:20:36 +00:00
|
|
|
*/
|
2016-03-10 11:54:13 +00:00
|
|
|
static void cpuset_cpu_active(void)
|
2008-07-15 11:43:49 +00:00
|
|
|
{
|
2016-03-10 11:54:13 +00:00
|
|
|
if (cpuhp_tasks_frozen) {
|
CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume
In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed
masks as and when necessary to ensure that the tasks belonging to the cpusets
have some place (online CPUs) to run on. And regular CPU hotplug is
destructive in the sense that the kernel doesn't remember the original cpuset
configurations set by the user, across hotplug operations.
However, suspend/resume (which uses CPU hotplug) is a special case in which
the kernel has the responsibility to restore the system (during resume), to
exactly the same state it was in before suspend.
In order to achieve that, do the following:
1. Don't modify cpusets during suspend/resume. At all.
In particular, don't move the tasks from one cpuset to another, and
don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets
during the CPU hotplug operations that are carried out in the
suspend/resume path.
2. However, cpusets and sched domains are related. We just want to avoid
altering cpusets alone. So, to keep the sched domains updated, build
a single sched domain (containing all active cpus) during each of the
CPU hotplug operations carried out in s/r path, effectively ignoring
the cpusets' cpus_allowed masks.
(Since userspace is frozen while doing all this, it will go unnoticed.)
3. During the last CPU online operation during resume, build the sched
domains by looking up the (unaltered) cpusets' cpus_allowed masks.
That will bring back the system to the same original state as it was in
before suspend.
Ultimately, this will not only solve the cpuset problem related to suspend
resume (ie., restores the cpusets to exactly what it was before suspend, by
not touching it at all) but also speeds up suspend/resume because we avoid
running cpuset update code for every CPU being offlined/onlined.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-05-24 14:16:26 +00:00
|
|
|
/*
|
|
|
|
* num_cpus_frozen tracks how many CPUs are involved in suspend
|
|
|
|
* resume sequence. As long as this is not the last online
|
|
|
|
* operation in the resume sequence, just build a single sched
|
|
|
|
* domain, ignoring cpusets.
|
|
|
|
*/
|
2017-09-07 09:13:38 +00:00
|
|
|
partition_sched_domains(1, NULL, NULL);
|
|
|
|
if (--num_cpus_frozen)
|
2016-03-10 11:54:11 +00:00
|
|
|
return;
|
CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume
In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed
masks as and when necessary to ensure that the tasks belonging to the cpusets
have some place (online CPUs) to run on. And regular CPU hotplug is
destructive in the sense that the kernel doesn't remember the original cpuset
configurations set by the user, across hotplug operations.
However, suspend/resume (which uses CPU hotplug) is a special case in which
the kernel has the responsibility to restore the system (during resume), to
exactly the same state it was in before suspend.
In order to achieve that, do the following:
1. Don't modify cpusets during suspend/resume. At all.
In particular, don't move the tasks from one cpuset to another, and
don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets
during the CPU hotplug operations that are carried out in the
suspend/resume path.
2. However, cpusets and sched domains are related. We just want to avoid
altering cpusets alone. So, to keep the sched domains updated, build
a single sched domain (containing all active cpus) during each of the
CPU hotplug operations carried out in s/r path, effectively ignoring
the cpusets' cpus_allowed masks.
(Since userspace is frozen while doing all this, it will go unnoticed.)
3. During the last CPU online operation during resume, build the sched
domains by looking up the (unaltered) cpusets' cpus_allowed masks.
That will bring back the system to the same original state as it was in
before suspend.
Ultimately, this will not only solve the cpuset problem related to suspend
resume (ie., restores the cpusets to exactly what it was before suspend, by
not touching it at all) but also speeds up suspend/resume because we avoid
running cpuset update code for every CPU being offlined/onlined.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-05-24 14:16:26 +00:00
|
|
|
/*
|
|
|
|
* This is the last CPU online operation. So fall through and
|
|
|
|
* restore the original sched domains by considering the
|
|
|
|
* cpuset configurations.
|
|
|
|
*/
|
2017-09-07 09:13:38 +00:00
|
|
|
cpuset_force_rebuild();
|
2010-06-08 19:40:36 +00:00
|
|
|
}
|
2017-04-09 01:36:14 +00:00
|
|
|
cpuset_update_active_cpus();
|
2010-06-08 19:40:36 +00:00
|
|
|
}
|
2008-07-15 11:43:49 +00:00
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
static int cpuset_cpu_inactive(unsigned int cpu)
|
2010-06-08 19:40:36 +00:00
|
|
|
{
|
2016-03-10 11:54:13 +00:00
|
|
|
if (!cpuhp_tasks_frozen) {
|
2017-06-21 18:22:01 +00:00
|
|
|
if (dl_cpu_busy(cpu))
|
2016-03-10 11:54:11 +00:00
|
|
|
return -EBUSY;
|
2017-04-09 01:36:14 +00:00
|
|
|
cpuset_update_active_cpus();
|
2016-03-10 11:54:11 +00:00
|
|
|
} else {
|
CPU hotplug, cpusets, suspend: Don't modify cpusets during suspend/resume
In the event of CPU hotplug, the kernel modifies the cpusets' cpus_allowed
masks as and when necessary to ensure that the tasks belonging to the cpusets
have some place (online CPUs) to run on. And regular CPU hotplug is
destructive in the sense that the kernel doesn't remember the original cpuset
configurations set by the user, across hotplug operations.
However, suspend/resume (which uses CPU hotplug) is a special case in which
the kernel has the responsibility to restore the system (during resume), to
exactly the same state it was in before suspend.
In order to achieve that, do the following:
1. Don't modify cpusets during suspend/resume. At all.
In particular, don't move the tasks from one cpuset to another, and
don't modify any cpuset's cpus_allowed mask. So, simply ignore cpusets
during the CPU hotplug operations that are carried out in the
suspend/resume path.
2. However, cpusets and sched domains are related. We just want to avoid
altering cpusets alone. So, to keep the sched domains updated, build
a single sched domain (containing all active cpus) during each of the
CPU hotplug operations carried out in s/r path, effectively ignoring
the cpusets' cpus_allowed masks.
(Since userspace is frozen while doing all this, it will go unnoticed.)
3. During the last CPU online operation during resume, build the sched
domains by looking up the (unaltered) cpusets' cpus_allowed masks.
That will bring back the system to the same original state as it was in
before suspend.
Ultimately, this will not only solve the cpuset problem related to suspend
resume (ie., restores the cpusets to exactly what it was before suspend, by
not touching it at all) but also speeds up suspend/resume because we avoid
running cpuset update code for every CPU being offlined/onlined.
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20120524141611.3692.20155.stgit@srivatsabhat.in.ibm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2012-05-24 14:16:26 +00:00
|
|
|
num_cpus_frozen++;
|
|
|
|
partition_sched_domains(1, NULL, NULL);
|
2008-07-15 11:43:49 +00:00
|
|
|
}
|
2016-03-10 11:54:11 +00:00
|
|
|
return 0;
|
2008-07-15 11:43:49 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
int sched_cpu_activate(unsigned int cpu)
|
2016-03-10 11:54:11 +00:00
|
|
|
{
|
2016-03-10 11:54:17 +00:00
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2016-03-10 11:54:17 +00:00
|
|
|
|
2018-05-29 14:43:46 +00:00
|
|
|
#ifdef CONFIG_SCHED_SMT
|
|
|
|
/*
|
2018-11-25 18:33:36 +00:00
|
|
|
* When going up, increment the number of cores with SMT present.
|
2018-05-29 14:43:46 +00:00
|
|
|
*/
|
2018-11-25 18:33:36 +00:00
|
|
|
if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
|
|
|
|
static_branch_inc_cpuslocked(&sched_smt_present);
|
2018-05-29 14:43:46 +00:00
|
|
|
#endif
|
2016-03-10 11:54:13 +00:00
|
|
|
set_cpu_active(cpu, true);
|
2016-03-10 11:54:11 +00:00
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
if (sched_smp_initialized) {
|
2016-03-10 11:54:11 +00:00
|
|
|
sched_domains_numa_masks_set(cpu);
|
2016-03-10 11:54:13 +00:00
|
|
|
cpuset_cpu_active();
|
2008-07-15 11:43:49 +00:00
|
|
|
}
|
2016-03-10 11:54:17 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the rq online, if not already. This happens:
|
|
|
|
*
|
|
|
|
* 1) In the early boot process, because we build the real domains
|
2017-02-01 10:46:42 +00:00
|
|
|
* after all CPUs have been brought up.
|
2016-03-10 11:54:17 +00:00
|
|
|
*
|
|
|
|
* 2) At runtime, if cpuset_cpu_active() fails to rebuild the
|
|
|
|
* domains.
|
|
|
|
*/
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock_irqsave(rq, &rf);
|
2016-03-10 11:54:17 +00:00
|
|
|
if (rq->rd) {
|
|
|
|
BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
|
|
|
|
set_rq_online(rq);
|
|
|
|
}
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irqrestore(rq, &rf);
|
2016-03-10 11:54:17 +00:00
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
return 0;
|
2016-03-10 11:54:11 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
int sched_cpu_deactivate(unsigned int cpu)
|
2016-03-10 11:54:11 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
set_cpu_active(cpu, false);
|
2016-03-10 11:54:14 +00:00
|
|
|
/*
|
|
|
|
* We've cleared cpu_active_mask, wait for all preempt-disabled and RCU
|
|
|
|
* users of this state to go away such that all new such users will
|
|
|
|
* observe it.
|
|
|
|
*
|
|
|
|
* Do sync before park smpboot threads to take care the rcu boost case.
|
|
|
|
*/
|
2018-07-11 21:36:49 +00:00
|
|
|
synchronize_rcu();
|
2016-03-10 11:54:13 +00:00
|
|
|
|
2018-11-25 18:33:36 +00:00
|
|
|
#ifdef CONFIG_SCHED_SMT
|
|
|
|
/*
|
|
|
|
* When going down, decrement the number of cores with SMT present.
|
|
|
|
*/
|
|
|
|
if (cpumask_weight(cpu_smt_mask(cpu)) == 2)
|
|
|
|
static_branch_dec_cpuslocked(&sched_smt_present);
|
|
|
|
#endif
|
|
|
|
|
2016-03-10 11:54:13 +00:00
|
|
|
if (!sched_smp_initialized)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ret = cpuset_cpu_inactive(cpu);
|
|
|
|
if (ret) {
|
|
|
|
set_cpu_active(cpu, true);
|
|
|
|
return ret;
|
2016-03-10 11:54:11 +00:00
|
|
|
}
|
2016-03-10 11:54:13 +00:00
|
|
|
sched_domains_numa_masks_clear(cpu);
|
|
|
|
return 0;
|
2016-03-10 11:54:11 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 11:54:15 +00:00
|
|
|
static void sched_rq_cpu_starting(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
|
|
|
|
rq->calc_load_update = calc_load_update;
|
|
|
|
update_max_interval();
|
|
|
|
}
|
|
|
|
|
2016-03-10 11:54:11 +00:00
|
|
|
int sched_cpu_starting(unsigned int cpu)
|
|
|
|
{
|
2016-03-10 11:54:15 +00:00
|
|
|
sched_rq_cpu_starting(cpu);
|
2018-02-21 04:17:27 +00:00
|
|
|
sched_tick_start(cpu);
|
2016-03-10 11:54:11 +00:00
|
|
|
return 0;
|
2008-07-15 11:43:49 +00:00
|
|
|
}
|
|
|
|
|
2016-03-10 11:54:18 +00:00
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
int sched_cpu_dying(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct rq *rq = cpu_rq(cpu);
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2016-03-10 11:54:18 +00:00
|
|
|
|
|
|
|
/* Handle pending wakeups and then migrate everything off */
|
|
|
|
sched_ttwu_pending();
|
2018-02-21 04:17:27 +00:00
|
|
|
sched_tick_stop(cpu);
|
2016-10-04 14:04:35 +00:00
|
|
|
|
|
|
|
rq_lock_irqsave(rq, &rf);
|
2016-03-10 11:54:18 +00:00
|
|
|
if (rq->rd) {
|
|
|
|
BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
|
|
|
|
set_rq_offline(rq);
|
|
|
|
}
|
2016-10-04 14:04:35 +00:00
|
|
|
migrate_tasks(rq, &rf);
|
2016-03-10 11:54:18 +00:00
|
|
|
BUG_ON(rq->nr_running != 1);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irqrestore(rq, &rf);
|
|
|
|
|
2016-03-10 11:54:18 +00:00
|
|
|
calc_load_migrate(rq);
|
|
|
|
update_max_interval();
|
2017-12-21 14:06:50 +00:00
|
|
|
nohz_balance_exit_idle(rq);
|
2016-03-10 11:54:21 +00:00
|
|
|
hrtick_clear(rq);
|
2016-03-10 11:54:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
void __init sched_init_smp(void)
|
|
|
|
{
|
2012-04-17 13:49:36 +00:00
|
|
|
sched_init_numa();
|
|
|
|
|
2013-10-11 12:38:20 +00:00
|
|
|
/*
|
|
|
|
* There's no userspace yet to cause hotplug operations; hence all the
|
2017-02-01 10:46:42 +00:00
|
|
|
* CPU masks are stable and all blatant races in the below code cannot
|
2018-12-19 18:23:16 +00:00
|
|
|
* happen.
|
2013-10-11 12:38:20 +00:00
|
|
|
*/
|
2008-04-28 09:33:07 +00:00
|
|
|
mutex_lock(&sched_domains_mutex);
|
2017-04-25 13:29:40 +00:00
|
|
|
sched_init_domains(cpu_active_mask);
|
2008-04-28 09:33:07 +00:00
|
|
|
mutex_unlock(&sched_domains_mutex);
|
2008-07-15 11:43:49 +00:00
|
|
|
|
2006-10-03 08:14:04 +00:00
|
|
|
/* Move init over to a non-isolated CPU */
|
2017-10-27 02:42:37 +00:00
|
|
|
if (set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_FLAG_DOMAIN)) < 0)
|
2006-10-03 08:14:04 +00:00
|
|
|
BUG();
|
2007-11-09 21:39:38 +00:00
|
|
|
sched_init_granularity();
|
2008-11-24 16:05:12 +00:00
|
|
|
|
2008-11-24 16:05:13 +00:00
|
|
|
init_sched_rt_class();
|
sched/deadline: Add SCHED_DEADLINE SMP-related data structures & logic
Introduces data structures relevant for implementing dynamic
migration of -deadline tasks and the logic for checking if
runqueues are overloaded with -deadline tasks and for choosing
where a task should migrate, when it is the case.
Adds also dynamic migrations to SCHED_DEADLINE, so that tasks can
be moved among CPUs when necessary. It is also possible to bind a
task to a (set of) CPU(s), thus restricting its capability of
migrating, or forbidding migrations at all.
The very same approach used in sched_rt is utilised:
- -deadline tasks are kept into CPU-specific runqueues,
- -deadline tasks are migrated among runqueues to achieve the
following:
* on an M-CPU system the M earliest deadline ready tasks
are always running;
* affinity/cpusets settings of all the -deadline tasks is
always respected.
Therefore, this very special form of "load balancing" is done with
an active method, i.e., the scheduler pushes or pulls tasks between
runqueues when they are woken up and/or (de)scheduled.
IOW, every time a preemption occurs, the descheduled task might be sent
to some other CPU (depending on its deadline) to continue executing
(push). On the other hand, every time a CPU becomes idle, it might pull
the second earliest deadline ready task from some other CPU.
To enforce this, a pull operation is always attempted before taking any
scheduling decision (pre_schedule()), as well as a push one after each
scheduling decision (post_schedule()). In addition, when a task arrives
or wakes up, the best CPU where to resume it is selected taking into
account its affinity mask, the system topology, but also its deadline.
E.g., from the scheduling point of view, the best CPU where to wake
up (and also where to push) a task is the one which is running the task
with the latest deadline among the M executing ones.
In order to facilitate these decisions, per-runqueue "caching" of the
deadlines of the currently running and of the first ready task is used.
Queued but not running tasks are also parked in another rb-tree to
speed-up pushes.
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-5-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:38 +00:00
|
|
|
init_sched_dl_class();
|
2016-05-09 08:38:41 +00:00
|
|
|
|
2016-03-10 11:54:10 +00:00
|
|
|
sched_smp_initialized = true;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2016-03-10 11:54:10 +00:00
|
|
|
|
|
|
|
static int __init migration_init(void)
|
|
|
|
{
|
2019-04-11 03:34:44 +00:00
|
|
|
sched_cpu_starting(smp_processor_id());
|
2016-03-10 11:54:10 +00:00
|
|
|
return 0;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2016-03-10 11:54:10 +00:00
|
|
|
early_initcall(migration_init);
|
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
#else
|
|
|
|
void __init sched_init_smp(void)
|
|
|
|
{
|
2007-11-09 21:39:38 +00:00
|
|
|
sched_init_granularity();
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
#endif /* CONFIG_SMP */
|
|
|
|
|
|
|
|
int in_sched_functions(unsigned long addr)
|
|
|
|
{
|
|
|
|
return in_lock_functions(addr) ||
|
|
|
|
(addr >= (unsigned long)__sched_text_start
|
|
|
|
&& addr < (unsigned long)__sched_text_end);
|
|
|
|
}
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
#ifdef CONFIG_CGROUP_SCHED
|
2013-03-05 08:07:52 +00:00
|
|
|
/*
|
|
|
|
* Default task group.
|
|
|
|
* Every task in system belongs to this group at bootup.
|
|
|
|
*/
|
2011-10-25 08:00:11 +00:00
|
|
|
struct task_group root_task_group;
|
2012-08-07 03:00:13 +00:00
|
|
|
LIST_HEAD(task_groups);
|
2015-12-02 18:41:49 +00:00
|
|
|
|
|
|
|
/* Cacheline aligned slab cache for task_group */
|
|
|
|
static struct kmem_cache *task_group_cache __read_mostly;
|
2008-02-13 14:45:40 +00:00
|
|
|
#endif
|
2008-01-25 20:08:30 +00:00
|
|
|
|
2013-04-23 08:27:41 +00:00
|
|
|
DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
|
2016-05-09 08:38:05 +00:00
|
|
|
DECLARE_PER_CPU(cpumask_var_t, select_idle_mask);
|
2008-01-25 20:08:30 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
void __init sched_init(void)
|
|
|
|
{
|
2019-07-20 01:23:19 +00:00
|
|
|
unsigned long ptr = 0;
|
2019-05-27 06:21:13 +00:00
|
|
|
int i;
|
2008-04-05 01:11:04 +00:00
|
|
|
|
2017-03-05 12:09:07 +00:00
|
|
|
wait_bit_init();
|
mm: remove per-zone hashtable of bitlock waitqueues
The per-zone waitqueues exist because of a scalability issue with the
page waitqueues on some NUMA machines, but it turns out that they hurt
normal loads, and now with the vmalloced stacks they also end up
breaking gfs2 that uses a bit_wait on a stack object:
wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE)
where 'gh' can be a reference to the local variable 'mount_gh' on the
stack of fill_super().
The reason the per-zone hash table breaks for this case is that there is
no "zone" for virtual allocations, and trying to look up the physical
page to get at it will fail (with a BUG_ON()).
It turns out that I actually complained to the mm people about the
per-zone hash table for another reason just a month ago: the zone lookup
also hurts the regular use of "unlock_page()" a lot, because the zone
lookup ends up forcing several unnecessary cache misses and generates
horrible code.
As part of that earlier discussion, we had a much better solution for
the NUMA scalability issue - by just making the page lock have a
separate contention bit, the waitqueue doesn't even have to be looked at
for the normal case.
Peter Zijlstra already has a patch for that, but let's see if anybody
even notices. In the meantime, let's fix the actual gfs2 breakage by
simplifying the bitlock waitqueues and removing the per-zone issue.
Reported-by: Andreas Gruenbacher <agruenba@redhat.com>
Tested-by: Bob Peterson <rpeterso@redhat.com>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Steven Whitehouse <swhiteho@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2016-10-26 17:15:30 +00:00
|
|
|
|
2008-04-05 01:11:04 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2019-07-20 01:23:19 +00:00
|
|
|
ptr += 2 * nr_cpu_ids * sizeof(void **);
|
2008-04-05 01:11:04 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2019-07-20 01:23:19 +00:00
|
|
|
ptr += 2 * nr_cpu_ids * sizeof(void **);
|
2008-04-05 01:11:04 +00:00
|
|
|
#endif
|
2019-07-20 01:23:19 +00:00
|
|
|
if (ptr) {
|
|
|
|
ptr = (unsigned long)kzalloc(ptr, GFP_NOWAIT);
|
2008-04-05 01:11:04 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2011-01-07 07:17:36 +00:00
|
|
|
root_task_group.se = (struct sched_entity **)ptr;
|
2008-04-05 01:11:04 +00:00
|
|
|
ptr += nr_cpu_ids * sizeof(void **);
|
|
|
|
|
2011-01-07 07:17:36 +00:00
|
|
|
root_task_group.cfs_rq = (struct cfs_rq **)ptr;
|
2008-04-05 01:11:04 +00:00
|
|
|
ptr += nr_cpu_ids * sizeof(void **);
|
2008-04-19 17:45:00 +00:00
|
|
|
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
2008-04-05 01:11:04 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2011-01-07 07:17:36 +00:00
|
|
|
root_task_group.rt_se = (struct sched_rt_entity **)ptr;
|
2008-04-05 01:11:04 +00:00
|
|
|
ptr += nr_cpu_ids * sizeof(void **);
|
|
|
|
|
2011-01-07 07:17:36 +00:00
|
|
|
root_task_group.rt_rq = (struct rt_rq **)ptr;
|
2008-04-19 17:45:00 +00:00
|
|
|
ptr += nr_cpu_ids * sizeof(void **);
|
|
|
|
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_RT_GROUP_SCHED */
|
2014-12-18 18:44:30 +00:00
|
|
|
}
|
2009-03-19 04:52:20 +00:00
|
|
|
#ifdef CONFIG_CPUMASK_OFFSTACK
|
2014-12-18 18:44:30 +00:00
|
|
|
for_each_possible_cpu(i) {
|
|
|
|
per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node(
|
|
|
|
cpumask_size(), GFP_KERNEL, cpu_to_node(i));
|
2016-05-09 08:38:05 +00:00
|
|
|
per_cpu(select_idle_mask, i) = (cpumask_var_t)kzalloc_node(
|
|
|
|
cpumask_size(), GFP_KERNEL, cpu_to_node(i));
|
2008-04-05 01:11:04 +00:00
|
|
|
}
|
2014-12-18 18:44:30 +00:00
|
|
|
#endif /* CONFIG_CPUMASK_OFFSTACK */
|
2007-07-09 16:51:59 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
init_rt_bandwidth(&def_rt_bandwidth, global_rt_period(), global_rt_runtime());
|
|
|
|
init_dl_bandwidth(&def_dl_bandwidth, global_rt_period(), global_rt_runtime());
|
sched/deadline: Add bandwidth management for SCHED_DEADLINE tasks
In order of deadline scheduling to be effective and useful, it is
important that some method of having the allocation of the available
CPU bandwidth to tasks and task groups under control.
This is usually called "admission control" and if it is not performed
at all, no guarantee can be given on the actual scheduling of the
-deadline tasks.
Since when RT-throttling has been introduced each task group have a
bandwidth associated to itself, calculated as a certain amount of
runtime over a period. Moreover, to make it possible to manipulate
such bandwidth, readable/writable controls have been added to both
procfs (for system wide settings) and cgroupfs (for per-group
settings).
Therefore, the same interface is being used for controlling the
bandwidth distrubution to -deadline tasks and task groups, i.e.,
new controls but with similar names, equivalent meaning and with
the same usage paradigm are added.
However, more discussion is needed in order to figure out how
we want to manage SCHED_DEADLINE bandwidth at the task group level.
Therefore, this patch adds a less sophisticated, but actually
very sensible, mechanism to ensure that a certain utilization
cap is not overcome per each root_domain (the single rq for !SMP
configurations).
Another main difference between deadline bandwidth management and
RT-throttling is that -deadline tasks have bandwidth on their own
(while -rt ones doesn't!), and thus we don't need an higher level
throttling mechanism to enforce the desired bandwidth.
This patch, therefore:
- adds system wide deadline bandwidth management by means of:
* /proc/sys/kernel/sched_dl_runtime_us,
* /proc/sys/kernel/sched_dl_period_us,
that determine (i.e., runtime / period) the total bandwidth
available on each CPU of each root_domain for -deadline tasks;
- couples the RT and deadline bandwidth management, i.e., enforces
that the sum of how much bandwidth is being devoted to -rt
-deadline tasks to stay below 100%.
This means that, for a root_domain comprising M CPUs, -deadline tasks
can be created until the sum of their bandwidths stay below:
M * (sched_dl_runtime_us / sched_dl_period_us)
It is also possible to disable this bandwidth management logic, and
be thus free of oversubscribing the system up to any arbitrary level.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-12-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:45 +00:00
|
|
|
|
2008-01-25 20:08:18 +00:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
init_defrootdomain();
|
|
|
|
#endif
|
|
|
|
|
2008-04-19 17:44:57 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2011-01-07 07:17:36 +00:00
|
|
|
init_rt_bandwidth(&root_task_group.rt_bandwidth,
|
2008-04-19 17:44:57 +00:00
|
|
|
global_rt_period(), global_rt_runtime());
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_RT_GROUP_SCHED */
|
2008-04-19 17:44:57 +00:00
|
|
|
|
2010-01-20 12:26:18 +00:00
|
|
|
#ifdef CONFIG_CGROUP_SCHED
|
2015-12-02 18:41:49 +00:00
|
|
|
task_group_cache = KMEM_CACHE(task_group, 0);
|
|
|
|
|
2011-01-07 07:17:36 +00:00
|
|
|
list_add(&root_task_group.list, &task_groups);
|
|
|
|
INIT_LIST_HEAD(&root_task_group.children);
|
2011-11-01 21:19:07 +00:00
|
|
|
INIT_LIST_HEAD(&root_task_group.siblings);
|
sched: Add 'autogroup' scheduling feature: automated per session task groups
A recurring complaint from CFS users is that parallel kbuild has
a negative impact on desktop interactivity. This patch
implements an idea from Linus, to automatically create task
groups. Currently, only per session autogroups are implemented,
but the patch leaves the way open for enhancement.
Implementation: each task's signal struct contains an inherited
pointer to a refcounted autogroup struct containing a task group
pointer, the default for all tasks pointing to the
init_task_group. When a task calls setsid(), a new task group
is created, the process is moved into the new task group, and a
reference to the preveious task group is dropped. Child
processes inherit this task group thereafter, and increase it's
refcount. When the last thread of a process exits, the
process's reference is dropped, such that when the last process
referencing an autogroup exits, the autogroup is destroyed.
At runqueue selection time, IFF a task has no cgroup assignment,
its current autogroup is used.
Autogroup bandwidth is controllable via setting it's nice level
through the proc filesystem:
cat /proc/<pid>/autogroup
Displays the task's group and the group's nice level.
echo <nice level> > /proc/<pid>/autogroup
Sets the task group's shares to the weight of nice <level> task.
Setting nice level is rate limited for !admin users due to the
abuse risk of task group locking.
The feature is enabled from boot by default if
CONFIG_SCHED_AUTOGROUP=y is selected, but can be disabled via
the boot option noautogroup, and can also be turned on/off on
the fly via:
echo [01] > /proc/sys/kernel/sched_autogroup_enabled
... which will automatically move tasks to/from the root task group.
Signed-off-by: Mike Galbraith <efault@gmx.de>
Acked-by: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Markus Trippelsdorf <markus@trippelsdorf.de>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Paul Turner <pjt@google.com>
Cc: Oleg Nesterov <oleg@redhat.com>
[ Removed the task_group_path() debug code, and fixed !EVENTFD build failure. ]
Signed-off-by: Ingo Molnar <mingo@elte.hu>
LKML-Reference: <1290281700.28711.9.camel@maggy.simson.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2010-11-30 13:18:03 +00:00
|
|
|
autogroup_init(&init_task);
|
2010-01-20 12:26:18 +00:00
|
|
|
#endif /* CONFIG_CGROUP_SCHED */
|
2008-01-25 20:08:30 +00:00
|
|
|
|
2006-03-28 09:56:37 +00:00
|
|
|
for_each_possible_cpu(i) {
|
2006-07-03 07:25:42 +00:00
|
|
|
struct rq *rq;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
|
|
|
rq = cpu_rq(i);
|
2009-11-17 13:28:38 +00:00
|
|
|
raw_spin_lock_init(&rq->lock);
|
2005-06-25 21:57:13 +00:00
|
|
|
rq->nr_running = 0;
|
2009-04-11 08:43:41 +00:00
|
|
|
rq->calc_load_active = 0;
|
|
|
|
rq->calc_load_update = jiffies + LOAD_FREQ;
|
2011-07-14 16:32:43 +00:00
|
|
|
init_cfs_rq(&rq->cfs);
|
2015-03-03 11:50:27 +00:00
|
|
|
init_rt_rq(&rq->rt);
|
|
|
|
init_dl_rq(&rq->dl);
|
2007-07-09 16:51:59 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2011-10-25 08:00:11 +00:00
|
|
|
root_task_group.shares = ROOT_TASK_GROUP_LOAD;
|
2008-01-25 20:08:30 +00:00
|
|
|
INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
|
2016-11-08 09:53:43 +00:00
|
|
|
rq->tmp_alone_branch = &rq->leaf_cfs_rq_list;
|
2008-04-19 17:44:59 +00:00
|
|
|
/*
|
2017-02-01 10:46:42 +00:00
|
|
|
* How much CPU bandwidth does root_task_group get?
|
2008-04-19 17:44:59 +00:00
|
|
|
*
|
|
|
|
* In case of task-groups formed thr' the cgroup filesystem, it
|
2017-02-01 10:46:42 +00:00
|
|
|
* gets 100% of the CPU resources in the system. This overall
|
|
|
|
* system CPU resource is divided among the tasks of
|
2011-01-07 07:17:36 +00:00
|
|
|
* root_task_group and its child task-groups in a fair manner,
|
2008-04-19 17:44:59 +00:00
|
|
|
* based on each entity's (task or task-group's) weight
|
|
|
|
* (se->load.weight).
|
|
|
|
*
|
2011-01-07 07:17:36 +00:00
|
|
|
* In other words, if root_task_group has 10 tasks of weight
|
2008-04-19 17:44:59 +00:00
|
|
|
* 1024) and two child groups A0 and A1 (of weight 1024 each),
|
2017-02-01 10:46:42 +00:00
|
|
|
* then A0's share of the CPU resource is:
|
2008-04-19 17:44:59 +00:00
|
|
|
*
|
2009-05-04 17:13:30 +00:00
|
|
|
* A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33%
|
2008-04-19 17:44:59 +00:00
|
|
|
*
|
2011-01-07 07:17:36 +00:00
|
|
|
* We achieve this by letting root_task_group's tasks sit
|
|
|
|
* directly in rq->cfs (i.e root_task_group->se[] = NULL).
|
2008-04-19 17:44:59 +00:00
|
|
|
*/
|
2011-07-21 16:43:28 +00:00
|
|
|
init_cfs_bandwidth(&root_task_group.cfs_bandwidth);
|
2011-01-07 07:17:36 +00:00
|
|
|
init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
|
2008-04-19 17:44:59 +00:00
|
|
|
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
|
|
|
|
|
|
|
rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2011-01-07 07:17:36 +00:00
|
|
|
init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
|
2007-07-09 16:51:59 +00:00
|
|
|
#endif
|
2005-04-16 22:20:36 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2005-06-25 21:57:24 +00:00
|
|
|
rq->sd = NULL;
|
2008-01-25 20:08:18 +00:00
|
|
|
rq->rd = NULL;
|
2015-02-27 15:54:09 +00:00
|
|
|
rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE;
|
2015-06-11 12:46:37 +00:00
|
|
|
rq->balance_callback = NULL;
|
2005-04-16 22:20:36 +00:00
|
|
|
rq->active_balance = 0;
|
2007-07-09 16:51:59 +00:00
|
|
|
rq->next_balance = jiffies;
|
2005-04-16 22:20:36 +00:00
|
|
|
rq->push_cpu = 0;
|
2006-09-26 06:30:51 +00:00
|
|
|
rq->cpu = i;
|
2008-06-04 19:04:05 +00:00
|
|
|
rq->online = 0;
|
2009-11-10 02:50:02 +00:00
|
|
|
rq->idle_stamp = 0;
|
|
|
|
rq->avg_idle = 2*sysctl_sched_migration_cost;
|
2013-09-13 18:26:52 +00:00
|
|
|
rq->max_idle_balance_cost = sysctl_sched_migration_cost;
|
2012-02-20 20:49:09 +00:00
|
|
|
|
|
|
|
INIT_LIST_HEAD(&rq->cfs_tasks);
|
|
|
|
|
2008-01-25 20:08:26 +00:00
|
|
|
rq_attach_root(rq, &def_root_domain);
|
2011-08-10 21:21:01 +00:00
|
|
|
#ifdef CONFIG_NO_HZ_COMMON
|
2017-12-21 10:20:23 +00:00
|
|
|
rq->last_blocked_load_update_tick = jiffies;
|
2017-12-21 09:01:24 +00:00
|
|
|
atomic_set(&rq->nohz_flags, 0);
|
2010-05-22 00:09:41 +00:00
|
|
|
#endif
|
2016-04-19 15:36:51 +00:00
|
|
|
#endif /* CONFIG_SMP */
|
2018-02-21 04:17:23 +00:00
|
|
|
hrtick_rq_init(rq);
|
2005-04-16 22:20:36 +00:00
|
|
|
atomic_set(&rq->nr_iowait, 0);
|
|
|
|
}
|
|
|
|
|
2017-05-17 09:50:45 +00:00
|
|
|
set_load_weight(&init_task, false);
|
2006-07-30 10:03:52 +00:00
|
|
|
|
2005-04-16 22:20:36 +00:00
|
|
|
/*
|
|
|
|
* The boot idle thread does lazy MMU switching as well:
|
|
|
|
*/
|
2017-02-27 22:30:07 +00:00
|
|
|
mmgrab(&init_mm);
|
2005-04-16 22:20:36 +00:00
|
|
|
enter_lazy_tlb(&init_mm, current);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make us the idle thread. Technically, schedule() should not be
|
|
|
|
* called from this thread, however somewhere below it might be,
|
|
|
|
* but because we are the idle thread, we just pick up running again
|
|
|
|
* when this runqueue becomes "idle".
|
|
|
|
*/
|
|
|
|
init_idle(current, smp_processor_id());
|
2009-04-11 08:43:41 +00:00
|
|
|
|
|
|
|
calc_load_update = jiffies + LOAD_FREQ;
|
|
|
|
|
2008-11-24 23:27:51 +00:00
|
|
|
#ifdef CONFIG_SMP
|
2012-04-20 13:05:45 +00:00
|
|
|
idle_thread_set_boot_cpu();
|
2011-10-25 08:00:11 +00:00
|
|
|
#endif
|
|
|
|
init_sched_fair_class();
|
2008-11-24 16:05:04 +00:00
|
|
|
|
2016-06-07 19:43:16 +00:00
|
|
|
init_schedstats();
|
|
|
|
|
psi: pressure stall information for CPU, memory, and IO
When systems are overcommitted and resources become contended, it's hard
to tell exactly the impact this has on workload productivity, or how close
the system is to lockups and OOM kills. In particular, when machines work
multiple jobs concurrently, the impact of overcommit in terms of latency
and throughput on the individual job can be enormous.
In order to maximize hardware utilization without sacrificing individual
job health or risk complete machine lockups, this patch implements a way
to quantify resource pressure in the system.
A kernel built with CONFIG_PSI=y creates files in /proc/pressure/ that
expose the percentage of time the system is stalled on CPU, memory, or IO,
respectively. Stall states are aggregate versions of the per-task delay
accounting delays:
cpu: some tasks are runnable but not executing on a CPU
memory: tasks are reclaiming, or waiting for swapin or thrashing cache
io: tasks are waiting for io completions
These percentages of walltime can be thought of as pressure percentages,
and they give a general sense of system health and productivity loss
incurred by resource overcommit. They can also indicate when the system
is approaching lockup scenarios and OOMs.
To do this, psi keeps track of the task states associated with each CPU
and samples the time they spend in stall states. Every 2 seconds, the
samples are averaged across CPUs - weighted by the CPUs' non-idle time to
eliminate artifacts from unused CPUs - and translated into percentages of
walltime. A running average of those percentages is maintained over 10s,
1m, and 5m periods (similar to the loadaverage).
[hannes@cmpxchg.org: doc fixlet, per Randy]
Link: http://lkml.kernel.org/r/20180828205625.GA14030@cmpxchg.org
[hannes@cmpxchg.org: code optimization]
Link: http://lkml.kernel.org/r/20180907175015.GA8479@cmpxchg.org
[hannes@cmpxchg.org: rename psi_clock() to psi_update_work(), per Peter]
Link: http://lkml.kernel.org/r/20180907145404.GB11088@cmpxchg.org
[hannes@cmpxchg.org: fix build]
Link: http://lkml.kernel.org/r/20180913014222.GA2370@cmpxchg.org
Link: http://lkml.kernel.org/r/20180828172258.3185-9-hannes@cmpxchg.org
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Daniel Drake <drake@endlessm.com>
Tested-by: Suren Baghdasaryan <surenb@google.com>
Cc: Christopher Lameter <cl@linux.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Johannes Weiner <jweiner@fb.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Enderborg <peter.enderborg@sony.com>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Shakeel Butt <shakeelb@google.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Vinayak Menon <vinmenon@codeaurora.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-26 22:06:27 +00:00
|
|
|
psi_init();
|
|
|
|
|
2019-06-21 08:42:02 +00:00
|
|
|
init_uclamp();
|
|
|
|
|
2008-02-13 13:02:36 +00:00
|
|
|
scheduler_running = 1;
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
2011-06-08 17:31:56 +00:00
|
|
|
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
|
2009-07-16 13:44:29 +00:00
|
|
|
static inline int preempt_count_equals(int preempt_offset)
|
|
|
|
{
|
2015-09-28 16:11:45 +00:00
|
|
|
int nested = preempt_count() + rcu_preempt_depth();
|
2009-07-16 13:44:29 +00:00
|
|
|
|
2011-01-25 21:52:22 +00:00
|
|
|
return (nested == preempt_offset);
|
2009-07-16 13:44:29 +00:00
|
|
|
}
|
|
|
|
|
2009-12-23 10:08:18 +00:00
|
|
|
void __might_sleep(const char *file, int line, int preempt_offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2014-09-24 08:18:55 +00:00
|
|
|
/*
|
|
|
|
* Blocking primitives will set (and therefore destroy) current->state,
|
|
|
|
* since we will exit with TASK_RUNNING make sure we enter with it,
|
|
|
|
* otherwise we will destroy state.
|
|
|
|
*/
|
sched: don't cause task state changes in nested sleep debugging
Commit 8eb23b9f35aa ("sched: Debug nested sleeps") added code to report
on nested sleep conditions, which we generally want to avoid because the
inner sleeping operation can re-set the thread state to TASK_RUNNING,
but that will then cause the outer sleep loop not actually sleep when it
calls schedule.
However, that's actually valid traditional behavior, with the inner
sleep being some fairly rare case (like taking a sleeping lock that
normally doesn't actually need to sleep).
And the debug code would actually change the state of the task to
TASK_RUNNING internally, which makes that kind of traditional and
working code not work at all, because now the nested sleep doesn't just
sometimes cause the outer one to not block, but will cause it to happen
every time.
In particular, it will cause the cardbus kernel daemon (pccardd) to
basically busy-loop doing scheduling, converting a laptop into a heater,
as reported by Bruno Prémont. But there may be other legacy uses of
that nested sleep model in other drivers that are also likely to never
get converted to the new model.
This fixes both cases:
- don't set TASK_RUNNING when the nested condition happens (note: even
if WARN_ONCE() only _warns_ once, the return value isn't whether the
warning happened, but whether the condition for the warning was true.
So despite the warning only happening once, the "if (WARN_ON(..))"
would trigger for every nested sleep.
- in the cases where we knowingly disable the warning by using
"sched_annotate_sleep()", don't change the task state (that is used
for all core scheduling decisions), instead use '->task_state_change'
that is used for the debugging decision itself.
(Credit for the second part of the fix goes to Oleg Nesterov: "Can't we
avoid this subtle change in behaviour DEBUG_ATOMIC_SLEEP adds?" with the
suggested change to use 'task_state_change' as part of the test)
Reported-and-bisected-by: Bruno Prémont <bonbons@linux-vserver.org>
Tested-by: Rafael J Wysocki <rjw@rjwysocki.net>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Cc: Ilya Dryomov <ilya.dryomov@inktank.com>,
Cc: Mike Galbraith <umgwanakikbuti@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Hurley <peter@hurleysoftware.com>,
Cc: Davidlohr Bueso <dave@stgolabs.net>,
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-02-01 20:23:32 +00:00
|
|
|
WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change,
|
2014-09-24 08:18:55 +00:00
|
|
|
"do not call blocking ops when !TASK_RUNNING; "
|
|
|
|
"state=%lx set at [<%p>] %pS\n",
|
|
|
|
current->state,
|
|
|
|
(void *)current->task_state_change,
|
sched: don't cause task state changes in nested sleep debugging
Commit 8eb23b9f35aa ("sched: Debug nested sleeps") added code to report
on nested sleep conditions, which we generally want to avoid because the
inner sleeping operation can re-set the thread state to TASK_RUNNING,
but that will then cause the outer sleep loop not actually sleep when it
calls schedule.
However, that's actually valid traditional behavior, with the inner
sleep being some fairly rare case (like taking a sleeping lock that
normally doesn't actually need to sleep).
And the debug code would actually change the state of the task to
TASK_RUNNING internally, which makes that kind of traditional and
working code not work at all, because now the nested sleep doesn't just
sometimes cause the outer one to not block, but will cause it to happen
every time.
In particular, it will cause the cardbus kernel daemon (pccardd) to
basically busy-loop doing scheduling, converting a laptop into a heater,
as reported by Bruno Prémont. But there may be other legacy uses of
that nested sleep model in other drivers that are also likely to never
get converted to the new model.
This fixes both cases:
- don't set TASK_RUNNING when the nested condition happens (note: even
if WARN_ONCE() only _warns_ once, the return value isn't whether the
warning happened, but whether the condition for the warning was true.
So despite the warning only happening once, the "if (WARN_ON(..))"
would trigger for every nested sleep.
- in the cases where we knowingly disable the warning by using
"sched_annotate_sleep()", don't change the task state (that is used
for all core scheduling decisions), instead use '->task_state_change'
that is used for the debugging decision itself.
(Credit for the second part of the fix goes to Oleg Nesterov: "Can't we
avoid this subtle change in behaviour DEBUG_ATOMIC_SLEEP adds?" with the
suggested change to use 'task_state_change' as part of the test)
Reported-and-bisected-by: Bruno Prémont <bonbons@linux-vserver.org>
Tested-by: Rafael J Wysocki <rjw@rjwysocki.net>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Cc: Ilya Dryomov <ilya.dryomov@inktank.com>,
Cc: Mike Galbraith <umgwanakikbuti@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Hurley <peter@hurleysoftware.com>,
Cc: Davidlohr Bueso <dave@stgolabs.net>,
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2015-02-01 20:23:32 +00:00
|
|
|
(void *)current->task_state_change);
|
2014-09-24 08:18:55 +00:00
|
|
|
|
2014-09-24 08:18:56 +00:00
|
|
|
___might_sleep(file, line, preempt_offset);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(__might_sleep);
|
|
|
|
|
|
|
|
void ___might_sleep(const char *file, int line, int preempt_offset)
|
2005-04-16 22:20:36 +00:00
|
|
|
{
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Ratelimiting timestamp: */
|
|
|
|
static unsigned long prev_jiffy;
|
|
|
|
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
unsigned long preempt_disable_ip;
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* WARN_ON_ONCE() by default, no rate limit required: */
|
|
|
|
rcu_sleep_check();
|
|
|
|
|
2014-02-07 19:58:38 +00:00
|
|
|
if ((preempt_count_equals(preempt_offset) && !irqs_disabled() &&
|
2019-08-26 20:14:23 +00:00
|
|
|
!is_idle_task(current) && !current->non_block_count) ||
|
2017-05-16 18:42:48 +00:00
|
|
|
system_state == SYSTEM_BOOTING || system_state > SYSTEM_RUNNING ||
|
|
|
|
oops_in_progress)
|
2008-08-28 09:34:43 +00:00
|
|
|
return;
|
2017-05-16 18:42:48 +00:00
|
|
|
|
2008-08-28 09:34:43 +00:00
|
|
|
if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
|
|
|
|
return;
|
|
|
|
prev_jiffy = jiffies;
|
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Save this before calling printk(), since that will clobber it: */
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
preempt_disable_ip = get_preempt_disable_ip(current);
|
|
|
|
|
2009-12-20 13:23:57 +00:00
|
|
|
printk(KERN_ERR
|
|
|
|
"BUG: sleeping function called from invalid context at %s:%d\n",
|
|
|
|
file, line);
|
|
|
|
printk(KERN_ERR
|
2019-08-26 20:14:23 +00:00
|
|
|
"in_atomic(): %d, irqs_disabled(): %d, non_block: %d, pid: %d, name: %s\n",
|
|
|
|
in_atomic(), irqs_disabled(), current->non_block_count,
|
2009-12-20 13:23:57 +00:00
|
|
|
current->pid, current->comm);
|
2008-08-28 09:34:43 +00:00
|
|
|
|
2014-12-16 22:25:28 +00:00
|
|
|
if (task_stack_end_corrupted(current))
|
|
|
|
printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
|
|
|
|
|
2008-08-28 09:34:43 +00:00
|
|
|
debug_show_held_locks(current);
|
|
|
|
if (irqs_disabled())
|
|
|
|
print_irqtrace_events(current);
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
if (IS_ENABLED(CONFIG_DEBUG_PREEMPT)
|
|
|
|
&& !preempt_count_equals(preempt_offset)) {
|
2014-02-07 19:58:39 +00:00
|
|
|
pr_err("Preemption disabled at:");
|
sched/debug: Make the "Preemption disabled at ..." message more useful
This message is currently really useless since it always prints a value
that comes from the printk() we just did, e.g.:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
BUG: sleeping function called from invalid context at include/linux/freezer.h:56
in_atomic(): 0, irqs_disabled(): 0, pid: 31996, name: trinity-c1
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
Here, both down_trylock() and console_unlock() is somewhere in the
printk() path.
We should save the value before calling printk() and use the saved value
instead. That immediately reveals the offending callsite:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 14971, name: trinity-c2
Preemption disabled at:[<ffffffff819bcd46>] rhashtable_walk_start+0x46/0x150
Bug report:
http://marc.info/?l=linux-netdev&m=146925979821849&w=2
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-23 07:46:39 +00:00
|
|
|
print_ip_sym(preempt_disable_ip);
|
2014-02-07 19:58:39 +00:00
|
|
|
pr_cont("\n");
|
|
|
|
}
|
2008-08-28 09:34:43 +00:00
|
|
|
dump_stack();
|
sched/debug: Add taint on "BUG: Sleeping function called from invalid context"
Seeing this, it occurs to me that we should probably add a taint here:
BUG: sleeping function called from invalid context at mm/slab.h:388
in_atomic(): 0, irqs_disabled(): 0, pid: 32211, name: trinity-c3
Preemption disabled at:[<ffffffff811aaa37>] console_unlock+0x2f7/0x930
CPU: 3 PID: 32211 Comm: trinity-c3 Not tainted 4.7.0-rc7+ #19
^^^^^^^^^^^
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
0000000000000000 ffff8800b8a17160 ffffffff81971441 ffff88011a3c4c80
ffff88011a3c4c80 ffff8800b8a17198 ffffffff81158067 0000000000000de6
ffff88011a3c4c80 ffffffff8390e07c 0000000000000184 0000000000000000
Call Trace:
[...]
BUG: sleeping function called from invalid context at arch/x86/mm/fault.c:1309
in_atomic(): 0, irqs_disabled(): 0, pid: 32211, name: trinity-c3
Preemption disabled at:[<ffffffff8119db33>] down_trylock+0x13/0x80
CPU: 3 PID: 32211 Comm: trinity-c3 Not tainted 4.7.0-rc7+ #19
^^^^^^^^^^^
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014
0000000000000000 ffff8800b8a17e08 ffffffff81971441 ffff88011a3c4c80
ffff88011a3c4c80 ffff8800b8a17e40 ffffffff81158067 0000000000000000
ffff88011a3c4c80 ffffffff83437b20 000000000000051d 0000000000000000
Call Trace:
[...]
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rusty Russel <rusty@rustcorp.com.au>
Link: http://lkml.kernel.org/r/1469216762-19626-1-git-send-email-vegard.nossum@oracle.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-22 19:46:02 +00:00
|
|
|
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
2014-09-24 08:18:56 +00:00
|
|
|
EXPORT_SYMBOL(___might_sleep);
|
2019-01-29 01:21:52 +00:00
|
|
|
|
|
|
|
void __cant_sleep(const char *file, int line, int preempt_offset)
|
|
|
|
{
|
|
|
|
static unsigned long prev_jiffy;
|
|
|
|
|
|
|
|
if (irqs_disabled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (preempt_count() > preempt_offset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy)
|
|
|
|
return;
|
|
|
|
prev_jiffy = jiffies;
|
|
|
|
|
|
|
|
printk(KERN_ERR "BUG: assuming atomic context at %s:%d\n", file, line);
|
|
|
|
printk(KERN_ERR "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n",
|
|
|
|
in_atomic(), irqs_disabled(),
|
|
|
|
current->pid, current->comm);
|
|
|
|
|
|
|
|
debug_show_held_locks(current);
|
|
|
|
dump_stack();
|
|
|
|
add_taint(TAINT_WARN, LOCKDEP_STILL_OK);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__cant_sleep);
|
2005-04-16 22:20:36 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_MAGIC_SYSRQ
|
2015-06-11 12:46:38 +00:00
|
|
|
void normalize_rt_tasks(void)
|
2007-10-15 15:00:15 +00:00
|
|
|
{
|
2015-06-11 12:46:38 +00:00
|
|
|
struct task_struct *g, *p;
|
sched: Add new scheduler syscalls to support an extended scheduling parameters ABI
Add the syscalls needed for supporting scheduling algorithms
with extended scheduling parameters (e.g., SCHED_DEADLINE).
In general, it makes possible to specify a periodic/sporadic task,
that executes for a given amount of runtime at each instance, and is
scheduled according to the urgency of their own timing constraints,
i.e.:
- a (maximum/typical) instance execution time,
- a minimum interval between consecutive instances,
- a time constraint by which each instance must be completed.
Thus, both the data structure that holds the scheduling parameters of
the tasks and the system calls dealing with it must be extended.
Unfortunately, modifying the existing struct sched_param would break
the ABI and result in potentially serious compatibility issues with
legacy binaries.
For these reasons, this patch:
- defines the new struct sched_attr, containing all the fields
that are necessary for specifying a task in the computational
model described above;
- defines and implements the new scheduling related syscalls that
manipulate it, i.e., sched_setattr() and sched_getattr().
Syscalls are introduced for x86 (32 and 64 bits) and ARM only, as a
proof of concept and for developing and testing purposes. Making them
available on other architectures is straightforward.
Since no "user" for these new parameters is introduced in this patch,
the implementation of the new system calls is just identical to their
already existing counterpart. Future patches that implement scheduling
policies able to exploit the new data structure must also take care of
modifying the sched_*attr() calls accordingly with their own purposes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
[ Rewrote to use sched_attr. ]
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
[ Removed sched_setscheduler2() for now. ]
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-3-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-07 13:43:36 +00:00
|
|
|
struct sched_attr attr = {
|
|
|
|
.sched_policy = SCHED_NORMAL,
|
|
|
|
};
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2014-09-21 19:33:38 +00:00
|
|
|
read_lock(&tasklist_lock);
|
2014-08-13 19:19:53 +00:00
|
|
|
for_each_process_thread(g, p) {
|
2007-10-15 15:00:18 +00:00
|
|
|
/*
|
|
|
|
* Only normalize user tasks:
|
|
|
|
*/
|
2014-09-21 19:33:38 +00:00
|
|
|
if (p->flags & PF_KTHREAD)
|
2007-10-15 15:00:18 +00:00
|
|
|
continue;
|
|
|
|
|
2016-06-17 17:43:26 +00:00
|
|
|
p->se.exec_start = 0;
|
|
|
|
schedstat_set(p->se.statistics.wait_start, 0);
|
|
|
|
schedstat_set(p->se.statistics.sleep_start, 0);
|
|
|
|
schedstat_set(p->se.statistics.block_start, 0);
|
2007-07-09 16:51:59 +00:00
|
|
|
|
sched/deadline: Add SCHED_DEADLINE structures & implementation
Introduces the data structures, constants and symbols needed for
SCHED_DEADLINE implementation.
Core data structure of SCHED_DEADLINE are defined, along with their
initializers. Hooks for checking if a task belong to the new policy
are also added where they are needed.
Adds a scheduling class, in sched/dl.c and a new policy called
SCHED_DEADLINE. It is an implementation of the Earliest Deadline
First (EDF) scheduling algorithm, augmented with a mechanism (called
Constant Bandwidth Server, CBS) that makes it possible to isolate
the behaviour of tasks between each other.
The typical -deadline task will be made up of a computation phase
(instance) which is activated on a periodic or sporadic fashion. The
expected (maximum) duration of such computation is called the task's
runtime; the time interval by which each instance need to be completed
is called the task's relative deadline. The task's absolute deadline
is dynamically calculated as the time instant a task (better, an
instance) activates plus the relative deadline.
The EDF algorithms selects the task with the smallest absolute
deadline as the one to be executed first, while the CBS ensures each
task to run for at most its runtime every (relative) deadline
length time interval, avoiding any interference between different
tasks (bandwidth isolation).
Thanks to this feature, also tasks that do not strictly comply with
the computational model sketched above can effectively use the new
policy.
To summarize, this patch:
- introduces the data structures, constants and symbols needed;
- implements the core logic of the scheduling algorithm in the new
scheduling class file;
- provides all the glue code between the new scheduling class and
the core scheduler and refines the interactions between sched/dl
and the other existing scheduling classes.
Signed-off-by: Dario Faggioli <raistlin@linux.it>
Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
Signed-off-by: Fabio Checconi <fchecconi@gmail.com>
Signed-off-by: Juri Lelli <juri.lelli@gmail.com>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1383831828-15501-4-git-send-email-juri.lelli@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2013-11-28 10:14:43 +00:00
|
|
|
if (!dl_task(p) && !rt_task(p)) {
|
2007-07-09 16:51:59 +00:00
|
|
|
/*
|
|
|
|
* Renice negative nice level userspace
|
|
|
|
* tasks back to 0:
|
|
|
|
*/
|
2014-09-21 19:33:38 +00:00
|
|
|
if (task_nice(p) < 0)
|
2007-07-09 16:51:59 +00:00
|
|
|
set_user_nice(p, 0);
|
2005-04-16 22:20:36 +00:00
|
|
|
continue;
|
2007-07-09 16:51:59 +00:00
|
|
|
}
|
2005-04-16 22:20:36 +00:00
|
|
|
|
2015-06-11 12:46:38 +00:00
|
|
|
__sched_setscheduler(p, &attr, false, false);
|
2014-08-13 19:19:53 +00:00
|
|
|
}
|
2014-09-21 19:33:38 +00:00
|
|
|
read_unlock(&tasklist_lock);
|
2005-04-16 22:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* CONFIG_MAGIC_SYSRQ */
|
2005-09-12 14:59:21 +00:00
|
|
|
|
2010-05-21 02:04:21 +00:00
|
|
|
#if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB)
|
2005-09-12 14:59:21 +00:00
|
|
|
/*
|
2010-05-21 02:04:21 +00:00
|
|
|
* These functions are only useful for the IA64 MCA handling, or kdb.
|
2005-09-12 14:59:21 +00:00
|
|
|
*
|
|
|
|
* They can only be called when the whole system has been
|
|
|
|
* stopped - every CPU needs to be quiescent, and no scheduling
|
|
|
|
* activity can take place. Using them for anything else would
|
|
|
|
* be a serious bug, and as a result, they aren't even visible
|
|
|
|
* under any other configuration.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2017-02-01 10:46:42 +00:00
|
|
|
* curr_task - return the current task for a given CPU.
|
2005-09-12 14:59:21 +00:00
|
|
|
* @cpu: the processor in question.
|
|
|
|
*
|
|
|
|
* ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
|
2013-07-12 18:45:47 +00:00
|
|
|
*
|
|
|
|
* Return: The current task for @cpu.
|
2005-09-12 14:59:21 +00:00
|
|
|
*/
|
2006-07-03 07:25:41 +00:00
|
|
|
struct task_struct *curr_task(int cpu)
|
2005-09-12 14:59:21 +00:00
|
|
|
{
|
|
|
|
return cpu_curr(cpu);
|
|
|
|
}
|
|
|
|
|
2010-05-21 02:04:21 +00:00
|
|
|
#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */
|
|
|
|
|
|
|
|
#ifdef CONFIG_IA64
|
2005-09-12 14:59:21 +00:00
|
|
|
/**
|
2019-05-29 20:36:38 +00:00
|
|
|
* ia64_set_curr_task - set the current task for a given CPU.
|
2005-09-12 14:59:21 +00:00
|
|
|
* @cpu: the processor in question.
|
|
|
|
* @p: the task pointer to set.
|
|
|
|
*
|
|
|
|
* Description: This function must only be used when non-maskable interrupts
|
2007-12-05 14:46:09 +00:00
|
|
|
* are serviced on a separate stack. It allows the architecture to switch the
|
2017-02-01 10:46:42 +00:00
|
|
|
* notion of the current task on a CPU in a non-blocking manner. This function
|
2005-09-12 14:59:21 +00:00
|
|
|
* must be called with all CPU's synchronized, and interrupts disabled, the
|
|
|
|
* and caller must save the original value of the current task (see
|
|
|
|
* curr_task() above) and restore that value before reenabling interrupts and
|
|
|
|
* re-starting the system.
|
|
|
|
*
|
|
|
|
* ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
|
|
|
|
*/
|
2016-09-20 18:29:40 +00:00
|
|
|
void ia64_set_curr_task(int cpu, struct task_struct *p)
|
2005-09-12 14:59:21 +00:00
|
|
|
{
|
|
|
|
cpu_curr(cpu) = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2007-10-15 15:00:07 +00:00
|
|
|
|
2010-01-20 12:26:18 +00:00
|
|
|
#ifdef CONFIG_CGROUP_SCHED
|
2011-10-25 08:00:11 +00:00
|
|
|
/* task_group_lock serializes the addition/removal of task groups */
|
|
|
|
static DEFINE_SPINLOCK(task_group_lock);
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
static inline void alloc_uclamp_sched_group(struct task_group *tg,
|
|
|
|
struct task_group *parent)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id) {
|
|
|
|
uclamp_se_set(&tg->uclamp_req[clamp_id],
|
|
|
|
uclamp_none(clamp_id), false);
|
2019-08-22 13:28:07 +00:00
|
|
|
tg->uclamp[clamp_id] = parent->uclamp[clamp_id];
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2016-03-16 15:22:45 +00:00
|
|
|
static void sched_free_group(struct task_group *tg)
|
2008-02-13 14:45:40 +00:00
|
|
|
{
|
|
|
|
free_fair_sched_group(tg);
|
|
|
|
free_rt_sched_group(tg);
|
2011-01-05 10:11:25 +00:00
|
|
|
autogroup_free(tg);
|
2015-12-02 18:41:49 +00:00
|
|
|
kmem_cache_free(task_group_cache, tg);
|
2008-02-13 14:45:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate runqueue etc for a new task group */
|
2008-04-19 17:44:59 +00:00
|
|
|
struct task_group *sched_create_group(struct task_group *parent)
|
2008-02-13 14:45:40 +00:00
|
|
|
{
|
|
|
|
struct task_group *tg;
|
|
|
|
|
2015-12-02 18:41:49 +00:00
|
|
|
tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO);
|
2008-02-13 14:45:40 +00:00
|
|
|
if (!tg)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
2008-04-19 17:44:59 +00:00
|
|
|
if (!alloc_fair_sched_group(tg, parent))
|
2008-02-13 14:45:40 +00:00
|
|
|
goto err;
|
|
|
|
|
2008-04-19 17:44:59 +00:00
|
|
|
if (!alloc_rt_sched_group(tg, parent))
|
2008-02-13 14:45:40 +00:00
|
|
|
goto err;
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
alloc_uclamp_sched_group(tg, parent);
|
|
|
|
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
return tg;
|
|
|
|
|
|
|
|
err:
|
2016-03-16 15:22:45 +00:00
|
|
|
sched_free_group(tg);
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
}
|
|
|
|
|
|
|
|
void sched_online_group(struct task_group *tg, struct task_group *parent)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
2008-02-13 14:45:39 +00:00
|
|
|
spin_lock_irqsave(&task_group_lock, flags);
|
2008-01-25 20:08:30 +00:00
|
|
|
list_add_rcu(&tg->list, &task_groups);
|
2008-04-19 17:45:00 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Root should already exist: */
|
|
|
|
WARN_ON(!parent);
|
2008-04-19 17:45:00 +00:00
|
|
|
|
|
|
|
tg->parent = parent;
|
|
|
|
INIT_LIST_HEAD(&tg->children);
|
2030-08-14 07:56:40 +00:00
|
|
|
list_add_rcu(&tg->siblings, &parent->children);
|
2008-02-13 14:45:39 +00:00
|
|
|
spin_unlock_irqrestore(&task_group_lock, flags);
|
2016-06-22 12:58:02 +00:00
|
|
|
|
|
|
|
online_fair_sched_group(tg);
|
2007-10-15 15:00:07 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 15:00:09 +00:00
|
|
|
/* rcu callback to free various structures associated with a task group */
|
2016-03-16 15:22:45 +00:00
|
|
|
static void sched_free_group_rcu(struct rcu_head *rhp)
|
2007-10-15 15:00:07 +00:00
|
|
|
{
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Now it should be safe to free those cfs_rqs: */
|
2016-03-16 15:22:45 +00:00
|
|
|
sched_free_group(container_of(rhp, struct task_group, rcu));
|
2007-10-15 15:00:07 +00:00
|
|
|
}
|
|
|
|
|
2007-10-15 15:00:14 +00:00
|
|
|
void sched_destroy_group(struct task_group *tg)
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
{
|
2017-02-01 10:46:42 +00:00
|
|
|
/* Wait for possible concurrent references to cfs_rqs complete: */
|
2016-03-16 15:22:45 +00:00
|
|
|
call_rcu(&tg->rcu, sched_free_group_rcu);
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void sched_offline_group(struct task_group *tg)
|
2007-10-15 15:00:07 +00:00
|
|
|
{
|
2008-02-13 14:45:39 +00:00
|
|
|
unsigned long flags;
|
2007-10-15 15:00:07 +00:00
|
|
|
|
2017-02-01 10:46:42 +00:00
|
|
|
/* End participation in shares distribution: */
|
2016-01-21 21:24:16 +00:00
|
|
|
unregister_fair_sched_group(tg);
|
2010-11-15 23:47:01 +00:00
|
|
|
|
|
|
|
spin_lock_irqsave(&task_group_lock, flags);
|
2008-01-25 20:08:30 +00:00
|
|
|
list_del_rcu(&tg->list);
|
2008-04-19 17:45:00 +00:00
|
|
|
list_del_rcu(&tg->siblings);
|
2008-02-13 14:45:39 +00:00
|
|
|
spin_unlock_irqrestore(&task_group_lock, flags);
|
2007-10-15 15:00:07 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 11:38:55 +00:00
|
|
|
static void sched_change_group(struct task_struct *tsk, int type)
|
2007-10-15 15:00:07 +00:00
|
|
|
{
|
2012-06-22 11:36:05 +00:00
|
|
|
struct task_group *tg;
|
2007-10-15 15:00:07 +00:00
|
|
|
|
2014-10-28 05:24:34 +00:00
|
|
|
/*
|
|
|
|
* All callers are synchronized by task_rq_lock(); we do not use RCU
|
|
|
|
* which is pointless here. Thus, we pass "true" to task_css_check()
|
|
|
|
* to prevent lockdep warnings.
|
|
|
|
*/
|
|
|
|
tg = container_of(task_css_check(tsk, cpu_cgrp_id, true),
|
2012-06-22 11:36:05 +00:00
|
|
|
struct task_group, css);
|
|
|
|
tg = autogroup_task_group(tsk, tg);
|
|
|
|
tsk->sched_task_group = tg;
|
|
|
|
|
2008-02-29 20:21:01 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2016-06-17 11:38:55 +00:00
|
|
|
if (tsk->sched_class->task_change_group)
|
|
|
|
tsk->sched_class->task_change_group(tsk, type);
|
2010-10-15 13:24:15 +00:00
|
|
|
else
|
2008-02-29 20:21:01 +00:00
|
|
|
#endif
|
2010-10-15 13:24:15 +00:00
|
|
|
set_task_rq(tsk, task_cpu(tsk));
|
2016-06-17 11:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change task's runqueue when it moves between groups.
|
|
|
|
*
|
|
|
|
* The caller of this function should have put the task in its new group by
|
|
|
|
* now. This function just updates tsk->se.cfs_rq and tsk->se.parent to reflect
|
|
|
|
* its new group.
|
|
|
|
*/
|
|
|
|
void sched_move_task(struct task_struct *tsk)
|
|
|
|
{
|
2017-02-21 13:47:02 +00:00
|
|
|
int queued, running, queue_flags =
|
|
|
|
DEQUEUE_SAVE | DEQUEUE_MOVE | DEQUEUE_NOCLOCK;
|
2016-06-17 11:38:55 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
rq = task_rq_lock(tsk, &rf);
|
2017-01-23 15:05:55 +00:00
|
|
|
update_rq_clock(rq);
|
2016-06-17 11:38:55 +00:00
|
|
|
|
|
|
|
running = task_current(rq, tsk);
|
|
|
|
queued = task_on_rq_queued(tsk);
|
|
|
|
|
|
|
|
if (queued)
|
2017-02-21 13:47:02 +00:00
|
|
|
dequeue_task(rq, tsk, queue_flags);
|
2017-02-06 16:04:26 +00:00
|
|
|
if (running)
|
2016-06-17 11:38:55 +00:00
|
|
|
put_prev_task(rq, tsk);
|
|
|
|
|
|
|
|
sched_change_group(tsk, TASK_MOVE_GROUP);
|
2008-02-29 20:21:01 +00:00
|
|
|
|
2014-08-20 09:47:32 +00:00
|
|
|
if (queued)
|
2017-02-21 13:47:02 +00:00
|
|
|
enqueue_task(rq, tsk, queue_flags);
|
2020-01-14 14:13:56 +00:00
|
|
|
if (running) {
|
2019-05-29 20:36:41 +00:00
|
|
|
set_next_task(rq, tsk);
|
2020-01-14 14:13:56 +00:00
|
|
|
/*
|
|
|
|
* After changing group, the running task may have joined a
|
|
|
|
* throttled one but it's still the running task. Trigger a
|
|
|
|
* resched to make sure that task can still run.
|
|
|
|
*/
|
|
|
|
resched_curr(rq);
|
|
|
|
}
|
2007-10-15 15:00:07 +00:00
|
|
|
|
2015-07-31 19:28:18 +00:00
|
|
|
task_rq_unlock(rq, tsk, &rf);
|
2007-10-15 15:00:07 +00:00
|
|
|
}
|
2007-10-19 06:41:03 +00:00
|
|
|
|
2013-08-09 00:11:23 +00:00
|
|
|
static inline struct task_group *css_tg(struct cgroup_subsys_state *css)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2013-08-09 00:11:23 +00:00
|
|
|
return css ? container_of(css, struct task_group, css) : NULL;
|
2007-10-19 06:41:03 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:23 +00:00
|
|
|
static struct cgroup_subsys_state *
|
|
|
|
cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2013-08-09 00:11:23 +00:00
|
|
|
struct task_group *parent = css_tg(parent_css);
|
|
|
|
struct task_group *tg;
|
2007-10-19 06:41:03 +00:00
|
|
|
|
2013-08-09 00:11:23 +00:00
|
|
|
if (!parent) {
|
2007-10-19 06:41:03 +00:00
|
|
|
/* This is early initialization for the top cgroup */
|
2011-01-07 07:17:36 +00:00
|
|
|
return &root_task_group.css;
|
2007-10-19 06:41:03 +00:00
|
|
|
}
|
|
|
|
|
2008-04-19 17:44:59 +00:00
|
|
|
tg = sched_create_group(parent);
|
2007-10-19 06:41:03 +00:00
|
|
|
if (IS_ERR(tg))
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
return &tg->css;
|
|
|
|
}
|
|
|
|
|
2017-02-08 11:27:27 +00:00
|
|
|
/* Expose task group only after completing cgroup initialization */
|
|
|
|
static int cpu_cgroup_css_online(struct cgroup_subsys_state *css)
|
|
|
|
{
|
|
|
|
struct task_group *tg = css_tg(css);
|
|
|
|
struct task_group *parent = css_tg(css->parent);
|
|
|
|
|
|
|
|
if (parent)
|
|
|
|
sched_online_group(tg, parent);
|
2019-12-24 11:54:04 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
|
|
|
/* Propagate the effective uclamp value for the new group */
|
|
|
|
cpu_util_update_eff(css);
|
|
|
|
#endif
|
|
|
|
|
2017-02-08 11:27:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-16 15:22:45 +00:00
|
|
|
static void cpu_cgroup_css_released(struct cgroup_subsys_state *css)
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
{
|
2013-08-09 00:11:23 +00:00
|
|
|
struct task_group *tg = css_tg(css);
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
|
2016-03-16 15:22:45 +00:00
|
|
|
sched_offline_group(tg);
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:23 +00:00
|
|
|
static void cpu_cgroup_css_free(struct cgroup_subsys_state *css)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2013-08-09 00:11:23 +00:00
|
|
|
struct task_group *tg = css_tg(css);
|
2007-10-19 06:41:03 +00:00
|
|
|
|
2016-03-16 15:22:45 +00:00
|
|
|
/*
|
|
|
|
* Relies on the RCU grace period between css_released() and this.
|
|
|
|
*/
|
|
|
|
sched_free_group(tg);
|
sched: split out css_online/css_offline from tg creation/destruction
This is a preparaton for later patches.
- What do we gain from cpu_cgroup_css_online():
After ss->css_alloc() and before ss->css_online(), there's a small
window that tg->css.cgroup is NULL. With this change, tg won't be seen
before ss->css_online(), where it's added to the global list, so we're
guaranteed we'll never see NULL tg->css.cgroup.
- What do we gain from cpu_cgroup_css_offline():
tg is freed via RCU, so is cgroup. Without this change, This is how
synchronization works:
cgroup_rmdir()
no ss->css_offline()
diput()
syncornize_rcu()
ss->css_free() <-- unregister tg, and free it via call_rcu()
kfree_rcu(cgroup) <-- wait possible refs to cgroup, and free cgroup
We can't just kfree(cgroup), because tg might access tg->css.cgroup.
With this change:
cgroup_rmdir()
ss->css_offline() <-- unregister tg
diput()
synchronize_rcu() <-- wait possible refs to tg and cgroup
ss->css_free() <-- free tg
kfree_rcu(cgroup) <-- free cgroup
As you see, kfree_rcu() is redundant now.
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Ingo Molnar <mingo@kernel.org>
2013-01-24 06:30:48 +00:00
|
|
|
}
|
|
|
|
|
2016-06-17 11:38:55 +00:00
|
|
|
/*
|
|
|
|
* This is called before wake_up_new_task(), therefore we really only
|
|
|
|
* have to set its group bits, all the other stuff does not apply.
|
|
|
|
*/
|
2015-12-03 15:24:08 +00:00
|
|
|
static void cpu_cgroup_fork(struct task_struct *task)
|
2014-10-27 10:18:25 +00:00
|
|
|
{
|
2016-06-17 11:38:55 +00:00
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
rq = task_rq_lock(task, &rf);
|
|
|
|
|
2016-10-03 14:28:37 +00:00
|
|
|
update_rq_clock(rq);
|
2016-06-17 11:38:55 +00:00
|
|
|
sched_change_group(task, TASK_SET_GROUP);
|
|
|
|
|
|
|
|
task_rq_unlock(rq, task, &rf);
|
2014-10-27 10:18:25 +00:00
|
|
|
}
|
|
|
|
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2011-12-13 02:12:21 +00:00
|
|
|
struct task_struct *task;
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
struct cgroup_subsys_state *css;
|
2016-06-16 11:29:28 +00:00
|
|
|
int ret = 0;
|
2011-12-13 02:12:21 +00:00
|
|
|
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
cgroup_taskset_for_each(task, css, tset) {
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2013-08-09 00:11:23 +00:00
|
|
|
if (!sched_rt_can_attach(css_tg(css), task))
|
2011-12-13 02:12:21 +00:00
|
|
|
return -EINVAL;
|
2008-02-13 14:45:40 +00:00
|
|
|
#endif
|
2016-06-16 11:29:28 +00:00
|
|
|
/*
|
|
|
|
* Serialize against wake_up_new_task() such that if its
|
|
|
|
* running, we're sure to observe its full state.
|
|
|
|
*/
|
|
|
|
raw_spin_lock_irq(&task->pi_lock);
|
|
|
|
/*
|
|
|
|
* Avoid calling sched_move_task() before wake_up_new_task()
|
|
|
|
* has happened. This would lead to problems with PELT, due to
|
|
|
|
* move wanting to detach+attach while we're not attached yet.
|
|
|
|
*/
|
|
|
|
if (task->state == TASK_NEW)
|
|
|
|
ret = -EINVAL;
|
|
|
|
raw_spin_unlock_irq(&task->pi_lock);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
break;
|
2011-12-13 02:12:21 +00:00
|
|
|
}
|
2016-06-16 11:29:28 +00:00
|
|
|
return ret;
|
2009-09-23 22:56:31 +00:00
|
|
|
}
|
2007-10-19 06:41:03 +00:00
|
|
|
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
static void cpu_cgroup_attach(struct cgroup_taskset *tset)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2011-12-13 02:12:21 +00:00
|
|
|
struct task_struct *task;
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
struct cgroup_subsys_state *css;
|
2011-12-13 02:12:21 +00:00
|
|
|
|
cgroup: fix handling of multi-destination migration from subtree_control enabling
Consider the following v2 hierarchy.
P0 (+memory) --- P1 (-memory) --- A
\- B
P0 has memory enabled in its subtree_control while P1 doesn't. If
both A and B contain processes, they would belong to the memory css of
P1. Now if memory is enabled on P1's subtree_control, memory csses
should be created on both A and B and A's processes should be moved to
the former and B's processes the latter. IOW, enabling controllers
can cause atomic migrations into different csses.
The core cgroup migration logic has been updated accordingly but the
controller migration methods haven't and still assume that all tasks
migrate to a single target css; furthermore, the methods were fed the
css in which subtree_control was updated which is the parent of the
target csses. pids controller depends on the migration methods to
move charges and this made the controller attribute charges to the
wrong csses often triggering the following warning by driving a
counter negative.
WARNING: CPU: 1 PID: 1 at kernel/cgroup_pids.c:97 pids_cancel.constprop.6+0x31/0x40()
Modules linked in:
CPU: 1 PID: 1 Comm: systemd Not tainted 4.4.0-rc1+ #29
...
ffffffff81f65382 ffff88007c043b90 ffffffff81551ffc 0000000000000000
ffff88007c043bc8 ffffffff810de202 ffff88007a752000 ffff88007a29ab00
ffff88007c043c80 ffff88007a1d8400 0000000000000001 ffff88007c043bd8
Call Trace:
[<ffffffff81551ffc>] dump_stack+0x4e/0x82
[<ffffffff810de202>] warn_slowpath_common+0x82/0xc0
[<ffffffff810de2fa>] warn_slowpath_null+0x1a/0x20
[<ffffffff8118e031>] pids_cancel.constprop.6+0x31/0x40
[<ffffffff8118e0fd>] pids_can_attach+0x6d/0xf0
[<ffffffff81188a4c>] cgroup_taskset_migrate+0x6c/0x330
[<ffffffff81188e05>] cgroup_migrate+0xf5/0x190
[<ffffffff81189016>] cgroup_attach_task+0x176/0x200
[<ffffffff8118949d>] __cgroup_procs_write+0x2ad/0x460
[<ffffffff81189684>] cgroup_procs_write+0x14/0x20
[<ffffffff811854e5>] cgroup_file_write+0x35/0x1c0
[<ffffffff812e26f1>] kernfs_fop_write+0x141/0x190
[<ffffffff81265f88>] __vfs_write+0x28/0xe0
[<ffffffff812666fc>] vfs_write+0xac/0x1a0
[<ffffffff81267019>] SyS_write+0x49/0xb0
[<ffffffff81bcef32>] entry_SYSCALL_64_fastpath+0x12/0x76
This patch fixes the bug by removing @css parameter from the three
migration methods, ->can_attach, ->cancel_attach() and ->attach() and
updating cgroup_taskset iteration helpers also return the destination
css in addition to the task being migrated. All controllers are
updated accordingly.
* Controllers which don't care whether there are one or multiple
target csses can be converted trivially. cpu, io, freezer, perf,
netclassid and netprio fall in this category.
* cpuset's current implementation assumes that there's single source
and destination and thus doesn't support v2 hierarchy already. The
only change made by this patchset is how that single destination css
is obtained.
* memory migration path already doesn't do anything on v2. How the
single destination css is obtained is updated and the prep stage of
mem_cgroup_can_attach() is reordered to accomodate the change.
* pids is the only controller which was affected by this bug. It now
correctly handles multi-destination migrations and no longer causes
counter underflow from incorrect accounting.
Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-and-tested-by: Daniel Wagner <daniel.wagner@bmw-carit.de>
Cc: Aleksa Sarai <cyphar@cyphar.com>
2015-12-03 15:18:21 +00:00
|
|
|
cgroup_taskset_for_each(task, css, tset)
|
2011-12-13 02:12:21 +00:00
|
|
|
sched_move_task(task);
|
2007-10-19 06:41:03 +00:00
|
|
|
}
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
2019-08-22 13:28:07 +00:00
|
|
|
static void cpu_util_update_eff(struct cgroup_subsys_state *css)
|
|
|
|
{
|
|
|
|
struct cgroup_subsys_state *top_css = css;
|
|
|
|
struct uclamp_se *uc_parent = NULL;
|
|
|
|
struct uclamp_se *uc_se = NULL;
|
|
|
|
unsigned int eff[UCLAMP_CNT];
|
2019-08-22 13:28:11 +00:00
|
|
|
enum uclamp_id clamp_id;
|
2019-08-22 13:28:07 +00:00
|
|
|
unsigned int clamps;
|
|
|
|
|
|
|
|
css_for_each_descendant_pre(css, top_css) {
|
|
|
|
uc_parent = css_tg(css)->parent
|
|
|
|
? css_tg(css)->parent->uclamp : NULL;
|
|
|
|
|
|
|
|
for_each_clamp_id(clamp_id) {
|
|
|
|
/* Assume effective clamps matches requested clamps */
|
|
|
|
eff[clamp_id] = css_tg(css)->uclamp_req[clamp_id].value;
|
|
|
|
/* Cap effective clamps with parent's effective clamps */
|
|
|
|
if (uc_parent &&
|
|
|
|
eff[clamp_id] > uc_parent[clamp_id].value) {
|
|
|
|
eff[clamp_id] = uc_parent[clamp_id].value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Ensure protection is always capped by limit */
|
|
|
|
eff[UCLAMP_MIN] = min(eff[UCLAMP_MIN], eff[UCLAMP_MAX]);
|
|
|
|
|
|
|
|
/* Propagate most restrictive effective clamps */
|
|
|
|
clamps = 0x0;
|
|
|
|
uc_se = css_tg(css)->uclamp;
|
|
|
|
for_each_clamp_id(clamp_id) {
|
|
|
|
if (eff[clamp_id] == uc_se[clamp_id].value)
|
|
|
|
continue;
|
|
|
|
uc_se[clamp_id].value = eff[clamp_id];
|
|
|
|
uc_se[clamp_id].bucket_id = uclamp_bucket_id(eff[clamp_id]);
|
|
|
|
clamps |= (0x1 << clamp_id);
|
|
|
|
}
|
2019-08-22 13:28:10 +00:00
|
|
|
if (!clamps) {
|
2019-08-22 13:28:07 +00:00
|
|
|
css = css_rightmost_descendant(css);
|
2019-08-22 13:28:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Immediately update descendants RUNNABLE tasks */
|
|
|
|
uclamp_update_active_tasks(css, clamps);
|
2019-08-22 13:28:07 +00:00
|
|
|
}
|
|
|
|
}
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Integer 10^N with a given N exponent by casting to integer the literal "1eN"
|
|
|
|
* C expression. Since there is no way to convert a macro argument (N) into a
|
|
|
|
* character constant, use two levels of macros.
|
|
|
|
*/
|
|
|
|
#define _POW10(exp) ((unsigned int)1e##exp)
|
|
|
|
#define POW10(exp) _POW10(exp)
|
|
|
|
|
|
|
|
struct uclamp_request {
|
|
|
|
#define UCLAMP_PERCENT_SHIFT 2
|
|
|
|
#define UCLAMP_PERCENT_SCALE (100 * POW10(UCLAMP_PERCENT_SHIFT))
|
|
|
|
s64 percent;
|
|
|
|
u64 util;
|
|
|
|
int ret;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct uclamp_request
|
|
|
|
capacity_from_percent(char *buf)
|
|
|
|
{
|
|
|
|
struct uclamp_request req = {
|
|
|
|
.percent = UCLAMP_PERCENT_SCALE,
|
|
|
|
.util = SCHED_CAPACITY_SCALE,
|
|
|
|
.ret = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
buf = strim(buf);
|
|
|
|
if (strcmp(buf, "max")) {
|
|
|
|
req.ret = cgroup_parse_float(buf, UCLAMP_PERCENT_SHIFT,
|
|
|
|
&req.percent);
|
|
|
|
if (req.ret)
|
|
|
|
return req;
|
2020-01-14 21:09:47 +00:00
|
|
|
if ((u64)req.percent > UCLAMP_PERCENT_SCALE) {
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
req.ret = -ERANGE;
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
|
|
|
req.util = req.percent << SCHED_CAPACITY_SHIFT;
|
|
|
|
req.util = DIV_ROUND_CLOSEST_ULL(req.util, UCLAMP_PERCENT_SCALE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t cpu_uclamp_write(struct kernfs_open_file *of, char *buf,
|
|
|
|
size_t nbytes, loff_t off,
|
|
|
|
enum uclamp_id clamp_id)
|
|
|
|
{
|
|
|
|
struct uclamp_request req;
|
|
|
|
struct task_group *tg;
|
|
|
|
|
|
|
|
req = capacity_from_percent(buf);
|
|
|
|
if (req.ret)
|
|
|
|
return req.ret;
|
|
|
|
|
|
|
|
mutex_lock(&uclamp_mutex);
|
|
|
|
rcu_read_lock();
|
|
|
|
|
|
|
|
tg = css_tg(of_css(of));
|
|
|
|
if (tg->uclamp_req[clamp_id].value != req.util)
|
|
|
|
uclamp_se_set(&tg->uclamp_req[clamp_id], req.util, false);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Because of not recoverable conversion rounding we keep track of the
|
|
|
|
* exact requested value
|
|
|
|
*/
|
|
|
|
tg->uclamp_pct[clamp_id] = req.percent;
|
|
|
|
|
2019-08-22 13:28:07 +00:00
|
|
|
/* Update effective clamps to track the most restrictive value */
|
|
|
|
cpu_util_update_eff(of_css(of));
|
|
|
|
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
rcu_read_unlock();
|
|
|
|
mutex_unlock(&uclamp_mutex);
|
|
|
|
|
|
|
|
return nbytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t cpu_uclamp_min_write(struct kernfs_open_file *of,
|
|
|
|
char *buf, size_t nbytes,
|
|
|
|
loff_t off)
|
|
|
|
{
|
|
|
|
return cpu_uclamp_write(of, buf, nbytes, off, UCLAMP_MIN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t cpu_uclamp_max_write(struct kernfs_open_file *of,
|
|
|
|
char *buf, size_t nbytes,
|
|
|
|
loff_t off)
|
|
|
|
{
|
|
|
|
return cpu_uclamp_write(of, buf, nbytes, off, UCLAMP_MAX);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void cpu_uclamp_print(struct seq_file *sf,
|
|
|
|
enum uclamp_id clamp_id)
|
|
|
|
{
|
|
|
|
struct task_group *tg;
|
|
|
|
u64 util_clamp;
|
|
|
|
u64 percent;
|
|
|
|
u32 rem;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
tg = css_tg(seq_css(sf));
|
|
|
|
util_clamp = tg->uclamp_req[clamp_id].value;
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
if (util_clamp == SCHED_CAPACITY_SCALE) {
|
|
|
|
seq_puts(sf, "max\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
percent = tg->uclamp_pct[clamp_id];
|
|
|
|
percent = div_u64_rem(percent, POW10(UCLAMP_PERCENT_SHIFT), &rem);
|
|
|
|
seq_printf(sf, "%llu.%0*u\n", percent, UCLAMP_PERCENT_SHIFT, rem);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpu_uclamp_min_show(struct seq_file *sf, void *v)
|
|
|
|
{
|
|
|
|
cpu_uclamp_print(sf, UCLAMP_MIN);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpu_uclamp_max_show(struct seq_file *sf, void *v)
|
|
|
|
{
|
|
|
|
cpu_uclamp_print(sf, UCLAMP_MAX);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_UCLAMP_TASK_GROUP */
|
|
|
|
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2013-08-09 00:11:24 +00:00
|
|
|
static int cpu_shares_write_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cftype, u64 shareval)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2019-02-27 08:10:18 +00:00
|
|
|
if (shareval > scale_load_down(ULONG_MAX))
|
|
|
|
shareval = MAX_SHARES;
|
2013-08-09 00:11:24 +00:00
|
|
|
return sched_group_set_shares(css_tg(css), scale_load(shareval));
|
2007-10-19 06:41:03 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
2007-10-19 06:41:03 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
struct task_group *tg = css_tg(css);
|
2007-10-19 06:41:03 +00:00
|
|
|
|
sched: Increase SCHED_LOAD_SCALE resolution
Introduce SCHED_LOAD_RESOLUTION, which scales is added to
SCHED_LOAD_SHIFT and increases the resolution of
SCHED_LOAD_SCALE. This patch sets the value of
SCHED_LOAD_RESOLUTION to 10, scaling up the weights for all
sched entities by a factor of 1024. With this extra resolution,
we can handle deeper cgroup hiearchies and the scheduler can do
better shares distribution and load load balancing on larger
systems (especially for low weight task groups).
This does not change the existing user interface, the scaled
weights are only used internally. We do not modify
prio_to_weight values or inverses, but use the original weights
when calculating the inverse which is used to scale execution
time delta in calc_delta_mine(). This ensures we do not lose
accuracy when accounting time to the sched entities. Thanks to
Nikunj Dadhania for fixing an bug in c_d_m() that broken fairness.
Below is some analysis of the performance costs/improvements of
this patch.
1. Micro-arch performance costs:
Experiment was to run Ingo's pipe_test_100k 200 times with the
task pinned to one cpu. I measured instruction, cycles and
stalled-cycles for the runs. See:
http://thread.gmane.org/gmane.linux.kernel/1129232/focus=1129389
for more info.
-tip (baseline):
Performance counter stats for '/root/load-scale/pipe-test-100k' (200 runs):
964,991,769 instructions # 0.82 insns per cycle
# 0.33 stalled cycles per insn
# ( +- 0.05% )
1,171,186,635 cycles # 0.000 GHz ( +- 0.08% )
306,373,664 stalled-cycles-backend # 26.16% backend cycles idle ( +- 0.28% )
314,933,621 stalled-cycles-frontend # 26.89% frontend cycles idle ( +- 0.34% )
1.122405684 seconds time elapsed ( +- 0.05% )
-tip+patches:
Performance counter stats for './load-scale/pipe-test-100k' (200 runs):
963,624,821 instructions # 0.82 insns per cycle
# 0.33 stalled cycles per insn
# ( +- 0.04% )
1,175,215,649 cycles # 0.000 GHz ( +- 0.08% )
315,321,126 stalled-cycles-backend # 26.83% backend cycles idle ( +- 0.28% )
316,835,873 stalled-cycles-frontend # 26.96% frontend cycles idle ( +- 0.29% )
1.122238659 seconds time elapsed ( +- 0.06% )
With this patch, instructions decrease by ~0.10% and cycles
increase by 0.27%. This doesn't look statistically significant.
The number of stalled cycles in the backend increased from
26.16% to 26.83%. This can be attributed to the shifts we do in
c_d_m() and other places. The fraction of stalled cycles in the
frontend remains about the same, at 26.96% compared to 26.89% in -tip.
2. Balancing low-weight task groups
Test setup: run 50 tasks with random sleep/busy times (biased
around 100ms) in a low weight container (with cpu.shares = 2).
Measure %idle as reported by mpstat over a 10s window.
-tip (baseline):
06:47:48 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle intr/s
06:47:49 PM all 94.32 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.62 15888.00
06:47:50 PM all 94.57 0.00 0.62 0.00 0.00 0.00 0.00 0.00 4.81 16180.00
06:47:51 PM all 94.69 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.25 15966.00
06:47:52 PM all 95.81 0.00 0.00 0.00 0.00 0.00 0.00 0.00 4.19 16053.00
06:47:53 PM all 94.88 0.06 0.00 0.00 0.00 0.00 0.00 0.00 5.06 15984.00
06:47:54 PM all 93.31 0.00 0.00 0.00 0.00 0.00 0.00 0.00 6.69 15806.00
06:47:55 PM all 94.19 0.00 0.06 0.00 0.00 0.00 0.00 0.00 5.75 15896.00
06:47:56 PM all 92.87 0.00 0.00 0.00 0.00 0.00 0.00 0.00 7.13 15716.00
06:47:57 PM all 94.88 0.00 0.00 0.00 0.00 0.00 0.00 0.00 5.12 15982.00
06:47:58 PM all 95.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00 4.56 16075.00
Average: all 94.49 0.01 0.08 0.00 0.00 0.00 0.00 0.00 5.42 15954.60
-tip+patches:
06:47:03 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle intr/s
06:47:04 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16630.00
06:47:05 PM all 99.69 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.31 16580.20
06:47:06 PM all 99.69 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.25 16596.00
06:47:07 PM all 99.20 0.00 0.74 0.00 0.00 0.06 0.00 0.00 0.00 17838.61
06:47:08 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16540.00
06:47:09 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16575.00
06:47:10 PM all 100.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 16614.00
06:47:11 PM all 99.94 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.06 16588.00
06:47:12 PM all 99.94 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.00 16593.00
06:47:13 PM all 99.94 0.00 0.06 0.00 0.00 0.00 0.00 0.00 0.00 16551.00
Average: all 99.84 0.00 0.09 0.00 0.00 0.01 0.00 0.00 0.06 16711.58
We see an improvement in idle% on the system (drops from 5.42% on -tip to 0.06%
with the patches).
We see an improvement in idle% on the system (drops from 5.42%
on -tip to 0.06% with the patches).
Signed-off-by: Nikhil Rao <ncrao@google.com>
Acked-by: Peter Zijlstra <peterz@infradead.org>
Cc: Nikunj A. Dadhania <nikunj@linux.vnet.ibm.com>
Cc: Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
Cc: Stephan Barwolf <stephan.baerwolf@tu-ilmenau.de>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Link: http://lkml.kernel.org/r/1305754668-18792-1-git-send-email-ncrao@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2011-05-18 21:37:48 +00:00
|
|
|
return (u64) scale_load_down(tg->shares);
|
2007-10-19 06:41:03 +00:00
|
|
|
}
|
2011-07-21 16:43:28 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_CFS_BANDWIDTH
|
2011-07-21 16:43:29 +00:00
|
|
|
static DEFINE_MUTEX(cfs_constraints_mutex);
|
|
|
|
|
2011-07-21 16:43:28 +00:00
|
|
|
const u64 max_cfs_quota_period = 1 * NSEC_PER_SEC; /* 1s */
|
2019-04-18 14:47:13 +00:00
|
|
|
static const u64 min_cfs_quota_period = 1 * NSEC_PER_MSEC; /* 1ms */
|
2011-07-21 16:43:28 +00:00
|
|
|
|
2011-07-21 16:43:29 +00:00
|
|
|
static int __cfs_schedulable(struct task_group *tg, u64 period, u64 runtime);
|
|
|
|
|
2011-07-21 16:43:28 +00:00
|
|
|
static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)
|
|
|
|
{
|
2011-11-08 04:26:33 +00:00
|
|
|
int i, ret = 0, runtime_enabled, runtime_was_enabled;
|
2011-10-25 08:00:11 +00:00
|
|
|
struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
|
2011-07-21 16:43:28 +00:00
|
|
|
|
|
|
|
if (tg == &root_task_group)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure we have at some amount of bandwidth every period. This is
|
|
|
|
* to prevent reaching a state of large arrears when throttled via
|
|
|
|
* entity_tick() resulting in prolonged exit starvation.
|
|
|
|
*/
|
|
|
|
if (quota < min_cfs_quota_period || period < min_cfs_quota_period)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Likewise, bound things on the otherside by preventing insane quota
|
|
|
|
* periods. This also allows us to normalize in computing quota
|
|
|
|
* feasibility.
|
|
|
|
*/
|
|
|
|
if (period > max_cfs_quota_period)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-06-25 08:19:42 +00:00
|
|
|
/*
|
|
|
|
* Prevent race between setting of cfs_rq->runtime_enabled and
|
|
|
|
* unthrottle_offline_cfs_rqs().
|
|
|
|
*/
|
|
|
|
get_online_cpus();
|
2011-07-21 16:43:29 +00:00
|
|
|
mutex_lock(&cfs_constraints_mutex);
|
|
|
|
ret = __cfs_schedulable(tg, period, quota);
|
|
|
|
if (ret)
|
|
|
|
goto out_unlock;
|
|
|
|
|
2011-07-21 16:43:31 +00:00
|
|
|
runtime_enabled = quota != RUNTIME_INF;
|
2011-11-08 04:26:33 +00:00
|
|
|
runtime_was_enabled = cfs_b->quota != RUNTIME_INF;
|
2013-10-16 18:16:12 +00:00
|
|
|
/*
|
|
|
|
* If we need to toggle cfs_bandwidth_used, off->on must occur
|
|
|
|
* before making related changes, and on->off must occur afterwards
|
|
|
|
*/
|
|
|
|
if (runtime_enabled && !runtime_was_enabled)
|
|
|
|
cfs_bandwidth_usage_inc();
|
2011-07-21 16:43:28 +00:00
|
|
|
raw_spin_lock_irq(&cfs_b->lock);
|
|
|
|
cfs_b->period = ns_to_ktime(period);
|
|
|
|
cfs_b->quota = quota;
|
2011-07-21 16:43:31 +00:00
|
|
|
|
2011-07-21 16:43:32 +00:00
|
|
|
__refill_cfs_bandwidth_runtime(cfs_b);
|
2017-02-01 10:46:42 +00:00
|
|
|
|
|
|
|
/* Restart the period timer (if active) to handle new period expiry: */
|
sched: Cleanup bandwidth timers
Roman reported a 3 cpu lockup scenario involving __start_cfs_bandwidth().
The more I look at that code the more I'm convinced its crack, that
entire __start_cfs_bandwidth() thing is brain melting, we don't need to
cancel a timer before starting it, *hrtimer_start*() will happily remove
the timer for you if its still enqueued.
Removing that, removes a big part of the problem, no more ugly cancel
loop to get stuck in.
So now, if I understand things right, the entire reason you have this
cfs_b->lock guarded ->timer_active nonsense is to make sure we don't
accidentally lose the timer.
It appears to me that it should be possible to guarantee that same by
unconditionally (re)starting the timer when !queued. Because regardless
what hrtimer::function will return, if we beat it to (re)enqueue the
timer, it doesn't matter.
Now, because hrtimers don't come with any serialization guarantees we
must ensure both handler and (re)start loop serialize their access to
the hrtimer to avoid both trying to forward the timer at the same
time.
Update the rt bandwidth timer to match.
This effectively reverts: 09dc4ab03936 ("sched/fair: Fix
tg_set_cfs_bandwidth() deadlock on rq->lock").
Reported-by: Roman Gushchin <klamm@yandex-team.ru>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Ben Segall <bsegall@google.com>
Cc: Paul Turner <pjt@google.com>
Link: http://lkml.kernel.org/r/20150415095011.804589208@infradead.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2015-04-15 09:41:57 +00:00
|
|
|
if (runtime_enabled)
|
|
|
|
start_cfs_bandwidth(cfs_b);
|
2017-02-01 10:46:42 +00:00
|
|
|
|
2011-07-21 16:43:28 +00:00
|
|
|
raw_spin_unlock_irq(&cfs_b->lock);
|
|
|
|
|
2014-06-25 08:19:42 +00:00
|
|
|
for_each_online_cpu(i) {
|
2011-07-21 16:43:28 +00:00
|
|
|
struct cfs_rq *cfs_rq = tg->cfs_rq[i];
|
2011-10-25 08:00:11 +00:00
|
|
|
struct rq *rq = cfs_rq->rq;
|
2016-10-04 14:04:35 +00:00
|
|
|
struct rq_flags rf;
|
2011-07-21 16:43:28 +00:00
|
|
|
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_lock_irq(rq, &rf);
|
2011-07-21 16:43:31 +00:00
|
|
|
cfs_rq->runtime_enabled = runtime_enabled;
|
2011-07-21 16:43:28 +00:00
|
|
|
cfs_rq->runtime_remaining = 0;
|
2011-07-21 16:43:34 +00:00
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
if (cfs_rq->throttled)
|
2011-07-21 16:43:34 +00:00
|
|
|
unthrottle_cfs_rq(cfs_rq);
|
2016-10-04 14:04:35 +00:00
|
|
|
rq_unlock_irq(rq, &rf);
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
2013-10-16 18:16:12 +00:00
|
|
|
if (runtime_was_enabled && !runtime_enabled)
|
|
|
|
cfs_bandwidth_usage_dec();
|
2011-07-21 16:43:29 +00:00
|
|
|
out_unlock:
|
|
|
|
mutex_unlock(&cfs_constraints_mutex);
|
2014-06-25 08:19:42 +00:00
|
|
|
put_online_cpus();
|
2011-07-21 16:43:28 +00:00
|
|
|
|
2011-07-21 16:43:29 +00:00
|
|
|
return ret;
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
|
|
|
|
2019-04-18 14:47:13 +00:00
|
|
|
static int tg_set_cfs_quota(struct task_group *tg, long cfs_quota_us)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
|
|
|
u64 quota, period;
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
period = ktime_to_ns(tg->cfs_bandwidth.period);
|
2011-07-21 16:43:28 +00:00
|
|
|
if (cfs_quota_us < 0)
|
|
|
|
quota = RUNTIME_INF;
|
2019-02-27 08:10:20 +00:00
|
|
|
else if ((u64)cfs_quota_us <= U64_MAX / NSEC_PER_USEC)
|
2011-07-21 16:43:28 +00:00
|
|
|
quota = (u64)cfs_quota_us * NSEC_PER_USEC;
|
2019-02-27 08:10:20 +00:00
|
|
|
else
|
|
|
|
return -EINVAL;
|
2011-07-21 16:43:28 +00:00
|
|
|
|
|
|
|
return tg_set_cfs_bandwidth(tg, period, quota);
|
|
|
|
}
|
|
|
|
|
2019-04-18 14:47:13 +00:00
|
|
|
static long tg_get_cfs_quota(struct task_group *tg)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
|
|
|
u64 quota_us;
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
if (tg->cfs_bandwidth.quota == RUNTIME_INF)
|
2011-07-21 16:43:28 +00:00
|
|
|
return -1;
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
quota_us = tg->cfs_bandwidth.quota;
|
2011-07-21 16:43:28 +00:00
|
|
|
do_div(quota_us, NSEC_PER_USEC);
|
|
|
|
|
|
|
|
return quota_us;
|
|
|
|
}
|
|
|
|
|
2019-04-18 14:47:13 +00:00
|
|
|
static int tg_set_cfs_period(struct task_group *tg, long cfs_period_us)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
|
|
|
u64 quota, period;
|
|
|
|
|
2019-02-27 08:10:20 +00:00
|
|
|
if ((u64)cfs_period_us > U64_MAX / NSEC_PER_USEC)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-07-21 16:43:28 +00:00
|
|
|
period = (u64)cfs_period_us * NSEC_PER_USEC;
|
2011-10-25 08:00:11 +00:00
|
|
|
quota = tg->cfs_bandwidth.quota;
|
2011-07-21 16:43:28 +00:00
|
|
|
|
|
|
|
return tg_set_cfs_bandwidth(tg, period, quota);
|
|
|
|
}
|
|
|
|
|
2019-04-18 14:47:13 +00:00
|
|
|
static long tg_get_cfs_period(struct task_group *tg)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
|
|
|
u64 cfs_period_us;
|
|
|
|
|
2011-10-25 08:00:11 +00:00
|
|
|
cfs_period_us = ktime_to_ns(tg->cfs_bandwidth.period);
|
2011-07-21 16:43:28 +00:00
|
|
|
do_div(cfs_period_us, NSEC_PER_USEC);
|
|
|
|
|
|
|
|
return cfs_period_us;
|
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static s64 cpu_cfs_quota_read_s64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return tg_get_cfs_quota(css_tg(css));
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static int cpu_cfs_quota_write_s64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cftype, s64 cfs_quota_us)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return tg_set_cfs_quota(css_tg(css), cfs_quota_us);
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static u64 cpu_cfs_period_read_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return tg_get_cfs_period(css_tg(css));
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static int cpu_cfs_period_write_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cftype, u64 cfs_period_us)
|
2011-07-21 16:43:28 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return tg_set_cfs_period(css_tg(css), cfs_period_us);
|
2011-07-21 16:43:28 +00:00
|
|
|
}
|
|
|
|
|
2011-07-21 16:43:29 +00:00
|
|
|
struct cfs_schedulable_data {
|
|
|
|
struct task_group *tg;
|
|
|
|
u64 period, quota;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* normalize group quota/period to be quota/max_period
|
|
|
|
* note: units are usecs
|
|
|
|
*/
|
|
|
|
static u64 normalize_cfs_quota(struct task_group *tg,
|
|
|
|
struct cfs_schedulable_data *d)
|
|
|
|
{
|
|
|
|
u64 quota, period;
|
|
|
|
|
|
|
|
if (tg == d->tg) {
|
|
|
|
period = d->period;
|
|
|
|
quota = d->quota;
|
|
|
|
} else {
|
|
|
|
period = tg_get_cfs_period(tg);
|
|
|
|
quota = tg_get_cfs_quota(tg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* note: these should typically be equivalent */
|
|
|
|
if (quota == RUNTIME_INF || quota == -1)
|
|
|
|
return RUNTIME_INF;
|
|
|
|
|
|
|
|
return to_ratio(period, quota);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
|
|
|
|
{
|
|
|
|
struct cfs_schedulable_data *d = data;
|
2011-10-25 08:00:11 +00:00
|
|
|
struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
|
2011-07-21 16:43:29 +00:00
|
|
|
s64 quota = 0, parent_quota = -1;
|
|
|
|
|
|
|
|
if (!tg->parent) {
|
|
|
|
quota = RUNTIME_INF;
|
|
|
|
} else {
|
2011-10-25 08:00:11 +00:00
|
|
|
struct cfs_bandwidth *parent_b = &tg->parent->cfs_bandwidth;
|
2011-07-21 16:43:29 +00:00
|
|
|
|
|
|
|
quota = normalize_cfs_quota(tg, d);
|
2014-09-21 01:24:36 +00:00
|
|
|
parent_quota = parent_b->hierarchical_quota;
|
2011-07-21 16:43:29 +00:00
|
|
|
|
|
|
|
/*
|
2018-01-22 19:26:18 +00:00
|
|
|
* Ensure max(child_quota) <= parent_quota. On cgroup2,
|
|
|
|
* always take the min. On cgroup1, only inherit when no
|
2017-02-01 10:46:42 +00:00
|
|
|
* limit is set:
|
2011-07-21 16:43:29 +00:00
|
|
|
*/
|
2018-01-22 19:26:18 +00:00
|
|
|
if (cgroup_subsys_on_dfl(cpu_cgrp_subsys)) {
|
|
|
|
quota = min(quota, parent_quota);
|
|
|
|
} else {
|
|
|
|
if (quota == RUNTIME_INF)
|
|
|
|
quota = parent_quota;
|
|
|
|
else if (parent_quota != RUNTIME_INF && quota > parent_quota)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2011-07-21 16:43:29 +00:00
|
|
|
}
|
2014-09-21 01:24:36 +00:00
|
|
|
cfs_b->hierarchical_quota = quota;
|
2011-07-21 16:43:29 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __cfs_schedulable(struct task_group *tg, u64 period, u64 quota)
|
|
|
|
{
|
2011-07-21 16:43:35 +00:00
|
|
|
int ret;
|
2011-07-21 16:43:29 +00:00
|
|
|
struct cfs_schedulable_data data = {
|
|
|
|
.tg = tg,
|
|
|
|
.period = period,
|
|
|
|
.quota = quota,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (quota != RUNTIME_INF) {
|
|
|
|
do_div(data.period, NSEC_PER_USEC);
|
|
|
|
do_div(data.quota, NSEC_PER_USEC);
|
|
|
|
}
|
|
|
|
|
2011-07-21 16:43:35 +00:00
|
|
|
rcu_read_lock();
|
|
|
|
ret = walk_tg_tree(tg_cfs_schedulable_down, tg_nop, &data);
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
return ret;
|
2011-07-21 16:43:29 +00:00
|
|
|
}
|
2011-07-21 16:43:40 +00:00
|
|
|
|
2017-09-25 16:00:18 +00:00
|
|
|
static int cpu_cfs_stat_show(struct seq_file *sf, void *v)
|
2011-07-21 16:43:40 +00:00
|
|
|
{
|
2013-12-05 17:28:04 +00:00
|
|
|
struct task_group *tg = css_tg(seq_css(sf));
|
2011-10-25 08:00:11 +00:00
|
|
|
struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
|
2011-07-21 16:43:40 +00:00
|
|
|
|
2013-12-05 17:28:01 +00:00
|
|
|
seq_printf(sf, "nr_periods %d\n", cfs_b->nr_periods);
|
|
|
|
seq_printf(sf, "nr_throttled %d\n", cfs_b->nr_throttled);
|
|
|
|
seq_printf(sf, "throttled_time %llu\n", cfs_b->throttled_time);
|
2011-07-21 16:43:40 +00:00
|
|
|
|
2018-07-04 03:27:27 +00:00
|
|
|
if (schedstat_enabled() && tg != &root_task_group) {
|
|
|
|
u64 ws = 0;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for_each_possible_cpu(i)
|
|
|
|
ws += schedstat_val(tg->se[i]->statistics.wait_sum);
|
|
|
|
|
|
|
|
seq_printf(sf, "wait_sum %llu\n", ws);
|
|
|
|
}
|
|
|
|
|
2011-07-21 16:43:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2011-07-21 16:43:28 +00:00
|
|
|
#endif /* CONFIG_CFS_BANDWIDTH */
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
2007-10-19 06:41:03 +00:00
|
|
|
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2013-08-09 00:11:24 +00:00
|
|
|
static int cpu_rt_runtime_write(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft, s64 val)
|
2008-01-25 20:08:30 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return sched_group_set_rt_runtime(css_tg(css), val);
|
2008-01-25 20:08:30 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static s64 cpu_rt_runtime_read(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
2008-01-25 20:08:30 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return sched_group_rt_runtime(css_tg(css));
|
2008-01-25 20:08:30 +00:00
|
|
|
}
|
2008-04-19 17:44:57 +00:00
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static int cpu_rt_period_write_uint(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cftype, u64 rt_period_us)
|
2008-04-19 17:44:57 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return sched_group_set_rt_period(css_tg(css), rt_period_us);
|
2008-04-19 17:44:57 +00:00
|
|
|
}
|
|
|
|
|
2013-08-09 00:11:24 +00:00
|
|
|
static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
2008-04-19 17:44:57 +00:00
|
|
|
{
|
2013-08-09 00:11:24 +00:00
|
|
|
return sched_group_rt_period(css_tg(css));
|
2008-04-19 17:44:57 +00:00
|
|
|
}
|
2008-05-30 12:23:45 +00:00
|
|
|
#endif /* CONFIG_RT_GROUP_SCHED */
|
2008-01-25 20:08:30 +00:00
|
|
|
|
2017-09-25 16:00:18 +00:00
|
|
|
static struct cftype cpu_legacy_files[] = {
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
2007-10-29 20:18:11 +00:00
|
|
|
{
|
|
|
|
.name = "shares",
|
2008-04-29 07:59:56 +00:00
|
|
|
.read_u64 = cpu_shares_read_u64,
|
|
|
|
.write_u64 = cpu_shares_write_u64,
|
2007-10-29 20:18:11 +00:00
|
|
|
},
|
2008-02-13 14:45:40 +00:00
|
|
|
#endif
|
2011-07-21 16:43:28 +00:00
|
|
|
#ifdef CONFIG_CFS_BANDWIDTH
|
|
|
|
{
|
|
|
|
.name = "cfs_quota_us",
|
|
|
|
.read_s64 = cpu_cfs_quota_read_s64,
|
|
|
|
.write_s64 = cpu_cfs_quota_write_s64,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "cfs_period_us",
|
|
|
|
.read_u64 = cpu_cfs_period_read_u64,
|
|
|
|
.write_u64 = cpu_cfs_period_write_u64,
|
|
|
|
},
|
2011-07-21 16:43:40 +00:00
|
|
|
{
|
|
|
|
.name = "stat",
|
2017-09-25 16:00:18 +00:00
|
|
|
.seq_show = cpu_cfs_stat_show,
|
2011-07-21 16:43:40 +00:00
|
|
|
},
|
2011-07-21 16:43:28 +00:00
|
|
|
#endif
|
2008-02-13 14:45:40 +00:00
|
|
|
#ifdef CONFIG_RT_GROUP_SCHED
|
2008-01-25 20:08:30 +00:00
|
|
|
{
|
2008-02-13 14:45:39 +00:00
|
|
|
.name = "rt_runtime_us",
|
2008-04-29 08:00:06 +00:00
|
|
|
.read_s64 = cpu_rt_runtime_read,
|
|
|
|
.write_s64 = cpu_rt_runtime_write,
|
2008-01-25 20:08:30 +00:00
|
|
|
},
|
2008-04-19 17:44:57 +00:00
|
|
|
{
|
|
|
|
.name = "rt_period_us",
|
2008-04-29 07:59:56 +00:00
|
|
|
.read_u64 = cpu_rt_period_read_uint,
|
|
|
|
.write_u64 = cpu_rt_period_write_uint,
|
2008-04-19 17:44:57 +00:00
|
|
|
},
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
|
|
|
{
|
|
|
|
.name = "uclamp.min",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.seq_show = cpu_uclamp_min_show,
|
|
|
|
.write = cpu_uclamp_min_write,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "uclamp.max",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.seq_show = cpu_uclamp_max_show,
|
|
|
|
.write = cpu_uclamp_max_write,
|
|
|
|
},
|
2008-02-13 14:45:40 +00:00
|
|
|
#endif
|
2017-02-01 10:46:42 +00:00
|
|
|
{ } /* Terminate */
|
2007-10-19 06:41:03 +00:00
|
|
|
};
|
|
|
|
|
2017-10-23 23:18:27 +00:00
|
|
|
static int cpu_extra_stat_show(struct seq_file *sf,
|
|
|
|
struct cgroup_subsys_state *css)
|
2017-09-25 16:00:19 +00:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_CFS_BANDWIDTH
|
|
|
|
{
|
2017-10-23 23:18:27 +00:00
|
|
|
struct task_group *tg = css_tg(css);
|
2017-09-25 16:00:19 +00:00
|
|
|
struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth;
|
|
|
|
u64 throttled_usec;
|
|
|
|
|
|
|
|
throttled_usec = cfs_b->throttled_time;
|
|
|
|
do_div(throttled_usec, NSEC_PER_USEC);
|
|
|
|
|
|
|
|
seq_printf(sf, "nr_periods %d\n"
|
|
|
|
"nr_throttled %d\n"
|
|
|
|
"throttled_usec %llu\n",
|
|
|
|
cfs_b->nr_periods, cfs_b->nr_throttled,
|
|
|
|
throttled_usec);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
|
|
|
static u64 cpu_weight_read_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
|
|
|
{
|
|
|
|
struct task_group *tg = css_tg(css);
|
|
|
|
u64 weight = scale_load_down(tg->shares);
|
|
|
|
|
|
|
|
return DIV_ROUND_CLOSEST_ULL(weight * CGROUP_WEIGHT_DFL, 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpu_weight_write_u64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft, u64 weight)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* cgroup weight knobs should use the common MIN, DFL and MAX
|
|
|
|
* values which are 1, 100 and 10000 respectively. While it loses
|
|
|
|
* a bit of range on both ends, it maps pretty well onto the shares
|
|
|
|
* value used by scheduler and the round-trip conversions preserve
|
|
|
|
* the original value over the entire range.
|
|
|
|
*/
|
|
|
|
if (weight < CGROUP_WEIGHT_MIN || weight > CGROUP_WEIGHT_MAX)
|
|
|
|
return -ERANGE;
|
|
|
|
|
|
|
|
weight = DIV_ROUND_CLOSEST_ULL(weight * 1024, CGROUP_WEIGHT_DFL);
|
|
|
|
|
|
|
|
return sched_group_set_shares(css_tg(css), scale_load(weight));
|
|
|
|
}
|
|
|
|
|
|
|
|
static s64 cpu_weight_nice_read_s64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft)
|
|
|
|
{
|
|
|
|
unsigned long weight = scale_load_down(css_tg(css)->shares);
|
|
|
|
int last_delta = INT_MAX;
|
|
|
|
int prio, delta;
|
|
|
|
|
|
|
|
/* find the closest nice value to the current weight */
|
|
|
|
for (prio = 0; prio < ARRAY_SIZE(sched_prio_to_weight); prio++) {
|
|
|
|
delta = abs(sched_prio_to_weight[prio] - weight);
|
|
|
|
if (delta >= last_delta)
|
|
|
|
break;
|
|
|
|
last_delta = delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PRIO_TO_NICE(prio - 1 + MAX_RT_PRIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpu_weight_nice_write_s64(struct cgroup_subsys_state *css,
|
|
|
|
struct cftype *cft, s64 nice)
|
|
|
|
{
|
|
|
|
unsigned long weight;
|
2018-04-20 12:29:51 +00:00
|
|
|
int idx;
|
2017-09-25 16:00:19 +00:00
|
|
|
|
|
|
|
if (nice < MIN_NICE || nice > MAX_NICE)
|
|
|
|
return -ERANGE;
|
|
|
|
|
2018-04-20 12:29:51 +00:00
|
|
|
idx = NICE_TO_PRIO(nice) - MAX_RT_PRIO;
|
|
|
|
idx = array_index_nospec(idx, 40);
|
|
|
|
weight = sched_prio_to_weight[idx];
|
|
|
|
|
2017-09-25 16:00:19 +00:00
|
|
|
return sched_group_set_shares(css_tg(css), scale_load(weight));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void __maybe_unused cpu_period_quota_print(struct seq_file *sf,
|
|
|
|
long period, long quota)
|
|
|
|
{
|
|
|
|
if (quota < 0)
|
|
|
|
seq_puts(sf, "max");
|
|
|
|
else
|
|
|
|
seq_printf(sf, "%ld", quota);
|
|
|
|
|
|
|
|
seq_printf(sf, " %ld\n", period);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* caller should put the current value in *@periodp before calling */
|
|
|
|
static int __maybe_unused cpu_period_quota_parse(char *buf,
|
|
|
|
u64 *periodp, u64 *quotap)
|
|
|
|
{
|
|
|
|
char tok[21]; /* U64_MAX */
|
|
|
|
|
2019-03-06 17:11:42 +00:00
|
|
|
if (sscanf(buf, "%20s %llu", tok, periodp) < 1)
|
2017-09-25 16:00:19 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
*periodp *= NSEC_PER_USEC;
|
|
|
|
|
|
|
|
if (sscanf(tok, "%llu", quotap))
|
|
|
|
*quotap *= NSEC_PER_USEC;
|
|
|
|
else if (!strcmp(tok, "max"))
|
|
|
|
*quotap = RUNTIME_INF;
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CFS_BANDWIDTH
|
|
|
|
static int cpu_max_show(struct seq_file *sf, void *v)
|
|
|
|
{
|
|
|
|
struct task_group *tg = css_tg(seq_css(sf));
|
|
|
|
|
|
|
|
cpu_period_quota_print(sf, tg_get_cfs_period(tg), tg_get_cfs_quota(tg));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t cpu_max_write(struct kernfs_open_file *of,
|
|
|
|
char *buf, size_t nbytes, loff_t off)
|
|
|
|
{
|
|
|
|
struct task_group *tg = css_tg(of_css(of));
|
|
|
|
u64 period = tg_get_cfs_period(tg);
|
|
|
|
u64 quota;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = cpu_period_quota_parse(buf, &period, "a);
|
|
|
|
if (!ret)
|
|
|
|
ret = tg_set_cfs_bandwidth(tg, period, quota);
|
|
|
|
return ret ?: nbytes;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct cftype cpu_files[] = {
|
|
|
|
#ifdef CONFIG_FAIR_GROUP_SCHED
|
|
|
|
{
|
|
|
|
.name = "weight",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.read_u64 = cpu_weight_read_u64,
|
|
|
|
.write_u64 = cpu_weight_write_u64,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "weight.nice",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.read_s64 = cpu_weight_nice_read_s64,
|
|
|
|
.write_s64 = cpu_weight_nice_write_s64,
|
|
|
|
},
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_CFS_BANDWIDTH
|
|
|
|
{
|
|
|
|
.name = "max",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.seq_show = cpu_max_show,
|
|
|
|
.write = cpu_max_write,
|
|
|
|
},
|
sched/uclamp: Extend CPU's cgroup controller
The cgroup CPU bandwidth controller allows to assign a specified
(maximum) bandwidth to the tasks of a group. However this bandwidth is
defined and enforced only on a temporal base, without considering the
actual frequency a CPU is running on. Thus, the amount of computation
completed by a task within an allocated bandwidth can be very different
depending on the actual frequency the CPU is running that task.
The amount of computation can be affected also by the specific CPU a
task is running on, especially when running on asymmetric capacity
systems like Arm's big.LITTLE.
With the availability of schedutil, the scheduler is now able
to drive frequency selections based on actual task utilization.
Moreover, the utilization clamping support provides a mechanism to
bias the frequency selection operated by schedutil depending on
constraints assigned to the tasks currently RUNNABLE on a CPU.
Giving the mechanisms described above, it is now possible to extend the
cpu controller to specify the minimum (or maximum) utilization which
should be considered for tasks RUNNABLE on a cpu.
This makes it possible to better defined the actual computational
power assigned to task groups, thus improving the cgroup CPU bandwidth
controller which is currently based just on time constraints.
Extend the CPU controller with a couple of new attributes uclamp.{min,max}
which allow to enforce utilization boosting and capping for all the
tasks in a group.
Specifically:
- uclamp.min: defines the minimum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run at least at a
minimum frequency which corresponds to the uclamp.min
utilization
- uclamp.max: defines the maximum utilization which should be considered
i.e. the RUNNABLE tasks of this group will run up to a
maximum frequency which corresponds to the uclamp.max
utilization
These attributes:
a) are available only for non-root nodes, both on default and legacy
hierarchies, while system wide clamps are defined by a generic
interface which does not depends on cgroups. This system wide
interface enforces constraints on tasks in the root node.
b) enforce effective constraints at each level of the hierarchy which
are a restriction of the group requests considering its parent's
effective constraints. Root group effective constraints are defined
by the system wide interface.
This mechanism allows each (non-root) level of the hierarchy to:
- request whatever clamp values it would like to get
- effectively get only up to the maximum amount allowed by its parent
c) have higher priority than task-specific clamps, defined via
sched_setattr(), thus allowing to control and restrict task requests.
Add two new attributes to the cpu controller to collect "requested"
clamp values. Allow that at each non-root level of the hierarchy.
Keep it simple by not caring now about "effective" values computation
and propagation along the hierarchy.
Update sysctl_sched_uclamp_handler() to use the newly introduced
uclamp_mutex so that we serialize system default updates with cgroup
relate updates.
Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Michal Koutny <mkoutny@suse.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Alessio Balsini <balsini@android.com>
Cc: Dietmar Eggemann <dietmar.eggemann@arm.com>
Cc: Joel Fernandes <joelaf@google.com>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Morten Rasmussen <morten.rasmussen@arm.com>
Cc: Paul Turner <pjt@google.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Perret <quentin.perret@arm.com>
Cc: Rafael J . Wysocki <rafael.j.wysocki@intel.com>
Cc: Steve Muckle <smuckle@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Todd Kjos <tkjos@google.com>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Viresh Kumar <viresh.kumar@linaro.org>
Link: https://lkml.kernel.org/r/20190822132811.31294-2-patrick.bellasi@arm.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-08-22 13:28:06 +00:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_UCLAMP_TASK_GROUP
|
|
|
|
{
|
|
|
|
.name = "uclamp.min",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.seq_show = cpu_uclamp_min_show,
|
|
|
|
.write = cpu_uclamp_min_write,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "uclamp.max",
|
|
|
|
.flags = CFTYPE_NOT_ON_ROOT,
|
|
|
|
.seq_show = cpu_uclamp_max_show,
|
|
|
|
.write = cpu_uclamp_max_write,
|
|
|
|
},
|
2017-09-25 16:00:19 +00:00
|
|
|
#endif
|
|
|
|
{ } /* terminate */
|
|
|
|
};
|
|
|
|
|
2014-02-08 15:36:58 +00:00
|
|
|
struct cgroup_subsys cpu_cgrp_subsys = {
|
2012-11-19 16:13:38 +00:00
|
|
|
.css_alloc = cpu_cgroup_css_alloc,
|
2017-02-08 11:27:27 +00:00
|
|
|
.css_online = cpu_cgroup_css_online,
|
2016-03-16 15:22:45 +00:00
|
|
|
.css_released = cpu_cgroup_css_released,
|
2012-11-19 16:13:38 +00:00
|
|
|
.css_free = cpu_cgroup_css_free,
|
2017-10-23 23:18:27 +00:00
|
|
|
.css_extra_stat_show = cpu_extra_stat_show,
|
2014-10-27 10:18:25 +00:00
|
|
|
.fork = cpu_cgroup_fork,
|
2011-12-13 02:12:21 +00:00
|
|
|
.can_attach = cpu_cgroup_can_attach,
|
|
|
|
.attach = cpu_cgroup_attach,
|
2017-09-25 16:00:18 +00:00
|
|
|
.legacy_cftypes = cpu_legacy_files,
|
2017-09-25 16:00:19 +00:00
|
|
|
.dfl_cftypes = cpu_files,
|
2016-02-23 15:00:50 +00:00
|
|
|
.early_init = true,
|
2017-09-25 16:00:19 +00:00
|
|
|
.threaded = true,
|
2007-10-19 06:41:03 +00:00
|
|
|
};
|
|
|
|
|
2008-02-13 14:45:40 +00:00
|
|
|
#endif /* CONFIG_CGROUP_SCHED */
|
2007-12-02 19:04:49 +00:00
|
|
|
|
2012-09-19 23:58:38 +00:00
|
|
|
void dump_cpu_task(int cpu)
|
|
|
|
{
|
|
|
|
pr_info("Task dump for CPU %d:\n", cpu);
|
|
|
|
sched_show_task(cpu_curr(cpu));
|
|
|
|
}
|
2015-11-30 04:59:43 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Nice levels are multiplicative, with a gentle 10% change for every
|
|
|
|
* nice level changed. I.e. when a CPU-bound task goes from nice 0 to
|
|
|
|
* nice 1, it will get ~10% less CPU time than another CPU-bound task
|
|
|
|
* that remained on nice 0.
|
|
|
|
*
|
|
|
|
* The "10% effect" is relative and cumulative: from _any_ nice level,
|
|
|
|
* if you go up 1 level, it's -10% CPU usage, if you go down 1 level
|
|
|
|
* it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
|
|
|
|
* If a task goes up by ~10% and another task goes down by ~10% then
|
|
|
|
* the relative distance between them is ~25%.)
|
|
|
|
*/
|
|
|
|
const int sched_prio_to_weight[40] = {
|
|
|
|
/* -20 */ 88761, 71755, 56483, 46273, 36291,
|
|
|
|
/* -15 */ 29154, 23254, 18705, 14949, 11916,
|
|
|
|
/* -10 */ 9548, 7620, 6100, 4904, 3906,
|
|
|
|
/* -5 */ 3121, 2501, 1991, 1586, 1277,
|
|
|
|
/* 0 */ 1024, 820, 655, 526, 423,
|
|
|
|
/* 5 */ 335, 272, 215, 172, 137,
|
|
|
|
/* 10 */ 110, 87, 70, 56, 45,
|
|
|
|
/* 15 */ 36, 29, 23, 18, 15,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inverse (2^32/x) values of the sched_prio_to_weight[] array, precalculated.
|
|
|
|
*
|
|
|
|
* In cases where the weight does not change often, we can use the
|
|
|
|
* precalculated inverse to speed up arithmetics by turning divisions
|
|
|
|
* into multiplications:
|
|
|
|
*/
|
|
|
|
const u32 sched_prio_to_wmult[40] = {
|
|
|
|
/* -20 */ 48388, 59856, 76040, 92818, 118348,
|
|
|
|
/* -15 */ 147320, 184698, 229616, 287308, 360437,
|
|
|
|
/* -10 */ 449829, 563644, 704093, 875809, 1099582,
|
|
|
|
/* -5 */ 1376151, 1717300, 2157191, 2708050, 3363326,
|
|
|
|
/* 0 */ 4194304, 5237765, 6557202, 8165337, 10153587,
|
|
|
|
/* 5 */ 12820798, 15790321, 19976592, 24970740, 31350126,
|
|
|
|
/* 10 */ 39045157, 49367440, 61356676, 76695844, 95443717,
|
|
|
|
/* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
|
|
|
|
};
|
2018-03-03 15:32:24 +00:00
|
|
|
|
|
|
|
#undef CREATE_TRACE_POINTS
|