Skip to contentSkip to conversation

Dynamic tick, version 050127-1

PATCH In review Tony Lindgren 7 participants 38 messages Jan 27, 2005 – Feb 7, 2005

lore
Share & tools
lore
#0 lore raw

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
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
@@ -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
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
@@ -112,6 +112,15 @@
 	return delay_at_last_interrupt + edx;
 }
 
+static unsigned long get_hw_time_tsc(void)
+{
+	register unsigned 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
diff -Nru a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
@@ -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
diff -Nru a/include/asm-i386/timer.h b/include/asm-i386/timer.h
@@ -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
diff -Nru a/kernel/Makefile b/kernel/Makefile
@@ -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

#1 lore raw
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

#2 lore raw
In reply to Tony Lindgren

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!
#3 lore raw
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

#4 lore raw

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         
#5 lore raw
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

#6 lore raw

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 to smp_apic_timer_interrupt(), but once therebut function dyn_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!
#7 lore raw
In reply to Tony Lindgren

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 to smp_apic_timer_interrupt(), but once therebut function dyn_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

								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!
#8 lore raw
In reply to Tony Lindgren

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 to smp_apic_timer_interrupt(), but once therebut function dyn_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!
#9 lore raw
In reply to Tony Lindgren

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!
#10 lore raw
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);
 }
 
#11 lore raw

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.c after the sleep? Do you to dyn_tick->skip = 1; part in dyn_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 -0
 	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);
 }
 

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!
#12 lore raw
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.c after the sleep? Do you to dyn_tick->skip = 1; part in dyn_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.

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

#13 lore raw
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.c after the sleep? Do you to dyn_tick->skip = 1; part in dyn_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.

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 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
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
@@ -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
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
@@ -112,6 +112,15 @@
 	return delay_at_last_interrupt + edx;
 }
 
+static unsigned long get_hw_time_tsc(void)
+{
+	register unsigned 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
diff -Nru a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
@@ -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
diff -Nru a/include/asm-i386/timer.h b/include/asm-i386/timer.h
@@ -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
diff -Nru a/kernel/Makefile b/kernel/Makefile
@@ -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

#14 lore raw
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.

#15 lore raw
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 using dyn_tick->skip as 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

#16 lore raw
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) ?

#17 lore raw
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

#18 lore raw
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?

#19 lore raw
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

#20 lore raw
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

#21 lore raw
In reply to Tony Lindgren

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_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.

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!
#22 lore raw
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_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.

Okay, I set POLL_PERIOD to 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

#23 lore raw
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
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
@@ -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
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_pm.c b/arch/i386/kernel/timers/timer_pm.c
@@ -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
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
@@ -112,6 +112,15 @@
 	return delay_at_last_interrupt + edx;
 }
 
+static unsigned long get_hw_time_tsc(void)
+{
+	register unsigned 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
diff -Nru a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
@@ -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
diff -Nru a/include/asm-i386/timer.h b/include/asm-i386/timer.h
@@ -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
diff -Nru a/kernel/Makefile b/kernel/Makefile
@@ -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

#24 lore raw

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!
#25 lore raw
In reply to Tony Lindgren

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!
#26 lore raw
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

#27 lore raw
In reply to Tony Lindgren

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!
#28 lore raw
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_tick is 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

#29 lore raw
In reply to Tony Lindgren

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!
#30 lore raw
Quoted 6 lines · Pavel Machek

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$ 

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

#31 lore raw

Hi!

Quoted 10 lines
Quoted 6 lines

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$ 

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!
#32 lore raw
Quoted 21 lines · Pavel Machek

Hi!

Quoted 10 lines
Quoted 6 lines

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$ 

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/
#33 lore raw
In reply to Pavel Machek
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_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?]

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

#34 lore raw

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_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$ 
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!
#35 lore raw
In reply to Tony Lindgren
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

#36 lore raw
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

#37 lore raw
In reply to Lee Revell
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