nohz: Introduce arch_needs_cpu
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 29 Sep 2009 12:25:16 +0000 (14:25 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 5 Nov 2009 06:53:53 +0000 (07:53 +0100)
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>
arch/s390/include/asm/cputime.h
arch/s390/kernel/s390_ext.c
arch/s390/kernel/vtime.c
drivers/s390/cio/cio.c
include/linux/tick.h
kernel/time/tick-sched.c

index 24b1244aadb9b632a5d605dababe7bff86f89893..95f3561517c7d43530db45aa93dd2eb2e7128acf 100644 (file)
@@ -183,6 +183,7 @@ struct s390_idle_data {
        unsigned long long idle_count;
        unsigned long long idle_enter;
        unsigned long long idle_time;
+       int nohz_delay;
 };
 
 DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
@@ -198,4 +199,11 @@ static inline void s390_idle_check(void)
                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 */
index 0de305b598cee30a1352f67d4ded1eda4f0d3be0..59618bcd99b7a64bc8b9077b688d907ac73fc0d8 100644 (file)
@@ -126,6 +126,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code)
                /* Serve timer interrupts first. */
                clock_comparator_work();
        kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+       if (code != 0x1004)
+               __get_cpu_var(s390_idle).nohz_delay = 1;
         index = ext_hash(code);
        for (p = ext_int_hash[index]; p; p = p->next) {
                if (likely(p->code == code))
index c41bb0d416e1a25a56f50dde6d40f13a17cab125..b59a812a010e2b1bd0861e30ae3d662c45d3e04a 100644 (file)
@@ -167,6 +167,8 @@ void vtime_stop_cpu(void)
        /* Wait for external, I/O or machine check interrupt. */
        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. */
        if (vq->do_spt) {
                __u64 vmax = VTIMER_MAX_SLICE;
index 138124fcfcade55165aca7ee1088cad8d7ec74d7..126f240715a426ecdc115f3fc514173c1442d5cb 100644 (file)
@@ -618,6 +618,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        old_regs = set_irq_regs(regs);
        s390_idle_check();
        irq_enter();
+       __get_cpu_var(s390_idle).nohz_delay = 1;
        if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
                /* Serve timer interrupts first. */
                clock_comparator_work();
index 0482229c07db348636a9089722b69168a8b4dcc9..8dc082194b226a3485535fa09646e6f31ccc4558 100644 (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 void tick_check_idle(int cpu);
 extern int tick_oneshot_mode_active(void);
+#  ifndef arch_needs_cpu
+#   define arch_needs_cpu(cpu) (0)
+#  endif
 # else
 static inline void tick_clock_notify(void) { }
 static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
index 7378e2c71ca6cc73e3f348c36ba85a3761f303bb..3840f6dff7eb09dfdbd65c6b8609f0fa07c08548 100644 (file)
@@ -264,12 +264,15 @@ void tick_nohz_stop_sched_tick(int inidle)
                last_jiffies = jiffies;
        } while (read_seqretry(&xtime_lock, seq));
 
-       /* Get the next timer wheel timer */
-       next_jiffies = get_next_timer_interrupt(last_jiffies);
-       delta_jiffies = next_jiffies - last_jiffies;
-
-       if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu))
+       if (rcu_needs_cpu(cpu) || printk_needs_cpu(cpu) ||
+           arch_needs_cpu(cpu)) {
+               next_jiffies = last_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
         * or if the cpu is required for rcu