Dynamic tick, version 050127-1
PATCH 1/1 Dynamic tick, version 050127-1
Hi all,
Thanks for all the comments, here's an updated version of the dynamic tick patch.
I've fixed couple of things:
- Dyn-tick now supports local APIC timer. This allows longer sleep time inbetween ticks, over 1000 ticks compared to 54 ticks with PIT timer. It seems to stop timers on SMP too, but I've only briefly played with it on SMP.
- Fixed a stupid bug where next_timer_interrupt() was called, but jiffies was not substracted from the value. This caused the sleep to be always maximum available...
- CONFIG_HPET_TIMER is still not supported, but now the dyn-tick should automatically get disabled if HPET timer is detected.
- Now processor _should_ stay in idle for the duration of skipped ticks, as PIT and local APIC timers are disabled. I haven't verified this though.
I haven't fixes some things, such as the separation of the idle loop into it's own module, the generic part does not really do much anyting, etc.
Please note that this patch alone probably does not produce any considerable power savings. More work is needed in the PM area to take advantage of the savings. Some examples of the work needed are:
- There's lots of polling timers being used in Linux, such as in the keyboard driver, that keeps the ticks skipped very short. Many of these timers could be improved.
- There's currently no way to specify what kind of idle to use based on the estimated length of the sleep. For example, if the system supports ACPI C3 state, it should be possible to automatically enter C3 if the skippable jiffies are long enough. I believe the current ACPI idle loop bases the promotion/demotion to the number of idle loops run in certain time, which does not work when skipping ticks.
Please also note that this patch does not solve the high-resolution timers issues. This patch is intended to be a minimal patch to expose and improve PM related issues.
The main difference between dyn-tick patch compared to the high-res VST patch is that dyn-tick uses the next_timer_interrupt() function, and does not require the high-res timers patch to be installed. In the long run the dyn-tick and VST patches will probably merge. But meanwhile, PM related work can be done that benefits both patches.
Again, comments and testing is appreciated! If having problems, please provide output of dmesg | grep -i "time\|tick\|apic".
Regards,
Tony
arch/i386/Kconfig +10 -0
@@ -452,6 +452,16 @@ bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y +config NO_IDLE_HZ + bool "Dynamic Tick Timer - Skip timer ticks during idle" + help + This option enables support for skipping timer ticks when the + processor is idle. During system load, timer is continuous. + This option saves power, as it allows the system to stay in + idle mode longer. Currently supported timers are ACPI PM + timer, local APIC timer, and TSC timer. HPET timer is currently + not supported. + config SMP bool "Symmetric multi-processing support" ---help---
arch/i386/kernel/apic.c +47 -2
92 lines not on this page · raw message
arch/i386/kernel/irq.c +6 -0
@@ -15,6 +15,7 @@#include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/dyn-tick-timer.h> #ifndef CONFIG_X86_LOCAL_APIC /*
@@ -100,6 +101,11 @@ } else#endif __do_IRQ (irq, regs); + +#ifdef CONFIG_NO_IDLE_HZ +if (dyn_tick->state & (DYN_TICK_ENABLED |DYN_TICK_SKIPPING ) && irq !=0 ) + dyn_tick->interrupt (irq,NULL , regs); +#endif irq_exit ();
arch/i386/kernel/time.c +126 -0
150 lines not on this page · raw message
arch/i386/kernel/timers/timer_pm.c +24 -0
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/dyn-tick-timer.h> #include <asm/types.h> #include <asm/timer.h> #include <asm/smp.h>
@@ -168,6 +169,7 @@ monotonic_base += delta *NSEC_PER_USEC ;write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* convert to ticks */ delta += offset_delay; lost = delta / (USEC_PER_SEC /HZ );
@@ -184,6 +186,7 @@ first_run =0 ; offset_delay = 0; } +#endif }
@@ -238,6 +241,25 @@return (unsigned long ) offset_delay +cyc2us (delta); } +static unsigned long long ns_time; + +static unsigned long long get_hw_time_pmtmr (void ) +{ +u32 now, delta; +static unsigned int last_cycles; + now =read_pmtmr (); + delta = (now - last_cycles) &ACPI_PM_MASK ; + last_cycles = now; + ns_time +=cyc2us (delta) *NSEC_PER_USEC ; +return ns_time; +} + +static void late_init_pmtmr (void ) +{ + ns_time =monotonic_clock_pmtmr (); +} + +extern irqreturn_t pmtmr_interrupt (int irq,void *dev_id,struct pt_regs *regs);/* acpi timer_opts struct */ static struct timer_opts timer_pmtmr = {
@@ -245,7 +267,9 @@ .mark_offset = mark_offset_pmtmr, .get_offset = get_offset_pmtmr, .monotonic_clock = monotonic_clock_pmtmr, + .get_hw_time = get_hw_time_pmtmr, .delay = delay_pmtmr, + .late_init = late_init_pmtmr, };struct init_timer_opts __initdata timer_pmtmr_init = {
arch/i386/kernel/timers/timer_tsc.c +15 -0
@@ -112,6 +112,15 @@return delay_at_last_interrupt + edx; } +static unsigned long get_hw_time_tsc (void ) +{ + registerunsigned long eax, edx; + +unsigned long long hw_time; +rdtscll (hw_time); +return cycles_2_ns (hw_time); +} +static unsigned long long monotonic_clock_tsc (void ) {unsigned long long last_offset, this_offset, base;
@@ -348,6 +357,7 @@rdtsc (last_tsc_low, last_tsc_high); +#ifndef CONFIG_NO_IDLE_HZ spin_lock (&i8253_lock);outb_p (0x00 ,PIT_MODE );/* latch the count ASAP */
@@ -415,14 +425,18 @@ cpufreq_delayed_get(); }else lost_count =0 ; +#endif +/* update the monotonic base value */ this_offset = ((unsigned long long )last_tsc_high<<32 )|last_tsc_low; monotonic_base +=cycles_2_ns (this_offset - last_offset);write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* calculate delay_at_last_interrupt */ count = ((LATCH -1 ) - count) *TICK_SIZE ; delay_at_last_interrupt = (count +LATCH /2 ) /LATCH ; +#endif /* catch corner case where tick rollover occured * between tsc and pit reads (as noted when
@@ -551,6 +565,7 @@ .mark_offset = mark_offset_tsc, .get_offset = get_offset_tsc, .monotonic_clock = monotonic_clock_tsc, + .get_hw_time = get_hw_time_tsc, .delay = delay_tsc, };
arch/i386/mach-default/setup.c +16 -0
@@ -85,6 +85,22 @@setup_irq (0 , &irq0); } +/** +* replace_timer_interrupt - allow replacing timer interrupt handler +* +* Description: +* Can be used to replace timer interrupt handler with a more optimized +* handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ. +*/ +void replace_timer_interrupt (void * new_handler) +{ +unsigned long flags; + +write_seqlock_irqsave (&xtime_lock, flags); + irq0.handler = new_handler; +write_sequnlock_irqrestore (&xtime_lock, flags); +} +#ifdef CONFIG_MCA /** * mca_nmi_hook - hook into MCA specific NMI chain
include/asm-i386/timer.h +3 -0
@@ -1,6 +1,7 @@#ifndef _ASMi386_TIMER_H#define _ASMi386_TIMER_H#include <linux/init.h> +#include <linux/interrupt.h> /** * struct timer_ops - used to define a timer source
@@ -21,7 +22,9 @@void (*mark_offset)(void );unsigned long (*get_offset)(void );unsigned long long (*monotonic_clock)(void ); +unsigned long long (*get_hw_time)(void );void (*delay)(unsigned long ); +void (*late_init)(void ); };struct init_timer_opts {
include/linux/dyn-tick-timer.h new file +73 -0
73 lines not on this page · raw message
kernel/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ +obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick-timer.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/dyn-tick-timer.c new file +140 -0
140 lines not on this page · raw message
Quoted 4 lines · Tony Lindgren
Hi all,
Thanks for all the comments, here's an updated version of the dynamic tick patch.
Oops, I guess I should test before posting :)
Looks like CONFIG_X86_LOCAL_APIC=y is currenly needed on uniprocessor machines to compile. Also CONFIG_SMP=y makes the skipping to fail on a uniprocessor machine.
Regards,
Tony
Hi!
Quoted 9 lines
Thanks for all the comments, here's an updated version of the dynamic tick patch.
I've fixed couple of things:
- Dyn-tick now supports local APIC timer. This allows longer sleep time inbetween ticks, over 1000 ticks compared to 54 ticks with PIT timer. It seems to stop timers on SMP too, but I've only briefly played with it on SMP.
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 12 lines · Pavel Machek
Hi!
Quoted 9 lines
Thanks for all the comments, here's an updated version of the dynamic tick patch.
I've fixed couple of things:
- Dyn-tick now supports local APIC timer. This allows longer sleep time inbetween ticks, over 1000 ticks compared to 54 ticks with PIT timer. It seems to stop timers on SMP too, but I've only briefly played with it on SMP.
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
I've noticed that the only machine I have with ACPI C2/C3 support does not do anything in the C2/C3 loops, it just spins around and consumes more power than in C1 with hlt!
That's because we currently don't have any code to enable the C2/C3 states in the southbridges on many Athlon boards. It's the same problem on my Crusoe laptop ALi 1533 chipset.
I think we should have some ACPI code that scans the southbridges, and sets them up with C2/C3 enable functions that can be enabled/disabled via /sys.
Does anybody happen to have documentation for the ALi 1533, 1535 or M7101 chipset, BTW? I'd like to know how to enable the C2/C3 on it.
Tony
Hi!
Quoted 7 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.
Quoted 5 lines
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
Quoted 7 lines
I've noticed that the only machine I have with ACPI C2/C3 support does not do anything in the C2/C3 loops, it just spins around and consumes more power than in C1 with hlt!
That's because we currently don't have any code to enable the C2/C3 states in the southbridges on many Athlon boards. It's the same problem on my Crusoe laptop ALi 1533 chipset.
I do not think we should need any chipset-specific code. ACPI is expected to solve it... Can you ask on acpi-devel?
Signature · 1 line
64 bytes from 195.113.31.123: icmp_seq=28 ttl=51 time=448769.1 ms
Quoted 9 lines · Pavel Machek
Hi!
Quoted 7 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.
Quoted 7 lines
Quoted 5 lines
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or CONFIG_SMP. It also looks like your local APIC timer is working.
If you have a serial console, you can put one letter printks in the code. Can you check if you ever get to smp_apic_timer_interrupt()? That's where you should get to after the sleep, and that calls the PIT timer interrupt to get it going again. I'm thinking that you'll get to smp_apic_timer_interrupt(), but once therebut function dyn_tick->interrupt(0, NULL, regs) never gets called.
It's OK to put printks to the timer code here, there's tons of output only when the system is busy :)
Also, can you post your .config again? And also please post output from:
dmesg | grep -i "time\|tick\|apic"
Quoted 10 lines
Quoted 7 lines
I've noticed that the only machine I have with ACPI C2/C3 support does not do anything in the C2/C3 loops, it just spins around and consumes more power than in C1 with hlt!
That's because we currently don't have any code to enable the C2/C3 states in the southbridges on many Athlon boards. It's the same problem on my Crusoe laptop ALi 1533 chipset.
I do not think we should need any chipset-specific code. ACPI is expected to solve it... Can you ask on acpi-devel?
Yeah, I've been meaning to, I just subscribed to it yesterday.
Tony
Hi!
Quoted 9 lines
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.If you have a serial console, you can put one letter printks in the code. Can you check if you ever get to
smp_apic_timer_interrupt()? That's where you should get to after the sleep, and that calls the PIT timer interrupt to get it going again. I'm thinking that you'll get tosmp_apic_timer_interrupt(), but once therebut functiondyn_tick->interrupt(0, NULL, regs)never gets called.
dyn_tick->interrupt *is* being called:
Feb 2 14:53:41 amd last message repeated 36 times Feb 2 14:53:41 amd postfix/postfix-script: starting the Postfix mail system Feb 2 14:53:41 amd kernel: dyn_tick->interrupt Feb 2 14:53:41 amd kernel: dyn_tick->interrupt Feb 2 14:53:41 amd postfix/master[1301]: daemon started -- version 2.1.5 Feb 2 14:53:41 amd kernel: dyn_tick->interrupt Feb 2 14:53:45 amd last message repeated 30 times Feb 2 14:53:45 amd log1n[1220]: ROOT LOGIN on `tty8' Feb 2 14:53:45 amd kernel: dyn_tick->interrupt Feb 2 14:54:16 amd last message repeated 228 times
I'll try turning off CONFIG_PREEMPT...
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Hi!
Quoted 11 lines
Quoted 7 lines
Quoted 5 lines
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.
Quoted 6 lines
If you have a serial console, you can put one letter printks in the code. Can you check if you ever get to
smp_apic_timer_interrupt()? That's where you should get to after the sleep, and that calls the PIT timer interrupt to get it going again. I'm thinking that you'll get tosmp_apic_timer_interrupt(), but once therebut functiondyn_tick->interrupt(0, NULL, regs)never gets called.
I definitely get to smp_apic_timer_interrupt:
Feb 2 14:46:53 amd kernel: ic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_ti Feb 2 14:46:54 amd kernel:
irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsmp_apic_timer_irqsm
I'll test with this code:
if (dyn_tick->state & (DYN_TICK_ENABLED | DYN_TICK_SKIPPING)) {
if (dyn_tick->skip_cpu == cpu && dyn_tick->skip > DYN_TICK_MIN_SKIP) {
printk("dyn_tick->interrupt\n");
dyn_tick->interrupt(0, NULL, regs);
} else
PavelSignature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Hi!
Quoted 10 lines
Quoted 7 lines
Quoted 5 lines
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.
I ran find /, now my machine seems to work... Except that the time is now two times as fast as it should be, ouch.
Quoted 6 lines
If you have a serial console, you can put one letter printks in the code. Can you check if you ever get to
smp_apic_timer_interrupt()? That's where you should get to after the sleep, and that calls the PIT timer interrupt to get it going again. I'm thinking that you'll get tosmp_apic_timer_interrupt(), but once therebut functiondyn_tick->interrupt(0, NULL, regs)never gets called.
Serial console would be slightly tricky to arrange...
Heh, is it possible that I'm not running NMI deadlock detector and therefore it does not tick or something like that?
Quoted 7 lines
It's OK to put printks to the timer code here, there's tons of output only when the system is busy :)
Also, can you post your .config again? And also please post output from:
dmesg | grep -i "time\|tick\|apic"
pavel@amd:~$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 dyn-tick: Maximum ticks to skip limited to 1339 dyn-tick: Timer using dynamic tick pavel@amd:~$
Config is attached.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Hi!
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
Quoted 4 lines
Quoted 1 line
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.
I turned off CONFIG_PREEMPT, but nothing changed :-(.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 16 lines · Pavel Machek
Hi!
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.I turned off
CONFIG_PREEMPT, but nothing changed :-(.
What about reprogramming the timers in time.c after the sleep? Do you to dyn_tick->skip = 1; part in dyn_tick_timer_interrupt?
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
arch/i368/kernel/time.c renamed from arch/i386/kernel/time.c +3 -0
@@ -479,8 +480,11 @@spin_lock_irqsave (&i8253_lock, flags);outb_p (0x34 ,PIT_MODE );/* binary, mode 2, LSB/MSB, ch 0 */ +udelay (10 );outb_p (skip &0xff ,PIT_CH0 );/* LSB */ +udelay (10 );outb (skip >>8 ,PIT_CH0 );/* MSB */ +udelay (10 );spin_unlock_irqrestore (&i8253_lock, flags); }
Hi!
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 7 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.Quoted 5 lines
Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.I turned off
CONFIG_PREEMPT, but nothing changed :-(.What about reprogramming the timers in
time.cafter the sleep? Do you todyn_tick->skip= 1; part indyn_tick_timer_interrupt?
Yes, when I enabled debugging, dbg_dyn_tick_irq() was reached and produced lot of noise to syslog. After I done nothing for a while, machine would just sit there and wait, not doing anything. When it was hung, dbg_dyn_timer_tick was not reached.
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Quoted 4 lines
arch/i368/kernel/time.c renamed from arch/i386/kernel/time.c +0
-0@@ -479,8 +480,11 @@
arch/i368/kernel/time.c line 490
Quoted 10 lines
arch/i368/kernel/time.c renamed from arch/i386/kernel/time.c +3
-0spin_lock_irqsave (&i8253_lock, flags);outb_p (0x34 ,PIT_MODE );/* binary, mode 2, LSB/MSB, ch 0 */ +udelay (10 );outb_p (skip &0xff ,PIT_CH0 );/* LSB */ +udelay (10 );outb (skip >>8 ,PIT_CH0 );/* MSB */ +udelay (10 );spin_unlock_irqrestore (&i8253_lock, flags); }
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 22 lines · Pavel Machek
Hi!
Quoted 20 lines
Quoted 19 lines
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
Quoted 4 lines
Quoted 1 line
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.I turned off
CONFIG_PREEMPT, but nothing changed :-(.
Quoted 7 lines
Quoted 2 lines
What about reprogramming the timers in
time.cafter the sleep? Do you todyn_tick->skip= 1; part indyn_tick_timer_interrupt?Yes, when I enabled debugging,
dbg_dyn_tick_irq()was reached and produced lot of noise to syslog. After I done nothing for a while, machine would just sit there and wait, not doing anything. When it was hung,dbg_dyn_timer_tickwas not reached.
OK. Function dbg_dyn_timer_tick only printks if the sleep was less than expected and the system woke to a non-timer interrupt. But when idling, it should still printk something occasionally.
Quoted 5 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
Tony
Quoted 39 lines · Tony Lindgren
Quoted 22 lines · Pavel Machek
Hi!
Quoted 20 lines
Quoted 19 lines
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 6 lines
I used your config advices from second mail, still it does not work as
expected: system gets "too sleepy". Like it takes a nap during boot after "dyn-tick: Maximum ticks to skip limited to 1339", and key is needed to make it continue boot. Then cursor stops blinking and machine is hung at random intervals during use, key is enough to awake it.Hmmm, that sounds like the local APIC does not wake up the PIT interrupt properly after sleep. Hitting the keys causes the timer interrupt to get called, and that explains why it keeps running. But the timer ticks are not happening as they should for some reason. This should not happen (tm)...
Quoted 4 lines
Quoted 1 line
:-). Any ideas how to debug it? Previous version of patch seemed to work better...
I don't think it's HPET timer, or
CONFIG_SMP. It also looks like your local APIC timer is working.I turned off
CONFIG_PREEMPT, but nothing changed :-(.Quoted 7 lines
Quoted 2 lines
What about reprogramming the timers in
time.cafter the sleep? Do you todyn_tick->skip= 1; part indyn_tick_timer_interrupt?Yes, when I enabled debugging,
dbg_dyn_tick_irq()was reached and produced lot of noise to syslog. After I done nothing for a while, machine would just sit there and wait, not doing anything. When it was hung,dbg_dyn_timer_tickwas not reached.OK. Function
dbg_dyn_timer_tickonly printks if the sleep was less than expected and the system woke to a non-timer interrupt. But when idling, it should still printk something occasionally.Quoted 4 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
Quoted 6 lines
Quoted 1 line
I added the udelays, but behaviour did not change.
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
I think something broke TSC timer after the first patch, but I could not figure out yet what. So the bad combo might be local APIC + TSC. At least I'm seeing similar problems with local APIC + TSC timer.
Attached is a slightly improved patch, but the patch does not fix the TSC problem. It just fixes compile without local APIC, and booting SMP kernel on uniprocessor machine.
Currently the suggested combo is local APIC + ACPI PM timer...
And if that works, changing the I8042_POLL_PERIOD from HZ/20 in drivers/input/serio/i8042.h to something like HZ increases the sleep interval quite a bit. I think I had lots of polling also in CONFIG_NETFILTER, but I haven't verified that.
Regards,
Tony
arch/i386/Kconfig +10 -0
@@ -452,6 +452,16 @@ bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y +config NO_IDLE_HZ + bool "Dynamic Tick Timer - Skip timer ticks during idle" + help + This option enables support for skipping timer ticks when the + processor is idle. During system load, timer is continuous. + This option saves power, as it allows the system to stay in + idle mode longer. Currently supported timers are ACPI PM + timer, local APIC timer, and TSC timer. HPET timer is currently + not supported. + config SMP bool "Symmetric multi-processing support" ---help---
arch/i386/kernel/apic.c +47 -2
92 lines not on this page · raw message
arch/i386/kernel/irq.c +6 -0
@@ -15,6 +15,7 @@#include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/dyn-tick-timer.h> #ifndef CONFIG_X86_LOCAL_APIC /*
@@ -100,6 +101,11 @@ } else#endif __do_IRQ (irq, regs); + +#ifdef CONFIG_NO_IDLE_HZ +if (dyn_tick->state & (DYN_TICK_ENABLED |DYN_TICK_SKIPPING ) && irq !=0 ) + dyn_tick->interrupt (irq,NULL , regs); +#endif irq_exit ();
arch/i386/kernel/time.c +131 -0
155 lines not on this page · raw message
arch/i386/kernel/timers/timer_pm.c +24 -0
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/dyn-tick-timer.h> #include <asm/types.h> #include <asm/timer.h> #include <asm/smp.h>
@@ -168,6 +169,7 @@ monotonic_base += delta *NSEC_PER_USEC ;write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* convert to ticks */ delta += offset_delay; lost = delta / (USEC_PER_SEC /HZ );
@@ -184,6 +186,7 @@ first_run =0 ; offset_delay = 0; } +#endif }
@@ -238,6 +241,25 @@return (unsigned long ) offset_delay +cyc2us (delta); } +static unsigned long long ns_time; + +static unsigned long long get_hw_time_pmtmr (void ) +{ +u32 now, delta; +static unsigned int last_cycles; + now =read_pmtmr (); + delta = (now - last_cycles) &ACPI_PM_MASK ; + last_cycles = now; + ns_time +=cyc2us (delta) *NSEC_PER_USEC ; +return ns_time; +} + +static void late_init_pmtmr (void ) +{ + ns_time =monotonic_clock_pmtmr (); +} + +extern irqreturn_t pmtmr_interrupt (int irq,void *dev_id,struct pt_regs *regs);/* acpi timer_opts struct */ static struct timer_opts timer_pmtmr = {
@@ -245,7 +267,9 @@ .mark_offset = mark_offset_pmtmr, .get_offset = get_offset_pmtmr, .monotonic_clock = monotonic_clock_pmtmr, + .get_hw_time = get_hw_time_pmtmr, .delay = delay_pmtmr, + .late_init = late_init_pmtmr, };struct init_timer_opts __initdata timer_pmtmr_init = {
arch/i386/kernel/timers/timer_tsc.c +15 -0
@@ -112,6 +112,15 @@return delay_at_last_interrupt + edx; } +static unsigned long get_hw_time_tsc (void ) +{ + registerunsigned long eax, edx; + +unsigned long long hw_time; +rdtscll (hw_time); +return cycles_2_ns (hw_time); +} +static unsigned long long monotonic_clock_tsc (void ) {unsigned long long last_offset, this_offset, base;
@@ -348,6 +357,7 @@rdtsc (last_tsc_low, last_tsc_high); +#ifndef CONFIG_NO_IDLE_HZ spin_lock (&i8253_lock);outb_p (0x00 ,PIT_MODE );/* latch the count ASAP */
@@ -415,14 +425,18 @@ cpufreq_delayed_get(); }else lost_count =0 ; +#endif +/* update the monotonic base value */ this_offset = ((unsigned long long )last_tsc_high<<32 )|last_tsc_low; monotonic_base +=cycles_2_ns (this_offset - last_offset);write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* calculate delay_at_last_interrupt */ count = ((LATCH -1 ) - count) *TICK_SIZE ; delay_at_last_interrupt = (count +LATCH /2 ) /LATCH ; +#endif /* catch corner case where tick rollover occured * between tsc and pit reads (as noted when
@@ -551,6 +565,7 @@ .mark_offset = mark_offset_tsc, .get_offset = get_offset_tsc, .monotonic_clock = monotonic_clock_tsc, + .get_hw_time = get_hw_time_tsc, .delay = delay_tsc, };
arch/i386/mach-default/setup.c +16 -0
@@ -85,6 +85,22 @@setup_irq (0 , &irq0); } +/** +* replace_timer_interrupt - allow replacing timer interrupt handler +* +* Description: +* Can be used to replace timer interrupt handler with a more optimized +* handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ. +*/ +void replace_timer_interrupt (void * new_handler) +{ +unsigned long flags; + +write_seqlock_irqsave (&xtime_lock, flags); + irq0.handler = new_handler; +write_sequnlock_irqrestore (&xtime_lock, flags); +} +#ifdef CONFIG_MCA /** * mca_nmi_hook - hook into MCA specific NMI chain
include/asm-i386/timer.h +3 -0
@@ -1,6 +1,7 @@#ifndef _ASMi386_TIMER_H#define _ASMi386_TIMER_H#include <linux/init.h> +#include <linux/interrupt.h> /** * struct timer_ops - used to define a timer source
@@ -21,7 +22,9 @@void (*mark_offset)(void );unsigned long (*get_offset)(void );unsigned long long (*monotonic_clock)(void ); +unsigned long long (*get_hw_time)(void );void (*delay)(unsigned long ); +void (*late_init)(void ); };struct init_timer_opts {
include/linux/dyn-tick-timer.h new file +73 -0
73 lines not on this page · raw message
kernel/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ +obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick-timer.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/dyn-tick-timer.c new file +149 -0
149 lines not on this page · raw message
Quoted 10 lines · Tony Lindgren
Quoted 10 lines
Quoted 5 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
I see in the patch that you're reprogramming the PIT for a periodic mode
(2) but using dyn_tick->skip as the period. Is this intentional? I thought you wanted a oneshot for that.
Quoted 8 lines · Zwane Mwaikambo
Quoted 6 lines · Tony Lindgren
Quoted 6 lines
Quoted 5 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Quoted 8 lines
Quoted 4 lines
Quoted 4 lines
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
I see in the patch that you're reprogramming the PIT for a periodic mode
(2) but usingdyn_tick->skipas the period. Is this intentional? I thought you wanted a oneshot for that.
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
Regards,
Tony
Quoted 8 lines · Tony Lindgren
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
Quoted 6 lines
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
disable_irq(0) ?
Quoted 10 lines · Zwane Mwaikambo
Quoted 8 lines · Tony Lindgren
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
Quoted 8 lines
Quoted 6 lines
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
disable_irq(0)?
Then the problem is that the CPU does not stay in sleep but wakes to the first PIT interrupt AFAIK.
Tony
Quoted 15 lines · Tony Lindgren
Quoted 14 lines · Zwane Mwaikambo
Quoted 12 lines · Tony Lindgren
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
disable_irq(0)?Then the problem is that the CPU does not stay in sleep but wakes to the first PIT interrupt AFAIK.
I do not understand, do you want to disable the PIT from interrupting the processor and enable it interrupting at a later time?
Quoted 20 lines · Zwane Mwaikambo
Quoted 18 lines · Tony Lindgren
Quoted 17 lines · Zwane Mwaikambo
Quoted 14 lines · Tony Lindgren
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
disable_irq(0)?Then the problem is that the CPU does not stay in sleep but wakes to the first PIT interrupt AFAIK.
I do not understand, do you want to disable the PIT from interrupting the processor and enable it interrupting at a later time?
Yes, that right. PIT max skip ticks = 54 and local APIC timer > 1000. PIT interrupt needs to be disabled to stay in sleep for over 54 ticks.
But I think you're right, disable_irq(0) should do the trick :)
Hmmm, we should be able to keep PIT irq disabled all the time when using local APIC timer. I'll play with it a bit.
Tony
Quoted 29 lines · Tony Lindgren
Quoted 20 lines · Zwane Mwaikambo
Quoted 18 lines · Tony Lindgren
Quoted 17 lines · Zwane Mwaikambo
Quoted 14 lines · Tony Lindgren
Yes, it's safer to keep the timer periodic, although it's used for oneshot purposes for the skips. If the timer interrupt got missed for some reason, the system would be able to recover when it's in periodic mode.
And with some timers, we can do the reprogramming faster, as we just need to load the new value.
I could not figure out how to disable the interrupts for PIT when local APIC is used and the ticks to skip is longer than PIT would allow. So I just changed the mode temporarily to disable it.
Does anybody know if there's a way to stop PIT interrupts while keeping it in the periodic mode?
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
disable_irq(0)?Then the problem is that the CPU does not stay in sleep but wakes to the first PIT interrupt AFAIK.
I do not understand, do you want to disable the PIT from interrupting the processor and enable it interrupting at a later time?
Quoted 7 lines
Yes, that right. PIT max skip ticks = 54 and local APIC timer > 1000. PIT interrupt needs to be disabled to stay in sleep for over 54 ticks.
But I think you're right,
disable_irq(0)should do the trick :)Hmmm, we should be able to keep PIT irq disabled all the time when using local APIC timer. I'll play with it a bit.
Oops, no, PIT must be running at least when the system is busy. Otherwise time won't get updated during load, as we never get to the idle loop.
Tony
Hi!
Quoted 15 lines
Quoted 10 lines
Quoted 5 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
I think something broke TSC timer after the first patch, but I could not figure out yet what. So the bad combo might be local APIC + TSC. At least I'm seeing similar problems with local APIC + TSC timer.
Quoted 5 lines
Attached is a slightly improved patch, but the patch does not fix the TSC problem. It just fixes compile without local APIC, and booting SMP kernel on uniprocessor machine.
Currently the suggested combo is local APIC + ACPI PM timer...
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Quoted 4 lines
And if that works, changing the
I8042_POLL_PERIODfrom HZ/20 indrivers/input/serio/i8042.hto something like HZ increases the sleep interval quite a bit. I think I had lots of polling also inCONFIG_NETFILTER, but I haven't verified that.
Okay, I set POLL_PERIOD to 5*HZ, and disabled USB. Perhaps it will sleep better now?
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 21 lines · Pavel Machek
Hi!
Quoted 19 lines
Quoted 10 lines
Quoted 5 lines
Quoted 3 lines
It could also be that the reprogamming of PIT timer does not work on your machine. I chopped off the udelays there... Can you try something like this:
I added the udelays, but behaviour did not change.
Yeah, and if the first patch was working better, that means the PIT interrupts work. I'll do another version of the patch where PIT interrupts work again without local APIC needed, let's see what happens with that.
I think something broke TSC timer after the first patch, but I could not figure out yet what. So the bad combo might be local APIC + TSC. At least I'm seeing similar problems with local APIC + TSC timer.
Attached is a slightly improved patch, but the patch does not fix the TSC problem. It just fixes compile without local APIC, and booting SMP kernel on uniprocessor machine.
Quoted 6 lines
Quoted 1 line
Currently the suggested combo is local APIC + ACPI PM timer...
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Sounds like dyn-tick did not get enabled then, maybe you don't have CONFIG_X86_PM_TIMER, or don't have ACPI PM timer on your board?
After modifying I8042_POLL_PERIOD and leaving out CONFIG_NETFILTER I'm getting roughly 6HZ timer rate when idle :)
$ dmesg | grep -i "time\|tick\|apic" ACPI: PM-Timer IO Port: 0x1008 Kernel command line: root=/dev/nfs ip=dhcp ro console=ttyS0,115200 lapic init=/bin/minit Local APIC disabled by BIOS -- reenabling. Found and enabled local APIC! mapped APIC to ffffd000 (fee00000) Using pmtmr for high-res timesource dyn-tick: Registering dynamic tick timer per-CPU timeslice cutoff: 365.35 usecs. task migration cache decay timeout: 1 msecs. Machine check exception polling timer started. Real Time Clock Driver v1.12 dyn-tick: Maximum ticks to skip limited to 2678 dyn-tick: Timer using dynamic tick
$ cat /proc/interrupts | grep timer && sleep 10 && cat /proc/interrupts | grep timer 0: 10689 XT-PIC timer 0: 10745 XT-PIC timer
Quoted 7 lines
Quoted 4 lines
And if that works, changing the
I8042_POLL_PERIODfrom HZ/20 indrivers/input/serio/i8042.hto something like HZ increases the sleep interval quite a bit. I think I had lots of polling also inCONFIG_NETFILTER, but I haven't verified that.Okay, I set
POLL_PERIODto 5*HZ, and disabled USB. Perhaps it will sleep better now?
Sounds like your system is not running with the dyn-tick... I'll try to fix that TSC bug.
Tony
Quoted 6 lines · Tony Lindgren
Quoted 5 lines · Pavel Machek
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
...
Quoted 3 lines
Sounds like your system is not running with the dyn-tick... I'll try to fix that TSC bug.
The following patch fixes TSC timer with dyn-tick, and local APIC timer on UP system with CONFIG_SMP.
Tony
arch/i386/Kconfig +10 -0
@@ -452,6 +452,16 @@ bool "Provide RTC interrupt" depends on HPET_TIMER && RTC=y +config NO_IDLE_HZ + bool "Dynamic Tick Timer - Skip timer ticks during idle" + help + This option enables support for skipping timer ticks when the + processor is idle. During system load, timer is continuous. + This option saves power, as it allows the system to stay in + idle mode longer. Currently supported timers are ACPI PM + timer, local APIC timer, and TSC timer. HPET timer is currently + not supported. + config SMP bool "Symmetric multi-processing support" ---help---
arch/i386/kernel/apic.c +49 -1
92 lines not on this page · raw message
arch/i386/kernel/irq.c +6 -0
@@ -15,6 +15,7 @@#include <linux/seq_file.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/dyn-tick-timer.h> #ifndef CONFIG_X86_LOCAL_APIC /*
@@ -100,6 +101,11 @@ } else#endif __do_IRQ (irq, regs); + +#ifdef CONFIG_NO_IDLE_HZ +if (dyn_tick->state & (DYN_TICK_ENABLED |DYN_TICK_SKIPPING ) && irq !=0 ) + dyn_tick->interrupt (irq,NULL , regs); +#endif irq_exit ();
arch/i386/kernel/time.c +131 -0
155 lines not on this page · raw message
arch/i386/kernel/timers/timer_pm.c +24 -0
@@ -15,6 +15,7 @@#include <linux/module.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/dyn-tick-timer.h> #include <asm/types.h> #include <asm/timer.h> #include <asm/smp.h>
@@ -168,6 +169,7 @@ monotonic_base += delta *NSEC_PER_USEC ;write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* convert to ticks */ delta += offset_delay; lost = delta / (USEC_PER_SEC /HZ );
@@ -184,6 +186,7 @@ first_run =0 ; offset_delay = 0; } +#endif }
@@ -238,6 +241,25 @@return (unsigned long ) offset_delay +cyc2us (delta); } +static unsigned long long ns_time; + +static unsigned long long get_hw_time_pmtmr (void ) +{ +u32 now, delta; +static unsigned int last_cycles; + now =read_pmtmr (); + delta = (now - last_cycles) &ACPI_PM_MASK ; + last_cycles = now; + ns_time +=cyc2us (delta) *NSEC_PER_USEC ; +return ns_time; +} + +static void late_init_pmtmr (void ) +{ + ns_time =monotonic_clock_pmtmr (); +} + +extern irqreturn_t pmtmr_interrupt (int irq,void *dev_id,struct pt_regs *regs);/* acpi timer_opts struct */ static struct timer_opts timer_pmtmr = {
@@ -245,7 +267,9 @@ .mark_offset = mark_offset_pmtmr, .get_offset = get_offset_pmtmr, .monotonic_clock = monotonic_clock_pmtmr, + .get_hw_time = get_hw_time_pmtmr, .delay = delay_pmtmr, + .late_init = late_init_pmtmr, };struct init_timer_opts __initdata timer_pmtmr_init = {
arch/i386/kernel/timers/timer_tsc.c +15 -0
@@ -112,6 +112,15 @@return delay_at_last_interrupt + edx; } +static unsigned long get_hw_time_tsc (void ) +{ + registerunsigned long eax, edx; + +unsigned long long hw_time; +rdtscll (hw_time); +return cycles_2_ns (hw_time); +} +static unsigned long long monotonic_clock_tsc (void ) {unsigned long long last_offset, this_offset, base;
@@ -348,6 +357,7 @@rdtsc (last_tsc_low, last_tsc_high); +#ifndef CONFIG_NO_IDLE_HZ spin_lock (&i8253_lock);outb_p (0x00 ,PIT_MODE );/* latch the count ASAP */
@@ -415,11 +425,14 @@ cpufreq_delayed_get(); }else lost_count =0 ; +#endif +/* update the monotonic base value */ this_offset = ((unsigned long long )last_tsc_high<<32 )|last_tsc_low; monotonic_base +=cycles_2_ns (this_offset - last_offset);write_sequnlock (&monotonic_lock); +#ifndef CONFIG_NO_IDLE_HZ /* calculate delay_at_last_interrupt */ count = ((LATCH -1 ) - count) *TICK_SIZE ; delay_at_last_interrupt = (count +LATCH /2 ) /LATCH ;
@@ -430,6 +443,7 @@*/ if (lost &&abs (delay - delay_at_last_interrupt) > (900000 /HZ )) jiffies_64++; +#endif }static int __init init_tsc (char * override)
@@ -551,6 +565,7 @@ .mark_offset = mark_offset_tsc, .get_offset = get_offset_tsc, .monotonic_clock = monotonic_clock_tsc, + .get_hw_time = get_hw_time_tsc, .delay = delay_tsc, };
arch/i386/mach-default/setup.c +16 -0
@@ -85,6 +85,22 @@setup_irq (0 , &irq0); } +/** +* replace_timer_interrupt - allow replacing timer interrupt handler +* +* Description: +* Can be used to replace timer interrupt handler with a more optimized +* handler. Used for enabling and disabling of CONFIG_NO_IDLE_HZ. +*/ +void replace_timer_interrupt (void * new_handler) +{ +unsigned long flags; + +write_seqlock_irqsave (&xtime_lock, flags); + irq0.handler = new_handler; +write_sequnlock_irqrestore (&xtime_lock, flags); +} +#ifdef CONFIG_MCA /** * mca_nmi_hook - hook into MCA specific NMI chain
include/asm-i386/timer.h +3 -0
@@ -1,6 +1,7 @@#ifndef _ASMi386_TIMER_H#define _ASMi386_TIMER_H#include <linux/init.h> +#include <linux/interrupt.h> /** * struct timer_ops - used to define a timer source
@@ -21,7 +22,9 @@void (*mark_offset)(void );unsigned long (*get_offset)(void );unsigned long long (*monotonic_clock)(void ); +unsigned long long (*get_hw_time)(void );void (*delay)(unsigned long ); +void (*late_init)(void ); };struct init_timer_opts {
include/linux/dyn-tick-timer.h new file +71 -0
71 lines not on this page · raw message
kernel/Makefile +1 -0
@@ -26,6 +26,7 @@ obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ +obj-$(CONFIG_NO_IDLE_HZ) += dyn-tick-timer.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
kernel/dyn-tick-timer.c new file +149 -0
149 lines not on this page · raw message
Hi!
Quoted 5 lines
Quoted 4 lines
Quoted 4 lines
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Quoted 8 lines
...
Quoted 3 lines
Sounds like your system is not running with the dyn-tick... I'll try to fix that TSC bug.
The following patch fixes TSC timer with dyn-tick, and local APIC timer on UP system with
CONFIG_SMP.
Tried that and got same "sleepy machine" behaviour. But now I realized that I have PREEMPT and CPUFREQ enabled; I'll try disabling them.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Hi!
Quoted 10 lines
Quoted 7 lines
Quoted 4 lines
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Sounds like your system is not running with the dyn-tick... I'll try to fix that TSC bug.
The following patch fixes TSC timer with dyn-tick, and local APIC timer on UP system with
CONFIG_SMP.
I disabled CPUFREQ & PREEMPT, but still get "sleepy machine" behaviour. Could you perhaps send me your .config?
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 7 lines · Pavel Machek
Hi!
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
Sounds like your system is not running with the dyn-tick... I'll try to fix that TSC bug.
The following patch fixes TSC timer with dyn-tick, and local APIC timer on UP system with
CONFIG_SMP.I disabled CPUFREQ & PREEMPT, but still get "sleepy machine" behaviour. Could you perhaps send me your .config?
I don't have CPUFREQ on but I do have PREEMPT. Attached is my generic config that I'm using on my Celeron box and my dual Athlon box for testing with NFS root. I don't think your problems are caused by the Kconfig options any longer though.
Tony
Hi!
kernel/dyn-tick-timer.c line 59
Quoted 4 lines
kernel/dyn-tick-timer.c new file +4
-0+extern void disable_pit_tick (void ); +extern void reprogram_pit_tick (int jiffies_to_skip); +extern void reprogram_apic_timer (unsigned int count); +extern void reprogram_pit_tick (int jiffies_to_skip);
reprogram_pit_tick is here twice; but perhaps this should be moved to some kind of header file.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 9 lines · Pavel Machek
Hi!
kernel/dyn-tick-timer.c line 59
Quoted 4 lines
kernel/dyn-tick-timer.c new file +4
-0+extern void disable_pit_tick (void ); +extern void reprogram_pit_tick (int jiffies_to_skip); +extern void reprogram_apic_timer (unsigned int count); +extern void reprogram_pit_tick (int jiffies_to_skip);
reprogram_pit_tickis here twice; but perhaps this should be moved to some kind of header file.
Yeah, and the function itself should be in timer_pit.c.
Tony
Hi!
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
Currently the suggested combo is local APIC + ACPI PM timer...
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Sounds like dyn-tick did not get enabled then, maybe you don't have
CONFIG_X86_PM_TIMER, or don't have ACPI PM timer on your board?
I do have CONFIG_X86_PM_TIMER enabled, but it seems by board does not have such piece of hardware:
pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$
[Strange, I should see some messages about apic, no?]
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 6 lines · Pavel Machek
I do have
CONFIG_X86_PM_TIMERenabled, but it seems by board does not have such piece of hardware:pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$
If you are sure that machine supports ACPI, maybe this is your problem (from the POSIX high res timer patch):
If you enable the ACPI pm timer and it cannot be found, it is possible that your BIOS is not producing the ACPI table or that your machine does not support ACPI. In the former case, see "Default ACPI pm timer address". If the timer is not found the boot will fail when trying to calibrate the 'delay' loop.
[...]
config HIGH_RES_TIMER_ACPI_PM_ADD
int "Default ACPI pm timer address"
depends on HIGH_RES_TIMER_ACPI_PM
default 0
help
This option is available for use on systems where the BIOS does not generate the ACPI tables if ACPI is not enabled. For example some BIOSes will not generate the ACPI tables if APM is enabled. The ACPI pm timer is still available but cannot be found by the software. This option allows you to supply the needed address. When the high resolution timers code finds a valid ACPI pm timer address it reports it in the boot messages log (look for lines that begin with "High-res-timers:"). You can turn on the ACPI support in the BIOS, boot the system and find this value. You can then enter it at configure time. Both the report and the entry are in decimal.
HTH,
Lee
Hi!
Quoted 10 lines
Quoted 6 lines
I do have
CONFIG_X86_PM_TIMERenabled, but it seems by board does not have such piece of hardware:pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$If you are sure that machine supports ACPI, maybe this is your problem (from the POSIX high res timer patch):
Quoted 6 lines
If you enable the ACPI pm timer and it cannot be found, it is possible that your BIOS is not producing the ACPI table or that your machine does not support ACPI. In the former case, see "Default ACPI pm timer address". If the timer is not found the boot will fail when trying to calibrate the 'delay' loop.
Well, but how do I get the address? I'll try looking at BIOS options...
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 21 lines · Pavel Machek
Hi!
Quoted 10 lines
Quoted 6 lines
I do have
CONFIG_X86_PM_TIMERenabled, but it seems by board does not have such piece of hardware:pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$If you are sure that machine supports ACPI, maybe this is your problem (from the POSIX high res timer patch):
Quoted 6 lines
If you enable the ACPI pm timer and it cannot be found, it is possible that your BIOS is not producing the ACPI table or that your machine does not support ACPI. In the former case, see "Default ACPI pm timer address". If the timer is not found the boot will fail when trying to calibrate the 'delay' loop.
Quoted 3 lines
Well, but how do I get the address? I'll try looking at BIOS options...
Pavel
In my machine, if I turned off the PM code (in the BIOS) (or possibly turning on the ACPI, again in the BIOS) it did produce the address. Booting then would put that address in the dmesg file. You can then change the BIOS back to what it was and use the address found in the dmesg file.
Signature · 2 lines
George Anzinger [email protected] High-res-timers: http://sourceforge.net/projects/high-res-timers/
Quoted 12 lines · Pavel Machek
Hi!
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
Currently the suggested combo is local APIC + ACPI PM timer...
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Sounds like dyn-tick did not get enabled then, maybe you don't have
CONFIG_X86_PM_TIMER, or don't have ACPI PM timer on your board?
Quoted 8 lines
I do have
CONFIG_X86_PM_TIMERenabled, but it seems by board does not have such piece of hardware:pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$[Strange, I should see some messages about apic, no?]
Yeah, looks like you don't have a local APIC then? Let me test the patch here with just PIT timer only.
It also looks like you don't have TSC either? Or do you still have notsc cmdline option?
Tony
Hi!
Quoted 15 lines
Quoted 15 lines
Quoted 7 lines
Quoted 4 lines
Ok, works slightly better: time no longer runs 2x too fast. When TSC is used, I get same behaviour as before ("sleepy machine"). With "notsc", machine seems to work okay, but I still get 1000 timer interrupts a second.
Sounds like dyn-tick did not get enabled then, maybe you don't have
CONFIG_X86_PM_TIMER, or don't have ACPI PM timer on your board?I do have
CONFIG_X86_PM_TIMERenabled, but it seems by board does not have such piece of hardware:pavel@amd:/usr/src/linux-mm$ dmesg | grep -i "time\|tick\|apic" PCI: Setting latency timer of device 0000:00:11.5 to 64 pavel@amd:/usr/src/linux-mm$
Quoted 7 lines
Quoted 1 line
[Strange, I should see some messages about apic, no?]
Yeah, looks like you don't have a local APIC then? Let me test the patch here with just PIT timer only.
It also looks like you don't have TSC either? Or do you still have notsc cmdline option?
It definitely does have TSC, it is athlon64. It was probably disabled in this particular run.
Pavel
Signature · 2 lines
People were complaining that M$ turns users into beta-testers... ...jr ghea gurz vagb qrirybcref, naq gurl frrz gb yvxr vg gung jnl!
Quoted 4 lines · Tony Lindgren
Hi all,
Thanks for all the comments, here's an updated version of the dynamic tick patch.
Hi,
I was wondering how Windows handles high res timers, if at all. The reason I ask is because I have been reverse engineering a Windows ASIO driver, and I find that if the latency is set below about 5ms, by examining the kernel timer queue with SoftICE I can see that several kernel timers with 1ms period are created. (Presumably the sound card's interval timer is used for longer periods).
But, I have seen people mention in the "singing capacitor" threads on this list that Windows uses 100 for HZ.
So, how do they implement 1ms timers with a 10ms tick rate? Does Windows dynamically reprogram the PIT as well?
Lee
Quoted 15 lines · Lee Revell
Quoted 4 lines · Tony Lindgren
Hi all,
Thanks for all the comments, here's an updated version of the dynamic tick patch.
Hi,
I was wondering how Windows handles high res timers, if at all. The reason I ask is because I have been reverse engineering a Windows ASIO driver, and I find that if the latency is set below about 5ms, by examining the kernel timer queue with SoftICE I can see that several kernel timers with 1ms period are created. (Presumably the sound card's interval timer is used for longer periods).
Quoted 5 lines
But, I have seen people mention in the "singing capacitor" threads on this list that Windows uses 100 for HZ.
So, how do they implement 1ms timers with a 10ms tick rate? Does Windows dynamically reprogram the PIT as well?
No idea, but it would probably show up by adding some debug code some an emulator like Bochs?
Tony
Quoted 3 lines · Lee Revell
I was wondering how Windows handles high res timers, if at all. The reason I ask is because I have been reverse engineering a Windows ASIO driver, and I find that if the latency is set below about 5ms, by
By default, Windows "multimedia" timers have 10ms resolution (this depends on the exact version of Windows used...). You can call the timeBeginPeriod() function to lower the resolution to 1ms.
This resolution seem related to the task scheduler timeslice. After you call this function, the Sleep() call has also a resolution of 1ms instead of 10ms.
I remember reading that the multimedia timers are implemented as a high priority thread.
You can found more details on this site :
http://www.geisswerks.com/ryan/FAQS/timing.html
Best regards,
Eric St-Laurent