From: Martin Schwidefsky On a NOHZ system with oprofile enabled the timer tick should not be stopped when a cpu goes idle. Oprofile needs the pt_regs structure of the interrupt and allocates memory in the ring buffer for each sample. Current a maximum of 1 tick is accounted with oprofile if a cpu sleeps for a longer period of time. This does bad things to the percentages in the oprofile output. To postpone the oprofile tick to tick_nohz_restart_sched_tick analog to the in kernel profiler is not possible as there is no pt_regs structure in the context the tick_nohz_restart_sched_tick function is called and it is not a good idea to create hundreds of samples at once. Signed-off-by: Martin Schwidefsky --- drivers/oprofile/oprof.c | 3 +++ include/linux/tick.h | 4 ++++ kernel/time/tick-sched.c | 26 +++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) Index: quilt-2.6/drivers/oprofile/oprof.c =================================================================== --- quilt-2.6.orig/drivers/oprofile/oprof.c +++ quilt-2.6/drivers/oprofile/oprof.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include "oprof.h" @@ -103,6 +104,7 @@ int oprofile_start(void) if (oprofile_started) goto out; + tick_nohz_disable(); oprofile_reset_stats(); if ((err = oprofile_ops.start())) @@ -123,6 +125,7 @@ void oprofile_stop(void) goto out; oprofile_ops.stop(); oprofile_started = 0; + tick_nohz_enable(); /* wake up the daemon to read what remains */ wake_up_buffer_waiter(); out: Index: quilt-2.6/include/linux/tick.h =================================================================== --- quilt-2.6.orig/include/linux/tick.h +++ quilt-2.6/include/linux/tick.h @@ -117,6 +117,8 @@ extern void tick_nohz_stop_sched_tick(in extern void tick_nohz_restart_sched_tick(void); extern ktime_t tick_nohz_get_sleep_length(void); extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); +extern void tick_nohz_enable(void); +extern void tick_nohz_disable(void); # else static inline void tick_nohz_stop_sched_tick(int inidle) { } static inline void tick_nohz_restart_sched_tick(void) { } @@ -127,6 +129,8 @@ static inline ktime_t tick_nohz_get_slee return len; } static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } +static inline void tick_nohz_enable(void) { } +static inline void tick_nohz_disable(void) { } # endif /* !NO_HZ */ #endif Index: quilt-2.6/kernel/time/tick-sched.c =================================================================== --- quilt-2.6.orig/kernel/time/tick-sched.c +++ quilt-2.6/kernel/time/tick-sched.c @@ -124,6 +124,29 @@ static int __init setup_tick_nohz(char * __setup("nohz=", setup_tick_nohz); +/* + * NO HZ currently disabled ? + */ +static atomic_t tick_nohz_disable_counter = ATOMIC_INIT(0); + +void tick_nohz_enable(void) +{ + atomic_dec(&tick_nohz_disable_counter); +} +EXPORT_SYMBOL_GPL(tick_nohz_enable); + +static void __tick_nohz_disable(void *dummy) +{ +} + +void tick_nohz_disable(void) +{ + if (atomic_inc_return(&tick_nohz_disable_counter) == 1) + /* Wake up all cpus to make them start ticking. */ + smp_call_function(__tick_nohz_disable, NULL, 0); +} +EXPORT_SYMBOL_GPL(tick_nohz_disable); + /** * tick_nohz_update_jiffies - update jiffies when idle was interrupted * @@ -271,7 +294,8 @@ void tick_nohz_stop_sched_tick(int inidl 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) || + atomic_read(&tick_nohz_disable_counter) > 0) delta_jiffies = 1; /* * Do not stop the tick, if we are only one off -- blue skies, Martin. "Reality continues to ruin my life." - Calvin. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/