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:
Martin Schwidefsky 2009-09-29 14:25:16 +02:00 committed by Thomas Gleixner
parent eed3b9cf3f
commit 3c5d92a0cf
6 changed files with 24 additions and 5 deletions

View File

@ -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 */

View File

@ -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))

View File

@ -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;

View File

@ -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();

View File

@ -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; }

View File

@ -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