2012-06-16 21:57:37 +08:00
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/tsacct_kern.h>
|
|
|
|
#include <linux/kernel_stat.h>
|
|
|
|
#include <linux/static_key.h>
|
2012-07-25 13:56:04 +08:00
|
|
|
#include <linux/context_tracking.h>
|
2017-02-05 18:48:36 +08:00
|
|
|
#include <linux/sched/cputime.h>
|
2012-06-16 21:57:37 +08:00
|
|
|
#include "sched.h"
|
|
|
|
|
|
|
|
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There are no locks covering percpu hardirq/softirq time.
|
2012-09-08 21:23:11 +08:00
|
|
|
* They are only modified in vtime_account, on corresponding CPU
|
2012-06-16 21:57:37 +08:00
|
|
|
* with interrupts disabled. So, writes are safe.
|
|
|
|
* They are read and saved off onto struct rq in update_rq_clock().
|
|
|
|
* This may result in other CPU reading this CPU's irq time and can
|
2012-09-08 21:23:11 +08:00
|
|
|
* race with irq/vtime_account on this CPU. We would either get old
|
2012-06-16 21:57:37 +08:00
|
|
|
* or new value with a side effect of accounting a slice of irq time to wrong
|
|
|
|
* task when irq is in progress while we read rq->clock. That is a worthy
|
|
|
|
* compromise in place of having locks on each irq in account_system_time.
|
|
|
|
*/
|
2016-09-26 08:29:20 +08:00
|
|
|
DEFINE_PER_CPU(struct irqtime, cpu_irqtime);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
static int sched_clock_irqtime;
|
|
|
|
|
|
|
|
void enable_sched_clock_irqtime(void)
|
|
|
|
{
|
|
|
|
sched_clock_irqtime = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void disable_sched_clock_irqtime(void)
|
|
|
|
{
|
|
|
|
sched_clock_irqtime = 0;
|
|
|
|
}
|
|
|
|
|
2017-04-25 22:10:48 +08:00
|
|
|
static void irqtime_account_delta(struct irqtime *irqtime, u64 delta,
|
|
|
|
enum cpu_usage_stat idx)
|
|
|
|
{
|
|
|
|
u64 *cpustat = kcpustat_this_cpu->cpustat;
|
|
|
|
|
|
|
|
u64_stats_update_begin(&irqtime->sync);
|
|
|
|
cpustat[idx] += delta;
|
|
|
|
irqtime->total += delta;
|
|
|
|
irqtime->tick_delta += delta;
|
|
|
|
u64_stats_update_end(&irqtime->sync);
|
|
|
|
}
|
|
|
|
|
2012-06-16 21:57:37 +08:00
|
|
|
/*
|
|
|
|
* Called before incrementing preempt_count on {soft,}irq_enter
|
|
|
|
* and before decrementing preempt_count on {soft,}irq_exit.
|
|
|
|
*/
|
2012-10-06 11:23:22 +08:00
|
|
|
void irqtime_account_irq(struct task_struct *curr)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2016-09-26 08:29:20 +08:00
|
|
|
struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime);
|
2012-06-16 21:57:37 +08:00
|
|
|
s64 delta;
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
if (!sched_clock_irqtime)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cpu = smp_processor_id();
|
2016-09-26 08:29:20 +08:00
|
|
|
delta = sched_clock_cpu(cpu) - irqtime->irq_start_time;
|
|
|
|
irqtime->irq_start_time += delta;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We do not account for softirq time from ksoftirqd here.
|
|
|
|
* We want to continue accounting softirq time to ksoftirqd thread
|
|
|
|
* in that case, so as not to confuse scheduler with a special task
|
|
|
|
* that do not consume any time, but still wants to run.
|
|
|
|
*/
|
2017-04-25 22:10:48 +08:00
|
|
|
if (hardirq_count())
|
|
|
|
irqtime_account_delta(irqtime, delta, CPUTIME_IRQ);
|
|
|
|
else if (in_serving_softirq() && curr != this_cpu_ksoftirqd())
|
|
|
|
irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
2012-10-06 11:23:22 +08:00
|
|
|
EXPORT_SYMBOL_GPL(irqtime_account_irq);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
static u64 irqtime_tick_accounted(u64 maxtime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2017-01-31 11:09:32 +08:00
|
|
|
struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime);
|
2017-01-31 11:09:41 +08:00
|
|
|
u64 delta;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
delta = min(irqtime->tick_delta, maxtime);
|
|
|
|
irqtime->tick_delta -= delta;
|
2016-09-26 08:29:18 +08:00
|
|
|
|
2017-01-31 11:09:32 +08:00
|
|
|
return delta;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#else /* CONFIG_IRQ_TIME_ACCOUNTING */
|
|
|
|
|
|
|
|
#define sched_clock_irqtime (0)
|
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
static u64 irqtime_tick_accounted(u64 dummy)
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-06-16 21:57:37 +08:00
|
|
|
#endif /* !CONFIG_IRQ_TIME_ACCOUNTING */
|
|
|
|
|
|
|
|
static inline void task_group_account_field(struct task_struct *p, int index,
|
|
|
|
u64 tmp)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Since all updates are sure to touch the root cgroup, we
|
|
|
|
* get ourselves ahead and touch it first. If the root cgroup
|
|
|
|
* is the only cgroup, then nothing else should be necessary.
|
|
|
|
*
|
|
|
|
*/
|
2013-08-07 23:38:24 +08:00
|
|
|
__this_cpu_add(kernel_cpustat.cpustat[index], tmp);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-03-29 14:37:06 +08:00
|
|
|
cpuacct_account_field(p, index, tmp);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account user cpu time to a process.
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @cputime: the cpu time spent in user space since the last update
|
|
|
|
*/
|
2017-01-31 11:09:37 +08:00
|
|
|
void account_user_time(struct task_struct *p, u64 cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
int index;
|
|
|
|
|
|
|
|
/* Add user time to process. */
|
2017-01-31 11:09:37 +08:00
|
|
|
p->utime += cputime;
|
|
|
|
account_group_user_time(p, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2014-01-28 11:00:45 +08:00
|
|
|
index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/* Add user time to cpustat. */
|
2017-01-31 11:09:37 +08:00
|
|
|
task_group_account_field(p, index, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/* Account for user time used */
|
2012-11-13 21:20:55 +08:00
|
|
|
acct_account_cputime(p);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account guest cpu time to a process.
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @cputime: the cpu time spent in virtual machine since the last update
|
|
|
|
*/
|
2017-01-31 11:09:40 +08:00
|
|
|
void account_guest_time(struct task_struct *p, u64 cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
u64 *cpustat = kcpustat_this_cpu->cpustat;
|
|
|
|
|
|
|
|
/* Add guest time to process. */
|
2017-01-31 11:09:40 +08:00
|
|
|
p->utime += cputime;
|
|
|
|
account_group_user_time(p, cputime);
|
|
|
|
p->gtime += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/* Add guest time to cpustat. */
|
2014-01-28 11:00:45 +08:00
|
|
|
if (task_nice(p) > 0) {
|
2017-01-31 11:09:40 +08:00
|
|
|
cpustat[CPUTIME_NICE] += cputime;
|
|
|
|
cpustat[CPUTIME_GUEST_NICE] += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
} else {
|
2017-01-31 11:09:40 +08:00
|
|
|
cpustat[CPUTIME_USER] += cputime;
|
|
|
|
cpustat[CPUTIME_GUEST] += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account system cpu time to a process and desired cpustat field
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @cputime: the cpu time spent in kernel space since the last update
|
2016-11-15 10:06:51 +08:00
|
|
|
* @index: pointer to cpustat field that has to be updated
|
2012-06-16 21:57:37 +08:00
|
|
|
*/
|
2017-01-06 01:11:43 +08:00
|
|
|
void account_system_index_time(struct task_struct *p,
|
2017-01-31 11:09:40 +08:00
|
|
|
u64 cputime, enum cpu_usage_stat index)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
/* Add system time to process. */
|
2017-01-31 11:09:40 +08:00
|
|
|
p->stime += cputime;
|
|
|
|
account_group_system_time(p, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/* Add system time to cpustat. */
|
2017-01-31 11:09:40 +08:00
|
|
|
task_group_account_field(p, index, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
/* Account for system time used */
|
2012-11-13 21:20:55 +08:00
|
|
|
acct_account_cputime(p);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account system cpu time to a process.
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @hardirq_offset: the offset to subtract from hardirq_count()
|
|
|
|
* @cputime: the cpu time spent in kernel space since the last update
|
|
|
|
*/
|
2017-01-31 11:09:40 +08:00
|
|
|
void account_system_time(struct task_struct *p, int hardirq_offset, u64 cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
int index;
|
|
|
|
|
|
|
|
if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) {
|
2016-11-15 10:06:51 +08:00
|
|
|
account_guest_time(p, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hardirq_count() - hardirq_offset)
|
|
|
|
index = CPUTIME_IRQ;
|
|
|
|
else if (in_serving_softirq())
|
|
|
|
index = CPUTIME_SOFTIRQ;
|
|
|
|
else
|
|
|
|
index = CPUTIME_SYSTEM;
|
|
|
|
|
2017-01-06 01:11:43 +08:00
|
|
|
account_system_index_time(p, cputime, index);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account for involuntary wait time.
|
|
|
|
* @cputime: the cpu time spent in involuntary wait
|
|
|
|
*/
|
2017-01-31 11:09:38 +08:00
|
|
|
void account_steal_time(u64 cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
u64 *cpustat = kcpustat_this_cpu->cpustat;
|
|
|
|
|
2017-01-31 11:09:38 +08:00
|
|
|
cpustat[CPUTIME_STEAL] += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Account for idle time.
|
|
|
|
* @cputime: the cpu time spent in idle wait
|
|
|
|
*/
|
2017-01-31 11:09:39 +08:00
|
|
|
void account_idle_time(u64 cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
u64 *cpustat = kcpustat_this_cpu->cpustat;
|
|
|
|
struct rq *rq = this_rq();
|
|
|
|
|
|
|
|
if (atomic_read(&rq->nr_iowait) > 0)
|
2017-01-31 11:09:39 +08:00
|
|
|
cpustat[CPUTIME_IOWAIT] += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
else
|
2017-01-31 11:09:39 +08:00
|
|
|
cpustat[CPUTIME_IDLE] += cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
sched/cputime: Resync steal time when guest & host lose sync
Commit:
57430218317e ("sched/cputime: Count actually elapsed irq & softirq time")
... fixed a bug but also triggered a regression:
On an i5 laptop, 4 pCPUs, 4vCPUs for one full dynticks guest, there are four
CPU hog processes(for loop) running in the guest, I hot-unplug the pCPUs
on host one by one until there is only one left, then observe CPU utilization
via 'top' in the guest, it shows:
100% st for cpu0(housekeeping)
75% st for other CPUs (nohz full mode)
However, w/o this commit it shows the correct 75% for all four CPUs.
When a guest is interrupted for a longer amount of time, missed clock ticks
are not redelivered later. Because of that, we should not limit the amount
of steal time accounted to the amount of time that the calling functions
think have passed.
However, the interval returned by account_other_time() is NOT rounded down
to the nearest jiffy, while the base interval in get_vtime_delta() it is
subtracted from is, so the max cputime limit is required to avoid underflow.
This patch fixes the regression by limiting the account_other_time() from
get_vtime_delta() to avoid underflow, and lets the other three call sites
(in account_other_time() and steal_account_process_time()) account however
much steal time the host told us elapsed.
Suggested-by: Rik van Riel <riel@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
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: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kvm@vger.kernel.org
Link: http://lkml.kernel.org/r/1471399546-4069-1-git-send-email-wanpeng.li@hotmail.com
[ Improved the changelog. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-17 10:05:46 +08:00
|
|
|
/*
|
|
|
|
* When a guest is interrupted for a longer amount of time, missed clock
|
|
|
|
* ticks are not redelivered later. Due to that, this function may on
|
|
|
|
* occasion account more time than the calling functions think elapsed.
|
|
|
|
*/
|
2017-01-31 11:09:41 +08:00
|
|
|
static __always_inline u64 steal_account_process_time(u64 maxtime)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_PARAVIRT
|
|
|
|
if (static_key_false(¶virt_steal_enabled)) {
|
2017-01-31 11:09:41 +08:00
|
|
|
u64 steal;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
|
|
|
steal = paravirt_steal_clock(smp_processor_id());
|
|
|
|
steal -= this_rq()->prev_steal_time;
|
2017-01-31 11:09:41 +08:00
|
|
|
steal = min(steal, maxtime);
|
|
|
|
account_steal_time(steal);
|
|
|
|
this_rq()->prev_steal_time += steal;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
return steal;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
#endif
|
2016-06-13 18:32:46 +08:00
|
|
|
return 0;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
/*
|
|
|
|
* Account how much elapsed time was spent in steal, irq, or softirq time.
|
|
|
|
*/
|
2017-01-31 11:09:41 +08:00
|
|
|
static inline u64 account_other_time(u64 max)
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
{
|
2017-01-31 11:09:41 +08:00
|
|
|
u64 accounted;
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
|
2016-09-26 08:29:18 +08:00
|
|
|
/* Shall be converted to a lockdep-enabled lightweight check */
|
|
|
|
WARN_ON_ONCE(!irqs_disabled());
|
|
|
|
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
accounted = steal_account_process_time(max);
|
|
|
|
|
|
|
|
if (accounted < max)
|
2017-01-31 11:09:32 +08:00
|
|
|
accounted += irqtime_tick_accounted(max - accounted);
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
|
|
|
|
return accounted;
|
|
|
|
}
|
|
|
|
|
2016-08-17 17:30:44 +08:00
|
|
|
#ifdef CONFIG_64BIT
|
|
|
|
static inline u64 read_sum_exec_runtime(struct task_struct *t)
|
|
|
|
{
|
|
|
|
return t->se.sum_exec_runtime;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static u64 read_sum_exec_runtime(struct task_struct *t)
|
|
|
|
{
|
|
|
|
u64 ns;
|
|
|
|
struct rq_flags rf;
|
|
|
|
struct rq *rq;
|
|
|
|
|
|
|
|
rq = task_rq_lock(t, &rf);
|
|
|
|
ns = t->se.sum_exec_runtime;
|
|
|
|
task_rq_unlock(rq, t, &rf);
|
|
|
|
|
|
|
|
return ns;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-11-21 22:55:59 +08:00
|
|
|
/*
|
|
|
|
* Accumulate raw cputime values of dead tasks (sig->[us]time) and live
|
|
|
|
* tasks (sum on group iteration) belonging to @tsk's group.
|
|
|
|
*/
|
|
|
|
void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
|
|
|
|
{
|
|
|
|
struct signal_struct *sig = tsk->signal;
|
2017-01-31 11:09:23 +08:00
|
|
|
u64 utime, stime;
|
2012-11-21 22:55:59 +08:00
|
|
|
struct task_struct *t;
|
2014-08-17 01:40:10 +08:00
|
|
|
unsigned int seq, nextseq;
|
2014-09-12 21:12:15 +08:00
|
|
|
unsigned long flags;
|
2012-11-21 22:55:59 +08:00
|
|
|
|
2016-08-17 17:30:44 +08:00
|
|
|
/*
|
|
|
|
* Update current task runtime to account pending time since last
|
|
|
|
* scheduler action or thread_group_cputime() call. This thread group
|
|
|
|
* might have other running tasks on different CPUs, but updating
|
|
|
|
* their runtime can affect syscall performance, so we skip account
|
|
|
|
* those pending times and rely only on values updated on tick or
|
|
|
|
* other scheduler action.
|
|
|
|
*/
|
|
|
|
if (same_thread_group(current, tsk))
|
|
|
|
(void) task_sched_runtime(current);
|
|
|
|
|
2012-11-21 22:55:59 +08:00
|
|
|
rcu_read_lock();
|
2014-08-17 01:40:10 +08:00
|
|
|
/* Attempt a lockless read on the first round. */
|
|
|
|
nextseq = 0;
|
|
|
|
do {
|
|
|
|
seq = nextseq;
|
2014-09-12 21:12:15 +08:00
|
|
|
flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
|
2014-08-17 01:40:10 +08:00
|
|
|
times->utime = sig->utime;
|
|
|
|
times->stime = sig->stime;
|
|
|
|
times->sum_exec_runtime = sig->sum_sched_runtime;
|
|
|
|
|
|
|
|
for_each_thread(tsk, t) {
|
|
|
|
task_cputime(t, &utime, &stime);
|
|
|
|
times->utime += utime;
|
|
|
|
times->stime += stime;
|
2016-08-17 17:30:44 +08:00
|
|
|
times->sum_exec_runtime += read_sum_exec_runtime(t);
|
2014-08-17 01:40:10 +08:00
|
|
|
}
|
|
|
|
/* If lockless access failed, take the lock. */
|
|
|
|
nextseq = 1;
|
|
|
|
} while (need_seqretry(&sig->stats_lock, seq));
|
2014-09-12 21:12:15 +08:00
|
|
|
done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
|
2012-11-21 22:55:59 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
}
|
|
|
|
|
2012-06-16 21:57:37 +08:00
|
|
|
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
|
|
|
|
/*
|
|
|
|
* Account a tick to a process and cpustat
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @user_tick: is the tick from userspace
|
|
|
|
* @rq: the pointer to rq
|
|
|
|
*
|
|
|
|
* Tick demultiplexing follows the order
|
|
|
|
* - pending hardirq update
|
|
|
|
* - pending softirq update
|
|
|
|
* - user_time
|
|
|
|
* - idle_time
|
|
|
|
* - system time
|
|
|
|
* - check for guest_time
|
|
|
|
* - else account as system_time
|
|
|
|
*
|
|
|
|
* Check for hardirq is done both for system and user time as there is
|
|
|
|
* no timer going off while we are on hardirq and hence we may never get an
|
|
|
|
* opportunity to update it solely in system time.
|
|
|
|
* p->stime and friends are only updated on system time and not on irq
|
|
|
|
* softirq as those do not count in task exec_runtime any more.
|
|
|
|
*/
|
|
|
|
static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
|
2014-05-03 05:26:24 +08:00
|
|
|
struct rq *rq, int ticks)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2017-01-31 11:09:41 +08:00
|
|
|
u64 other, cputime = TICK_NSEC * ticks;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
/*
|
|
|
|
* When returning from idle, many ticks can get accounted at
|
|
|
|
* once, including some ticks of steal, irq, and softirq time.
|
|
|
|
* Subtract those ticks from the amount of time accounted to
|
|
|
|
* idle, or potentially user or system time. Due to rounding,
|
|
|
|
* other time can exceed ticks occasionally.
|
|
|
|
*/
|
sched/cputime: Resync steal time when guest & host lose sync
Commit:
57430218317e ("sched/cputime: Count actually elapsed irq & softirq time")
... fixed a bug but also triggered a regression:
On an i5 laptop, 4 pCPUs, 4vCPUs for one full dynticks guest, there are four
CPU hog processes(for loop) running in the guest, I hot-unplug the pCPUs
on host one by one until there is only one left, then observe CPU utilization
via 'top' in the guest, it shows:
100% st for cpu0(housekeeping)
75% st for other CPUs (nohz full mode)
However, w/o this commit it shows the correct 75% for all four CPUs.
When a guest is interrupted for a longer amount of time, missed clock ticks
are not redelivered later. Because of that, we should not limit the amount
of steal time accounted to the amount of time that the calling functions
think have passed.
However, the interval returned by account_other_time() is NOT rounded down
to the nearest jiffy, while the base interval in get_vtime_delta() it is
subtracted from is, so the max cputime limit is required to avoid underflow.
This patch fixes the regression by limiting the account_other_time() from
get_vtime_delta() to avoid underflow, and lets the other three call sites
(in account_other_time() and steal_account_process_time()) account however
much steal time the host told us elapsed.
Suggested-by: Rik van Riel <riel@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
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: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kvm@vger.kernel.org
Link: http://lkml.kernel.org/r/1471399546-4069-1-git-send-email-wanpeng.li@hotmail.com
[ Improved the changelog. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-17 10:05:46 +08:00
|
|
|
other = account_other_time(ULONG_MAX);
|
2017-01-31 11:09:41 +08:00
|
|
|
if (other >= cputime)
|
2012-06-16 21:57:37 +08:00
|
|
|
return;
|
2017-01-31 11:09:37 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
cputime -= other;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
if (this_cpu_ksoftirqd() == p) {
|
2012-06-16 21:57:37 +08:00
|
|
|
/*
|
|
|
|
* ksoftirqd time do not get accounted in cpu_softirq_time.
|
|
|
|
* So, we have to handle it separately here.
|
|
|
|
* Also, p->stime needs to be updated for ksoftirqd.
|
|
|
|
*/
|
2017-01-31 11:09:40 +08:00
|
|
|
account_system_index_time(p, cputime, CPUTIME_SOFTIRQ);
|
2012-06-16 21:57:37 +08:00
|
|
|
} else if (user_tick) {
|
2016-11-15 10:06:51 +08:00
|
|
|
account_user_time(p, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
} else if (p == rq->idle) {
|
2017-01-31 11:09:39 +08:00
|
|
|
account_idle_time(cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
} else if (p->flags & PF_VCPU) { /* System time or guest time */
|
2017-01-31 11:09:40 +08:00
|
|
|
account_guest_time(p, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
} else {
|
2017-01-31 11:09:40 +08:00
|
|
|
account_system_index_time(p, cputime, CPUTIME_SYSTEM);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void irqtime_account_idle_ticks(int ticks)
|
|
|
|
{
|
|
|
|
struct rq *rq = this_rq();
|
|
|
|
|
2014-05-03 05:26:24 +08:00
|
|
|
irqtime_account_process_tick(current, 0, rq, ticks);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
#else /* CONFIG_IRQ_TIME_ACCOUNTING */
|
2012-07-17 00:00:34 +08:00
|
|
|
static inline void irqtime_account_idle_ticks(int ticks) {}
|
|
|
|
static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick,
|
2014-05-03 05:26:24 +08:00
|
|
|
struct rq *rq, int nr_ticks) {}
|
2012-06-16 21:57:37 +08:00
|
|
|
#endif /* CONFIG_IRQ_TIME_ACCOUNTING */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Use precise platform statistics if available:
|
|
|
|
*/
|
|
|
|
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
|
2012-09-08 22:14:02 +08:00
|
|
|
|
2012-11-14 07:24:25 +08:00
|
|
|
#ifndef __ARCH_HAS_VTIME_TASK_SWITCH
|
2013-07-12 09:10:15 +08:00
|
|
|
void vtime_common_task_switch(struct task_struct *prev)
|
2012-11-14 07:24:25 +08:00
|
|
|
{
|
|
|
|
if (is_idle_task(prev))
|
|
|
|
vtime_account_idle(prev);
|
|
|
|
else
|
|
|
|
vtime_account_system(prev);
|
|
|
|
|
2017-01-06 01:11:50 +08:00
|
|
|
vtime_flush(prev);
|
2012-11-14 07:24:25 +08:00
|
|
|
arch_vtime_task_switch(prev);
|
|
|
|
}
|
|
|
|
#endif
|
2012-10-25 00:05:51 +08:00
|
|
|
|
2016-07-13 22:50:03 +08:00
|
|
|
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
|
2012-09-08 22:14:02 +08:00
|
|
|
/*
|
|
|
|
* Archs that account the whole time spent in the idle task
|
|
|
|
* (outside irq) as idle time can rely on this and just implement
|
2012-11-14 01:21:22 +08:00
|
|
|
* vtime_account_system() and vtime_account_idle(). Archs that
|
2012-09-08 22:14:02 +08:00
|
|
|
* have other meaning of the idle time (s390 only includes the
|
|
|
|
* time spent by the CPU when it's in low power mode) must override
|
|
|
|
* vtime_account().
|
|
|
|
*/
|
|
|
|
#ifndef __ARCH_HAS_VTIME_ACCOUNT
|
2016-07-13 22:50:03 +08:00
|
|
|
void vtime_account_irq_enter(struct task_struct *tsk)
|
2012-09-08 22:14:02 +08:00
|
|
|
{
|
2016-07-13 22:50:03 +08:00
|
|
|
if (!in_interrupt() && is_idle_task(tsk))
|
|
|
|
vtime_account_idle(tsk);
|
|
|
|
else
|
|
|
|
vtime_account_system(tsk);
|
2012-09-08 22:14:02 +08:00
|
|
|
}
|
2016-07-13 22:50:03 +08:00
|
|
|
EXPORT_SYMBOL_GPL(vtime_account_irq_enter);
|
2012-09-08 22:14:02 +08:00
|
|
|
#endif /* __ARCH_HAS_VTIME_ACCOUNT */
|
2013-02-26 00:25:39 +08:00
|
|
|
|
2017-01-31 11:09:23 +08:00
|
|
|
void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
|
2013-02-26 00:25:39 +08:00
|
|
|
{
|
|
|
|
*ut = p->utime;
|
|
|
|
*st = p->stime;
|
|
|
|
}
|
2015-09-16 17:29:50 +08:00
|
|
|
EXPORT_SYMBOL_GPL(task_cputime_adjusted);
|
2012-09-08 22:14:02 +08:00
|
|
|
|
2017-01-31 11:09:23 +08:00
|
|
|
void thread_group_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
|
2013-02-26 00:25:39 +08:00
|
|
|
{
|
|
|
|
struct task_cputime cputime;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-02-26 00:25:39 +08:00
|
|
|
thread_group_cputime(p, &cputime);
|
|
|
|
|
|
|
|
*ut = cputime.utime;
|
|
|
|
*st = cputime.stime;
|
|
|
|
}
|
|
|
|
#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
|
|
|
|
/*
|
|
|
|
* Account a single tick of cpu time.
|
|
|
|
* @p: the process that the cpu time gets accounted to
|
|
|
|
* @user_tick: indicates if the tick is a user or a system tick
|
|
|
|
*/
|
|
|
|
void account_process_tick(struct task_struct *p, int user_tick)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2017-01-31 11:09:41 +08:00
|
|
|
u64 cputime, steal;
|
2013-02-26 00:25:39 +08:00
|
|
|
struct rq *rq = this_rq();
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2015-11-19 23:47:32 +08:00
|
|
|
if (vtime_accounting_cpu_enabled())
|
2013-02-26 00:25:39 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (sched_clock_irqtime) {
|
2014-05-03 05:26:24 +08:00
|
|
|
irqtime_account_process_tick(p, user_tick, rq, 1);
|
2013-02-26 00:25:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
cputime = TICK_NSEC;
|
sched/cputime: Resync steal time when guest & host lose sync
Commit:
57430218317e ("sched/cputime: Count actually elapsed irq & softirq time")
... fixed a bug but also triggered a regression:
On an i5 laptop, 4 pCPUs, 4vCPUs for one full dynticks guest, there are four
CPU hog processes(for loop) running in the guest, I hot-unplug the pCPUs
on host one by one until there is only one left, then observe CPU utilization
via 'top' in the guest, it shows:
100% st for cpu0(housekeeping)
75% st for other CPUs (nohz full mode)
However, w/o this commit it shows the correct 75% for all four CPUs.
When a guest is interrupted for a longer amount of time, missed clock ticks
are not redelivered later. Because of that, we should not limit the amount
of steal time accounted to the amount of time that the calling functions
think have passed.
However, the interval returned by account_other_time() is NOT rounded down
to the nearest jiffy, while the base interval in get_vtime_delta() it is
subtracted from is, so the max cputime limit is required to avoid underflow.
This patch fixes the regression by limiting the account_other_time() from
get_vtime_delta() to avoid underflow, and lets the other three call sites
(in account_other_time() and steal_account_process_time()) account however
much steal time the host told us elapsed.
Suggested-by: Rik van Riel <riel@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
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: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kvm@vger.kernel.org
Link: http://lkml.kernel.org/r/1471399546-4069-1-git-send-email-wanpeng.li@hotmail.com
[ Improved the changelog. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-17 10:05:46 +08:00
|
|
|
steal = steal_account_process_time(ULONG_MAX);
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
if (steal >= cputime)
|
2013-02-26 00:25:39 +08:00
|
|
|
return;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:41 +08:00
|
|
|
cputime -= steal;
|
sched/cputime: Count actually elapsed irq & softirq time
Currently, if there was any irq or softirq time during 'ticks'
jiffies, the entire period will be accounted as irq or softirq
time.
This is inaccurate if only a subset of the time was actually spent
handling irqs, and could conceivably mis-count all of the ticks during
a period as irq time, when there was some irq and some softirq time.
This can actually happen when irqtime_account_process_tick is called
from account_idle_ticks, which can pass a larger number of ticks down
all at once.
Fix this by changing irqtime_account_hi_update(), irqtime_account_si_update(),
and steal_account_process_ticks() to work with cputime_t time units, and
return the amount of time spent in each mode.
Rename steal_account_process_ticks() to steal_account_process_time(), to
reflect that time is now accounted in cputime_t, instead of ticks.
Additionally, have irqtime_account_process_tick() take into account how
much time was spent in each of steal, irq, and softirq time.
The latter could help improve the accuracy of cputime
accounting when returning from idle on a NO_HZ_IDLE CPU.
Properly accounting how much time was spent in hardirq and
softirq time will also allow the NO_HZ_FULL code to re-use
these same functions for hardirq and softirq accounting.
Signed-off-by: Rik van Riel <riel@redhat.com>
[ Make nsecs_to_cputime64() actually return cputime64_t. ]
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Wanpeng Li <wanpeng.li@hotmail.com>
Link: http://lkml.kernel.org/r/1468421405-20056-2-git-send-email-fweisbec@gmail.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-07-13 22:50:01 +08:00
|
|
|
|
2013-02-26 00:25:39 +08:00
|
|
|
if (user_tick)
|
2016-11-15 10:06:51 +08:00
|
|
|
account_user_time(p, cputime);
|
2013-02-26 00:25:39 +08:00
|
|
|
else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
|
2017-01-31 11:09:40 +08:00
|
|
|
account_system_time(p, HARDIRQ_OFFSET, cputime);
|
2012-06-16 21:57:37 +08:00
|
|
|
else
|
2017-01-31 11:09:39 +08:00
|
|
|
account_idle_time(cputime);
|
2013-02-26 00:25:39 +08:00
|
|
|
}
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-02-26 00:25:39 +08:00
|
|
|
/*
|
|
|
|
* Account multiple ticks of idle time.
|
|
|
|
* @ticks: number of stolen ticks
|
|
|
|
*/
|
|
|
|
void account_idle_ticks(unsigned long ticks)
|
|
|
|
{
|
2017-01-31 11:09:39 +08:00
|
|
|
u64 cputime, steal;
|
2016-08-11 20:58:24 +08:00
|
|
|
|
2013-02-26 00:25:39 +08:00
|
|
|
if (sched_clock_irqtime) {
|
|
|
|
irqtime_account_idle_ticks(ticks);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-31 11:09:39 +08:00
|
|
|
cputime = ticks * TICK_NSEC;
|
2017-01-31 11:09:41 +08:00
|
|
|
steal = steal_account_process_time(ULONG_MAX);
|
2016-08-11 13:36:35 +08:00
|
|
|
|
|
|
|
if (steal >= cputime)
|
|
|
|
return;
|
|
|
|
|
|
|
|
cputime -= steal;
|
|
|
|
account_idle_time(cputime);
|
2013-02-26 00:25:39 +08:00
|
|
|
}
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-02-21 01:54:55 +08:00
|
|
|
/*
|
2013-04-30 23:14:42 +08:00
|
|
|
* Perform (stime * rtime) / total, but avoid multiplication overflow by
|
|
|
|
* loosing precision when the numbers are big.
|
2013-02-21 01:54:55 +08:00
|
|
|
*/
|
2017-01-31 11:09:23 +08:00
|
|
|
static u64 scale_stime(u64 stime, u64 rtime, u64 total)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2013-04-30 23:14:42 +08:00
|
|
|
u64 scaled;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-04-30 23:14:42 +08:00
|
|
|
for (;;) {
|
|
|
|
/* Make sure "rtime" is the bigger of stime/rtime */
|
2013-05-02 21:34:33 +08:00
|
|
|
if (stime > rtime)
|
|
|
|
swap(rtime, stime);
|
2013-04-30 23:14:42 +08:00
|
|
|
|
|
|
|
/* Make sure 'total' fits in 32 bits */
|
|
|
|
if (total >> 32)
|
|
|
|
goto drop_precision;
|
|
|
|
|
|
|
|
/* Does rtime (and thus stime) fit in 32 bits? */
|
|
|
|
if (!(rtime >> 32))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Can we just balance rtime/stime rather than dropping bits? */
|
|
|
|
if (stime >> 31)
|
|
|
|
goto drop_precision;
|
|
|
|
|
|
|
|
/* We can grow stime and shrink rtime and try to make them both fit */
|
|
|
|
stime <<= 1;
|
|
|
|
rtime >>= 1;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
drop_precision:
|
|
|
|
/* We drop from rtime, it has more bits than stime */
|
|
|
|
rtime >>= 1;
|
|
|
|
total >>= 1;
|
2013-02-21 01:54:55 +08:00
|
|
|
}
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-04-30 23:14:42 +08:00
|
|
|
/*
|
|
|
|
* Make sure gcc understands that this is a 32x32->64 multiply,
|
|
|
|
* followed by a 64/32->64 divide.
|
|
|
|
*/
|
|
|
|
scaled = div_u64((u64) (u32) stime * (u64) (u32) rtime, (u32)total);
|
2017-01-31 11:09:23 +08:00
|
|
|
return scaled;
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
|
|
|
|
2014-10-01 03:59:47 +08:00
|
|
|
/*
|
2015-06-30 17:30:54 +08:00
|
|
|
* Adjust tick based cputime random precision against scheduler runtime
|
|
|
|
* accounting.
|
2014-10-01 03:59:47 +08:00
|
|
|
*
|
2015-06-30 17:30:54 +08:00
|
|
|
* Tick based cputime accounting depend on random scheduling timeslices of a
|
|
|
|
* task to be interrupted or not by the timer. Depending on these
|
|
|
|
* circumstances, the number of these interrupts may be over or
|
|
|
|
* under-optimistic, matching the real user and system cputime with a variable
|
|
|
|
* precision.
|
|
|
|
*
|
|
|
|
* Fix this by scaling these tick based values against the total runtime
|
|
|
|
* accounted by the CFS scheduler.
|
|
|
|
*
|
|
|
|
* This code provides the following guarantees:
|
|
|
|
*
|
|
|
|
* stime + utime == rtime
|
|
|
|
* stime_i+1 >= stime_i, utime_i+1 >= utime_i
|
|
|
|
*
|
|
|
|
* Assuming that rtime_i+1 >= rtime_i.
|
2012-11-29 00:00:57 +08:00
|
|
|
*/
|
2012-11-22 07:58:35 +08:00
|
|
|
static void cputime_adjust(struct task_cputime *curr,
|
2015-06-30 17:30:54 +08:00
|
|
|
struct prev_cputime *prev,
|
2017-01-31 11:09:23 +08:00
|
|
|
u64 *ut, u64 *st)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
2017-01-31 11:09:23 +08:00
|
|
|
u64 rtime, stime, utime;
|
2015-06-30 17:30:54 +08:00
|
|
|
unsigned long flags;
|
2012-11-29 00:00:57 +08:00
|
|
|
|
2015-06-30 17:30:54 +08:00
|
|
|
/* Serialize concurrent callers such that we can honour our guarantees */
|
|
|
|
raw_spin_lock_irqsave(&prev->lock, flags);
|
2017-01-31 11:09:23 +08:00
|
|
|
rtime = curr->sum_exec_runtime;
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2013-04-30 17:35:05 +08:00
|
|
|
/*
|
2015-06-30 17:30:54 +08:00
|
|
|
* This is possible under two circumstances:
|
|
|
|
* - rtime isn't monotonic after all (a bug);
|
|
|
|
* - we got reordered by the lock.
|
|
|
|
*
|
|
|
|
* In both cases this acts as a filter such that the rest of the code
|
|
|
|
* can assume it is monotonic regardless of anything else.
|
2013-04-30 17:35:05 +08:00
|
|
|
*/
|
|
|
|
if (prev->stime + prev->utime >= rtime)
|
|
|
|
goto out;
|
|
|
|
|
2013-09-04 21:16:03 +08:00
|
|
|
stime = curr->stime;
|
|
|
|
utime = curr->utime;
|
|
|
|
|
2016-08-16 00:38:42 +08:00
|
|
|
/*
|
2017-07-04 17:53:40 +08:00
|
|
|
* If either stime or utime are 0, assume all runtime is userspace.
|
|
|
|
* Once a task gets some ticks, the monotonicy code at 'update:'
|
|
|
|
* will ensure things converge to the observed ratio.
|
2016-08-16 00:38:42 +08:00
|
|
|
*/
|
2017-07-04 17:53:40 +08:00
|
|
|
if (stime == 0) {
|
|
|
|
utime = rtime;
|
|
|
|
goto update;
|
2015-06-30 17:30:54 +08:00
|
|
|
}
|
2013-09-04 21:16:03 +08:00
|
|
|
|
2017-07-04 17:53:40 +08:00
|
|
|
if (utime == 0) {
|
|
|
|
stime = rtime;
|
|
|
|
goto update;
|
|
|
|
}
|
|
|
|
|
|
|
|
stime = scale_stime(stime, rtime, stime + utime);
|
|
|
|
|
|
|
|
update:
|
2015-06-30 17:30:54 +08:00
|
|
|
/*
|
|
|
|
* Make sure stime doesn't go backwards; this preserves monotonicity
|
|
|
|
* for utime because rtime is monotonic.
|
|
|
|
*
|
|
|
|
* utime_i+1 = rtime_i+1 - stime_i
|
|
|
|
* = rtime_i+1 - (rtime_i - utime_i)
|
|
|
|
* = (rtime_i+1 - rtime_i) + utime_i
|
|
|
|
* >= utime_i
|
|
|
|
*/
|
|
|
|
if (stime < prev->stime)
|
|
|
|
stime = prev->stime;
|
|
|
|
utime = rtime - stime;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure utime doesn't go backwards; this still preserves
|
|
|
|
* monotonicity for stime, analogous argument to above.
|
|
|
|
*/
|
|
|
|
if (utime < prev->utime) {
|
|
|
|
utime = prev->utime;
|
|
|
|
stime = rtime - utime;
|
|
|
|
}
|
2012-11-22 07:58:35 +08:00
|
|
|
|
2015-06-30 17:30:54 +08:00
|
|
|
prev->stime = stime;
|
|
|
|
prev->utime = utime;
|
2013-04-30 17:35:05 +08:00
|
|
|
out:
|
2012-11-22 07:58:35 +08:00
|
|
|
*ut = prev->utime;
|
|
|
|
*st = prev->stime;
|
2015-06-30 17:30:54 +08:00
|
|
|
raw_spin_unlock_irqrestore(&prev->lock, flags);
|
2012-11-22 07:58:35 +08:00
|
|
|
}
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:23 +08:00
|
|
|
void task_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
|
2012-11-22 07:58:35 +08:00
|
|
|
{
|
|
|
|
struct task_cputime cputime = {
|
|
|
|
.sum_exec_runtime = p->se.sum_exec_runtime,
|
|
|
|
};
|
|
|
|
|
2012-11-13 21:20:55 +08:00
|
|
|
task_cputime(p, &cputime.utime, &cputime.stime);
|
2012-11-22 07:58:35 +08:00
|
|
|
cputime_adjust(&cputime, &p->prev_cputime, ut, st);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
2015-09-16 17:29:50 +08:00
|
|
|
EXPORT_SYMBOL_GPL(task_cputime_adjusted);
|
2012-06-16 21:57:37 +08:00
|
|
|
|
2017-01-31 11:09:23 +08:00
|
|
|
void thread_group_cputime_adjusted(struct task_struct *p, u64 *ut, u64 *st)
|
2012-06-16 21:57:37 +08:00
|
|
|
{
|
|
|
|
struct task_cputime cputime;
|
|
|
|
|
|
|
|
thread_group_cputime(p, &cputime);
|
2012-11-22 07:58:35 +08:00
|
|
|
cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st);
|
2012-06-16 21:57:37 +08:00
|
|
|
}
|
2013-02-26 00:25:39 +08:00
|
|
|
#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
|
2012-07-25 13:56:04 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
|
2017-06-30 01:15:10 +08:00
|
|
|
static u64 vtime_delta(struct vtime *vtime)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:11 +08:00
|
|
|
unsigned long long clock;
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2017-06-30 01:15:11 +08:00
|
|
|
clock = sched_clock_cpu(smp_processor_id());
|
|
|
|
if (clock < vtime->starttime)
|
2012-12-17 03:00:34 +08:00
|
|
|
return 0;
|
2012-07-25 13:56:04 +08:00
|
|
|
|
2017-06-30 01:15:11 +08:00
|
|
|
return clock - vtime->starttime;
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
2017-06-30 01:15:10 +08:00
|
|
|
static u64 get_vtime_delta(struct vtime *vtime)
|
2012-07-25 13:56:04 +08:00
|
|
|
{
|
2017-06-30 01:15:11 +08:00
|
|
|
u64 delta = vtime_delta(vtime);
|
|
|
|
u64 other;
|
2012-07-25 13:56:04 +08:00
|
|
|
|
sched/cputime: Resync steal time when guest & host lose sync
Commit:
57430218317e ("sched/cputime: Count actually elapsed irq & softirq time")
... fixed a bug but also triggered a regression:
On an i5 laptop, 4 pCPUs, 4vCPUs for one full dynticks guest, there are four
CPU hog processes(for loop) running in the guest, I hot-unplug the pCPUs
on host one by one until there is only one left, then observe CPU utilization
via 'top' in the guest, it shows:
100% st for cpu0(housekeeping)
75% st for other CPUs (nohz full mode)
However, w/o this commit it shows the correct 75% for all four CPUs.
When a guest is interrupted for a longer amount of time, missed clock ticks
are not redelivered later. Because of that, we should not limit the amount
of steal time accounted to the amount of time that the calling functions
think have passed.
However, the interval returned by account_other_time() is NOT rounded down
to the nearest jiffy, while the base interval in get_vtime_delta() it is
subtracted from is, so the max cputime limit is required to avoid underflow.
This patch fixes the regression by limiting the account_other_time() from
get_vtime_delta() to avoid underflow, and lets the other three call sites
(in account_other_time() and steal_account_process_time()) account however
much steal time the host told us elapsed.
Suggested-by: Rik van Riel <riel@redhat.com>
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
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: Radim Krcmar <rkrcmar@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: kvm@vger.kernel.org
Link: http://lkml.kernel.org/r/1471399546-4069-1-git-send-email-wanpeng.li@hotmail.com
[ Improved the changelog. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-08-17 10:05:46 +08:00
|
|
|
/*
|
|
|
|
* Unlike tick based timing, vtime based timing never has lost
|
|
|
|
* ticks, and no need for steal time accounting to make up for
|
|
|
|
* lost ticks. Vtime accounts a rounded version of actual
|
|
|
|
* elapsed time. Limit account_other_time to prevent rounding
|
|
|
|
* errors from causing elapsed vtime to go negative.
|
|
|
|
*/
|
2016-07-13 22:50:02 +08:00
|
|
|
other = account_other_time(delta);
|
2017-06-30 01:15:10 +08:00
|
|
|
WARN_ON_ONCE(vtime->state == VTIME_INACTIVE);
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime->starttime += delta;
|
2012-07-25 13:56:04 +08:00
|
|
|
|
2016-07-13 22:50:02 +08:00
|
|
|
return delta - other;
|
2012-07-25 13:56:04 +08:00
|
|
|
}
|
|
|
|
|
2017-06-30 01:15:11 +08:00
|
|
|
static void __vtime_account_system(struct task_struct *tsk,
|
|
|
|
struct vtime *vtime)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime->stime += get_vtime_delta(vtime);
|
|
|
|
if (vtime->stime >= TICK_NSEC) {
|
|
|
|
account_system_time(tsk, irq_count(), vtime->stime);
|
|
|
|
vtime->stime = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vtime_account_guest(struct task_struct *tsk,
|
|
|
|
struct vtime *vtime)
|
|
|
|
{
|
|
|
|
vtime->gtime += get_vtime_delta(vtime);
|
|
|
|
if (vtime->gtime >= TICK_NSEC) {
|
|
|
|
account_guest_time(tsk, vtime->gtime);
|
|
|
|
vtime->gtime = 0;
|
|
|
|
}
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
2012-07-25 13:56:04 +08:00
|
|
|
void vtime_account_system(struct task_struct *tsk)
|
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &tsk->vtime;
|
|
|
|
|
|
|
|
if (!vtime_delta(vtime))
|
sched, time: Switch VIRT_CPU_ACCOUNTING_GEN to jiffy granularity
When profiling syscall overhead on nohz-full kernels,
after removing __acct_update_integrals() from the profile,
native_sched_clock() remains as the top CPU user. This can be
reduced by moving VIRT_CPU_ACCOUNTING_GEN to jiffy granularity.
This will reduce timing accuracy on nohz_full CPUs to jiffy
based sampling, just like on normal CPUs. It results in
totally removing native_sched_clock from the profile, and
significantly speeding up the syscall entry and exit path,
as well as irq entry and exit, and KVM guest entry & exit.
Additionally, only call the more expensive functions (and
advance the seqlock) when jiffies actually changed.
This code relies on another CPU advancing jiffies when the
system is busy. On a nohz_full system, this is done by a
housekeeping CPU.
A microbenchmark calling an invalid syscall number 10 million
times in a row speeds up an additional 30% over the numbers
with just the previous patches, for a total speedup of about
40% over 4.4 and 4.5-rc1.
Run times for the microbenchmark:
4.4 3.8 seconds
4.5-rc1 3.7 seconds
4.5-rc1 + first patch 3.3 seconds
4.5-rc1 + first 3 patches 3.1 seconds
4.5-rc1 + all patches 2.3 seconds
A non-NOHZ_FULL cpu (not the housekeeping CPU):
all kernels 1.86 seconds
Signed-off-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: clark@redhat.com
Cc: eric.dumazet@gmail.com
Cc: fweisbec@gmail.com
Cc: luto@amacapital.net
Link: http://lkml.kernel.org/r/1455152907-18495-5-git-send-email-riel@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-02-11 09:08:27 +08:00
|
|
|
return;
|
|
|
|
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
2017-06-30 01:15:11 +08:00
|
|
|
/* We might have scheduled out from guest path */
|
|
|
|
if (current->flags & PF_VCPU)
|
|
|
|
vtime_account_guest(tsk, vtime);
|
|
|
|
else
|
|
|
|
__vtime_account_system(tsk, vtime);
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
2012-07-17 00:00:34 +08:00
|
|
|
|
2017-06-30 01:15:07 +08:00
|
|
|
void vtime_user_enter(struct task_struct *tsk)
|
2012-07-25 13:56:04 +08:00
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &tsk->vtime;
|
|
|
|
|
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
2017-06-30 01:15:11 +08:00
|
|
|
__vtime_account_system(tsk, vtime);
|
2017-06-30 01:15:10 +08:00
|
|
|
vtime->state = VTIME_USER;
|
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
2017-06-30 01:15:07 +08:00
|
|
|
void vtime_user_exit(struct task_struct *tsk)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &tsk->vtime;
|
|
|
|
|
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime->utime += get_vtime_delta(vtime);
|
|
|
|
if (vtime->utime >= TICK_NSEC) {
|
|
|
|
account_user_time(tsk, vtime->utime);
|
|
|
|
vtime->utime = 0;
|
|
|
|
}
|
2017-06-30 01:15:10 +08:00
|
|
|
vtime->state = VTIME_SYS;
|
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void vtime_guest_enter(struct task_struct *tsk)
|
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &tsk->vtime;
|
2013-07-13 01:05:14 +08:00
|
|
|
/*
|
|
|
|
* The flags must be updated under the lock with
|
2017-06-30 01:15:09 +08:00
|
|
|
* the vtime_starttime flush and update.
|
2013-07-13 01:05:14 +08:00
|
|
|
* That enforces a right ordering and update sequence
|
|
|
|
* synchronization against the reader (task_gtime())
|
|
|
|
* that can thus safely catch up with a tickless delta.
|
|
|
|
*/
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
2017-06-30 01:15:11 +08:00
|
|
|
__vtime_account_system(tsk, vtime);
|
2012-12-17 03:00:34 +08:00
|
|
|
current->flags |= PF_VCPU;
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
2013-07-10 08:44:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(vtime_guest_enter);
|
2012-12-17 03:00:34 +08:00
|
|
|
|
|
|
|
void vtime_guest_exit(struct task_struct *tsk)
|
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &tsk->vtime;
|
|
|
|
|
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime_account_guest(tsk, vtime);
|
2012-12-17 03:00:34 +08:00
|
|
|
current->flags &= ~PF_VCPU;
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-07-25 13:56:04 +08:00
|
|
|
}
|
2013-07-10 08:44:35 +08:00
|
|
|
EXPORT_SYMBOL_GPL(vtime_guest_exit);
|
2012-07-25 13:56:04 +08:00
|
|
|
|
|
|
|
void vtime_account_idle(struct task_struct *tsk)
|
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
account_idle_time(get_vtime_delta(&tsk->vtime));
|
2012-07-25 13:56:04 +08:00
|
|
|
}
|
2012-07-17 00:00:34 +08:00
|
|
|
|
2012-12-17 03:00:34 +08:00
|
|
|
void arch_vtime_task_switch(struct task_struct *prev)
|
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &prev->vtime;
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
|
|
|
vtime->state = VTIME_INACTIVE;
|
|
|
|
write_seqcount_end(&vtime->seqcount);
|
|
|
|
|
|
|
|
vtime = ¤t->vtime;
|
|
|
|
|
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
|
|
|
vtime->state = VTIME_SYS;
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime->starttime = sched_clock_cpu(smp_processor_id());
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
2013-05-16 04:16:32 +08:00
|
|
|
void vtime_init_idle(struct task_struct *t, int cpu)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &t->vtime;
|
2012-12-17 03:00:34 +08:00
|
|
|
unsigned long flags;
|
|
|
|
|
2015-11-19 23:47:34 +08:00
|
|
|
local_irq_save(flags);
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_begin(&vtime->seqcount);
|
|
|
|
vtime->state = VTIME_SYS;
|
2017-06-30 01:15:11 +08:00
|
|
|
vtime->starttime = sched_clock_cpu(cpu);
|
2017-06-30 01:15:10 +08:00
|
|
|
write_seqcount_end(&vtime->seqcount);
|
2015-11-19 23:47:34 +08:00
|
|
|
local_irq_restore(flags);
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
|
|
|
|
2017-01-31 11:09:21 +08:00
|
|
|
u64 task_gtime(struct task_struct *t)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &t->vtime;
|
2012-12-17 03:00:34 +08:00
|
|
|
unsigned int seq;
|
2017-01-31 11:09:21 +08:00
|
|
|
u64 gtime;
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2015-11-19 23:47:33 +08:00
|
|
|
if (!vtime_accounting_enabled())
|
2015-11-19 23:47:28 +08:00
|
|
|
return t->gtime;
|
|
|
|
|
2012-12-17 03:00:34 +08:00
|
|
|
do {
|
2017-06-30 01:15:10 +08:00
|
|
|
seq = read_seqcount_begin(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
|
|
|
|
gtime = t->gtime;
|
2017-06-30 01:15:10 +08:00
|
|
|
if (vtime->state == VTIME_SYS && t->flags & PF_VCPU)
|
2017-06-30 01:15:11 +08:00
|
|
|
gtime += vtime->gtime + vtime_delta(vtime);
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2017-06-30 01:15:10 +08:00
|
|
|
} while (read_seqcount_retry(&vtime->seqcount, seq));
|
2012-12-17 03:00:34 +08:00
|
|
|
|
|
|
|
return gtime;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch cputime raw values from fields of task_struct and
|
|
|
|
* add up the pending nohz execution time since the last
|
|
|
|
* cputime snapshot.
|
|
|
|
*/
|
2017-01-31 11:09:23 +08:00
|
|
|
void task_cputime(struct task_struct *t, u64 *utime, u64 *stime)
|
2012-12-17 03:00:34 +08:00
|
|
|
{
|
2017-06-30 01:15:10 +08:00
|
|
|
struct vtime *vtime = &t->vtime;
|
2012-12-17 03:00:34 +08:00
|
|
|
unsigned int seq;
|
2017-06-30 01:15:10 +08:00
|
|
|
u64 delta;
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2016-11-15 10:06:52 +08:00
|
|
|
if (!vtime_accounting_enabled()) {
|
|
|
|
*utime = t->utime;
|
|
|
|
*stime = t->stime;
|
|
|
|
return;
|
|
|
|
}
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2016-11-15 10:06:52 +08:00
|
|
|
do {
|
2017-06-30 01:15:10 +08:00
|
|
|
seq = read_seqcount_begin(&vtime->seqcount);
|
2012-12-17 03:00:34 +08:00
|
|
|
|
2016-11-15 10:06:52 +08:00
|
|
|
*utime = t->utime;
|
|
|
|
*stime = t->stime;
|
2012-12-17 03:00:34 +08:00
|
|
|
|
|
|
|
/* Task is sleeping, nothing to add */
|
2017-06-30 01:15:10 +08:00
|
|
|
if (vtime->state == VTIME_INACTIVE || is_idle_task(t))
|
2012-12-17 03:00:34 +08:00
|
|
|
continue;
|
|
|
|
|
2017-06-30 01:15:10 +08:00
|
|
|
delta = vtime_delta(vtime);
|
2012-12-17 03:00:34 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Task runs either in user or kernel space, add pending nohz time to
|
|
|
|
* the right place.
|
|
|
|
*/
|
2017-06-30 01:15:10 +08:00
|
|
|
if (vtime->state == VTIME_USER || t->flags & PF_VCPU)
|
2017-06-30 01:15:11 +08:00
|
|
|
*utime += vtime->utime + delta;
|
2017-06-30 01:15:10 +08:00
|
|
|
else if (vtime->state == VTIME_SYS)
|
2017-06-30 01:15:11 +08:00
|
|
|
*stime += vtime->stime + delta;
|
2017-06-30 01:15:10 +08:00
|
|
|
} while (read_seqcount_retry(&vtime->seqcount, seq));
|
2012-12-17 03:00:34 +08:00
|
|
|
}
|
2012-07-25 13:56:04 +08:00
|
|
|
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
|