nohz: Introduce arch_needs_cpu
Allow the architecture to request a normal jiffy tick when the system goes idle and tick_nohz_stop_sched_tick is called . On s390 the hook is used to prevent the system going fully idle if there has been an interrupt other than a clock comparator interrupt since the last wakeup. On s390 the HiperSockets response time for 1 connection ping-pong goes down from 42 to 34 microseconds. The CPU cost decreases by 27%. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> LKML-Reference: <20090929122533.402715150@de.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
eed3b9cf3f
commit
3c5d92a0cf
|
@ -183,6 +183,7 @@ struct s390_idle_data {
|
||||||
unsigned long long idle_count;
|
unsigned long long idle_count;
|
||||||
unsigned long long idle_enter;
|
unsigned long long idle_enter;
|
||||||
unsigned long long idle_time;
|
unsigned long long idle_time;
|
||||||
|
int nohz_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
|
DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
|
||||||
|
@ -198,4 +199,11 @@ static inline void s390_idle_check(void)
|
||||||
vtime_start_cpu();
|
vtime_start_cpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int s390_nohz_delay(int cpu)
|
||||||
|
{
|
||||||
|
return per_cpu(s390_idle, cpu).nohz_delay != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define arch_needs_cpu(cpu) s390_nohz_delay(cpu)
|
||||||
|
|
||||||
#endif /* _S390_CPUTIME_H */
|
#endif /* _S390_CPUTIME_H */
|
||||||
|
|
|
@ -126,6 +126,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
|
||||||
/* Serve timer interrupts first. */
|
/* Serve timer interrupts first. */
|
||||||
clock_comparator_work();
|
clock_comparator_work();
|
||||||
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
|
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
|
||||||
|
if (code != 0x1004)
|
||||||
|
__get_cpu_var(s390_idle).nohz_delay = 1;
|
||||||
index = ext_hash(code);
|
index = ext_hash(code);
|
||||||
for (p = ext_int_hash[index]; p; p = p->next) {
|
for (p = ext_int_hash[index]; p; p = p->next) {
|
||||||
if (likely(p->code == code))
|
if (likely(p->code == code))
|
||||||
|
|
|
@ -167,6 +167,8 @@ void vtime_stop_cpu(void)
|
||||||
/* Wait for external, I/O or machine check interrupt. */
|
/* Wait for external, I/O or machine check interrupt. */
|
||||||
psw.mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_IO | PSW_MASK_EXT;
|
psw.mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_IO | PSW_MASK_EXT;
|
||||||
|
|
||||||
|
idle->nohz_delay = 0;
|
||||||
|
|
||||||
/* Check if the CPU timer needs to be reprogrammed. */
|
/* Check if the CPU timer needs to be reprogrammed. */
|
||||||
if (vq->do_spt) {
|
if (vq->do_spt) {
|
||||||
__u64 vmax = VTIMER_MAX_SLICE;
|
__u64 vmax = VTIMER_MAX_SLICE;
|
||||||
|
|
|
@ -618,6 +618,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
|
||||||
old_regs = set_irq_regs(regs);
|
old_regs = set_irq_regs(regs);
|
||||||
s390_idle_check();
|
s390_idle_check();
|
||||||
irq_enter();
|
irq_enter();
|
||||||
|
__get_cpu_var(s390_idle).nohz_delay = 1;
|
||||||
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
|
if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
|
||||||
/* Serve timer interrupts first. */
|
/* Serve timer interrupts first. */
|
||||||
clock_comparator_work();
|
clock_comparator_work();
|
||||||
|
|
|
@ -98,6 +98,9 @@ extern int tick_check_oneshot_change(int allow_nohz);
|
||||||
extern struct tick_sched *tick_get_tick_sched(int cpu);
|
extern struct tick_sched *tick_get_tick_sched(int cpu);
|
||||||
extern void tick_check_idle(int cpu);
|
extern void tick_check_idle(int cpu);
|
||||||
extern int tick_oneshot_mode_active(void);
|
extern int tick_oneshot_mode_active(void);
|
||||||
|
# ifndef arch_needs_cpu
|
||||||
|
# define arch_needs_cpu(cpu) (0)
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
static inline void tick_clock_notify(void) { }
|
static inline void tick_clock_notify(void) { }
|
||||||
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
|
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
|
||||||
|
|
|
@ -264,12 +264,15 @@ void tick_nohz_stop_sched_tick(int inidle)
|
||||||
last_jiffies = jiffies;
|
last_jiffies = jiffies;
|
||||||
} while (read_seqretry(&xtime_lock, seq));
|
} while (read_seqretry(&xtime_lock, seq));
|
||||||
|
|
||||||
/* Get the next timer wheel timer */
|
if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) ||
|
||||||
next_jiffies = get_next_timer_interrupt(last_jiffies);
|
arch_needs_cpu(cpu)) {
|
||||||
delta_jiffies = next_jiffies - last_jiffies;
|
next_jiffies = last_jiffies + 1;
|
||||||
|
|
||||||
if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu))
|
|
||||||
delta_jiffies = 1;
|
delta_jiffies = 1;
|
||||||
|
} else {
|
||||||
|
/* Get the next timer wheel timer */
|
||||||
|
next_jiffies = get_next_timer_interrupt(last_jiffies);
|
||||||
|
delta_jiffies = next_jiffies - last_jiffies;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Do not stop the tick, if we are only one off
|
* Do not stop the tick, if we are only one off
|
||||||
* or if the cpu is required for rcu
|
* or if the cpu is required for rcu
|
||||||
|
|
Loading…
Reference in New Issue