mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 03:24:19 +02:00
Merge branch 'idle-vtime-fixes-cleanups' into fixes
Pull a small idle/vtime series with two cputime accounting fixes plus related cleanups and minor improvements. * idle-vtime-fixes-cleanups: s390/idle: Remove psw_idle() prototype s390/vtime: Use lockdep_assert_irqs_disabled() instead of BUG_ON() s390/vtime: Use __this_cpu_read() / get rid of READ_ONCE() s390/irq/idle: Remove psw bits early s390/idle: Inline update_timer_idle() s390/idle: Slightly optimize idle time accounting s390/idle: Add comment for non obvious code s390/vtime: Fix virtual timer forwarding s390/idle: Fix cpu idle exit cpu time accounting Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
commit
05c58a6605
|
|
@ -19,9 +19,9 @@ struct s390_idle_data {
|
|||
unsigned long mt_cycles_enter[8];
|
||||
};
|
||||
|
||||
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
|
||||
|
||||
extern struct device_attribute dev_attr_idle_count;
|
||||
extern struct device_attribute dev_attr_idle_time_us;
|
||||
|
||||
void psw_idle(struct s390_idle_data *data, unsigned long psw_mask);
|
||||
|
||||
#endif /* _S390_IDLE_H */
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
#ifndef _S390_VTIME_H
|
||||
#define _S390_VTIME_H
|
||||
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/cpu_mf.h>
|
||||
#include <asm/idle.h>
|
||||
|
||||
DECLARE_PER_CPU(u64, mt_cycles[8]);
|
||||
|
||||
static inline void update_timer_sys(void)
|
||||
{
|
||||
struct lowcore *lc = get_lowcore();
|
||||
|
|
@ -20,4 +26,32 @@ static inline void update_timer_mcck(void)
|
|||
lc->last_update_timer = lc->mcck_enter_timer;
|
||||
}
|
||||
|
||||
static inline void update_timer_idle(void)
|
||||
{
|
||||
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
||||
struct lowcore *lc = get_lowcore();
|
||||
u64 cycles_new[8];
|
||||
int i, mtid;
|
||||
|
||||
mtid = smp_cpu_mtid;
|
||||
if (mtid) {
|
||||
stcctm(MT_DIAG, mtid, cycles_new);
|
||||
for (i = 0; i < mtid; i++)
|
||||
__this_cpu_add(mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]);
|
||||
}
|
||||
/*
|
||||
* This is a bit subtle: Forward last_update_clock so it excludes idle
|
||||
* time. For correct steal time calculation in do_account_vtime() add
|
||||
* passed wall time before idle_enter to steal_timer:
|
||||
* During the passed wall time before idle_enter CPU time may have
|
||||
* been accounted to system, hardirq, softirq, etc. lowcore fields.
|
||||
* The accounted CPU times will be subtracted again from steal_timer
|
||||
* when accumulated steal time is calculated in do_account_vtime().
|
||||
*/
|
||||
lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
|
||||
lc->last_update_clock = lc->int_clock;
|
||||
lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
|
||||
lc->last_update_timer = lc->sys_enter_timer;
|
||||
}
|
||||
|
||||
#endif /* _S390_VTIME_H */
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t);
|
|||
long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t);
|
||||
long sys_s390_sthyi(unsigned long function_code, void __user *buffer, u64 __user *return_code, unsigned long flags);
|
||||
|
||||
DECLARE_PER_CPU(u64, mt_cycles[8]);
|
||||
|
||||
unsigned long stack_alloc(void);
|
||||
void stack_free(unsigned long stack);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,37 +15,22 @@
|
|||
#include <trace/events/power.h>
|
||||
#include <asm/cpu_mf.h>
|
||||
#include <asm/cputime.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/nmi.h>
|
||||
#include <asm/smp.h>
|
||||
#include "entry.h"
|
||||
|
||||
static DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
|
||||
DEFINE_PER_CPU(struct s390_idle_data, s390_idle);
|
||||
|
||||
void account_idle_time_irq(void)
|
||||
{
|
||||
struct s390_idle_data *idle = this_cpu_ptr(&s390_idle);
|
||||
struct lowcore *lc = get_lowcore();
|
||||
unsigned long idle_time;
|
||||
u64 cycles_new[8];
|
||||
int i;
|
||||
|
||||
if (smp_cpu_mtid) {
|
||||
stcctm(MT_DIAG, smp_cpu_mtid, cycles_new);
|
||||
for (i = 0; i < smp_cpu_mtid; i++)
|
||||
this_cpu_add(mt_cycles[i], cycles_new[i] - idle->mt_cycles_enter[i]);
|
||||
}
|
||||
|
||||
idle_time = lc->int_clock - idle->clock_idle_enter;
|
||||
|
||||
lc->steal_timer += idle->clock_idle_enter - lc->last_update_clock;
|
||||
lc->last_update_clock = lc->int_clock;
|
||||
|
||||
lc->system_timer += lc->last_update_timer - idle->timer_idle_enter;
|
||||
lc->last_update_timer = lc->sys_enter_timer;
|
||||
idle_time = get_lowcore()->int_clock - idle->clock_idle_enter;
|
||||
|
||||
/* Account time spent with enabled wait psw loaded as idle time. */
|
||||
WRITE_ONCE(idle->idle_time, READ_ONCE(idle->idle_time) + idle_time);
|
||||
WRITE_ONCE(idle->idle_count, READ_ONCE(idle->idle_count) + 1);
|
||||
__atomic64_add(idle_time, &idle->idle_time);
|
||||
__atomic64_add_const(1, &idle->idle_count);
|
||||
account_idle_time(cputime_to_nsecs(idle_time));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,6 +146,12 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
|||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
bool from_idle;
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle) {
|
||||
update_timer_idle();
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
irq_enter_rcu();
|
||||
|
||||
if (user_mode(regs)) {
|
||||
|
|
@ -154,7 +160,6 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
|||
current->thread.last_break = regs->last_break;
|
||||
}
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle)
|
||||
account_idle_time_irq();
|
||||
|
||||
|
|
@ -171,9 +176,6 @@ void noinstr do_io_irq(struct pt_regs *regs)
|
|||
|
||||
set_irq_regs(old_regs);
|
||||
irqentry_exit(regs, state);
|
||||
|
||||
if (from_idle)
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
void noinstr do_ext_irq(struct pt_regs *regs)
|
||||
|
|
@ -182,6 +184,12 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
|||
struct pt_regs *old_regs = set_irq_regs(regs);
|
||||
bool from_idle;
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle) {
|
||||
update_timer_idle();
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
irq_enter_rcu();
|
||||
|
||||
if (user_mode(regs)) {
|
||||
|
|
@ -194,7 +202,6 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
|||
regs->int_parm = get_lowcore()->ext_params;
|
||||
regs->int_parm_long = get_lowcore()->ext_params2;
|
||||
|
||||
from_idle = test_and_clear_cpu_flag(CIF_ENABLED_WAIT);
|
||||
if (from_idle)
|
||||
account_idle_time_irq();
|
||||
|
||||
|
|
@ -203,9 +210,6 @@ void noinstr do_ext_irq(struct pt_regs *regs)
|
|||
irq_exit_rcu();
|
||||
set_irq_regs(old_regs);
|
||||
irqentry_exit(regs, state);
|
||||
|
||||
if (from_idle)
|
||||
regs->psw.mask &= ~(PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_WAIT);
|
||||
}
|
||||
|
||||
static void show_msi_interrupt(struct seq_file *p, int irq)
|
||||
|
|
|
|||
|
|
@ -48,8 +48,7 @@ static inline void set_vtimer(u64 expires)
|
|||
|
||||
static inline int virt_timer_forward(u64 elapsed)
|
||||
{
|
||||
BUG_ON(!irqs_disabled());
|
||||
|
||||
lockdep_assert_irqs_disabled();
|
||||
if (list_empty(&virt_timer_list))
|
||||
return 0;
|
||||
elapsed = atomic64_add_return(elapsed, &virt_timer_elapsed);
|
||||
|
|
@ -137,23 +136,16 @@ static int do_account_vtime(struct task_struct *tsk)
|
|||
lc->system_timer += timer;
|
||||
|
||||
/* Update MT utilization calculation */
|
||||
if (smp_cpu_mtid &&
|
||||
time_after64(jiffies_64, this_cpu_read(mt_scaling_jiffies)))
|
||||
if (smp_cpu_mtid && time_after64(jiffies_64, __this_cpu_read(mt_scaling_jiffies)))
|
||||
update_mt_scaling();
|
||||
|
||||
/* Calculate cputime delta */
|
||||
user = update_tsk_timer(&tsk->thread.user_timer,
|
||||
READ_ONCE(lc->user_timer));
|
||||
guest = update_tsk_timer(&tsk->thread.guest_timer,
|
||||
READ_ONCE(lc->guest_timer));
|
||||
system = update_tsk_timer(&tsk->thread.system_timer,
|
||||
READ_ONCE(lc->system_timer));
|
||||
hardirq = update_tsk_timer(&tsk->thread.hardirq_timer,
|
||||
READ_ONCE(lc->hardirq_timer));
|
||||
softirq = update_tsk_timer(&tsk->thread.softirq_timer,
|
||||
READ_ONCE(lc->softirq_timer));
|
||||
lc->steal_timer +=
|
||||
clock - user - guest - system - hardirq - softirq;
|
||||
user = update_tsk_timer(&tsk->thread.user_timer, lc->user_timer);
|
||||
guest = update_tsk_timer(&tsk->thread.guest_timer, lc->guest_timer);
|
||||
system = update_tsk_timer(&tsk->thread.system_timer, lc->system_timer);
|
||||
hardirq = update_tsk_timer(&tsk->thread.hardirq_timer, lc->hardirq_timer);
|
||||
softirq = update_tsk_timer(&tsk->thread.softirq_timer, lc->softirq_timer);
|
||||
lc->steal_timer += clock - user - guest - system - hardirq - softirq;
|
||||
|
||||
/* Push account value */
|
||||
if (user) {
|
||||
|
|
@ -225,10 +217,6 @@ static u64 vtime_delta(void)
|
|||
return timer - lc->last_update_timer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update process times based on virtual cpu times stored by entry.S
|
||||
* to the lowcore fields user_timer, system_timer & steal_clock.
|
||||
*/
|
||||
void vtime_account_kernel(struct task_struct *tsk)
|
||||
{
|
||||
struct lowcore *lc = get_lowcore();
|
||||
|
|
@ -238,27 +226,17 @@ void vtime_account_kernel(struct task_struct *tsk)
|
|||
lc->guest_timer += delta;
|
||||
else
|
||||
lc->system_timer += delta;
|
||||
|
||||
virt_timer_forward(delta);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vtime_account_kernel);
|
||||
|
||||
void vtime_account_softirq(struct task_struct *tsk)
|
||||
{
|
||||
u64 delta = vtime_delta();
|
||||
|
||||
get_lowcore()->softirq_timer += delta;
|
||||
|
||||
virt_timer_forward(delta);
|
||||
get_lowcore()->softirq_timer += vtime_delta();
|
||||
}
|
||||
|
||||
void vtime_account_hardirq(struct task_struct *tsk)
|
||||
{
|
||||
u64 delta = vtime_delta();
|
||||
|
||||
get_lowcore()->hardirq_timer += delta;
|
||||
|
||||
virt_timer_forward(delta);
|
||||
get_lowcore()->hardirq_timer += vtime_delta();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user