High-res-timers part 2 (x86 platform code) take 8
PATCH 2/3 High-res-timers part 2 (x86 platform code) take 8
This patch, in conjunction with the "core" high-res-timers patch implements high resolution timers on the i386 platforms. The high-res-timers use the periodic interrupt to "remind" the system to look at the clock. The clock should be relatively high resolution (1 micro second or better). This patch allows configuring of three possible clocks, the TSC, the ACPI pm timer, or the Programmable interrupt timer (PIT). Most of the changes in this patch are in the arch/i386/kernel/timer/* code.
This patch uses (if available) the APIC timer(s) to generate 1/HZ ticks and sub 1/HZ ticks as needed. The PIT still interrupts, but if the APIC timer is available, just causes the wall clock update. No attempt is made to make this interrupt happen on jiffie boundaries, however, the APIC timers are disciplined to expire on 1/HZ boundaries to give consistent timer latencies WRT to the system time.
With this patch applied and enabled (at config time in the processor feature section), the system clock will be the specified clock. The PIT is not used to keep track of time, but only to remind the system to look at the clock. Sub jiffies are kept and available for code that knows how to use them.
Depends on the core high res timers patch.
Patch is against 2.5.44-bk1
This patch as well as the POSIX clocks & timers patch is available on the project site:
http://sourceforge.net/projects/high-res-timers/
The 3 parts to the high res timers are:
core The core kernel (i.e. platform independent) changes
*i386 The high-res changes for the i386 (x86) platform
posixhr The changes to the POSIX clocks & timers patch to
use high-res timers
Please apply.
Signature · 5 lines
George Anzinger [email protected] High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/Config.help +69 -0
@@ -52,6 +52,75 @@ Say Y here if you are building a kernel for a desktop, embedded or real-time system. Say N if you are unsure. +High-res-timers +CONFIG_HIGH_RES_TIMERS + POSIX timers are available by default. This option enables high + resolution POSIX timers. With this option the resolution is at + least 1 micro second. High resolution is not free. If enabled this + option will add a small overhead each time a timer expires that is + not on a 1/HZ tick boundry. If no such timers are used the overhead + is nil. + + This option enables two additional POSIX CLOCKS, CLOCK_REALTIME_HR + and CLOCK_MONOTONIC_HR. Note that this option does not change the + resolution of CLOCK_REALTIME or CLOCK_MONOTONIC which remain at 1/HZ + resolution. + +High-res-timers clock +CONFIG_HIGH_RES_TIMER_ACPI_PM + This option allows you to choose the wall clock timer for your system. + With high resolution timers on the x86 platforms it is best to keep + the interrupt generating timer separate from the time keeping timer. + On x86 platforms there are three possible sources implemented for the + wall clock. These are: + + <timer> <resolution> + ACPI power management (pm) timer ~280 nano seconds + TSC (Time Stamp Counter) 1/CPU clock + PIT (Programmable Interrupt Timer) ~838 nano seconds + + The PIT is used to generate interrupts and at any given time will be + programmed to interrupt when the next timer is to expire or on the + next 1/HZ tick. For this reason it is best to not use this timer as + the wall clock timer. This timer has a resolution of 838 nano + seconds. THIS OPTION SHOULD ONLY BE USED IF BOTH ACPI AND TSC ARE + NOT AVAILABLE. + + The TSC runs at the cpu clock rate (i.e. its resolution is 1/CPU + clock) and it has a very low access time. However, it is subject, + in some (incorrect) processors, to throttling to cool the cpu, and + to other slow downs during power management. If your cpu is correct + and does not change the TSC frequency for throttling or power + management this is the best clock timer. + + The ACPI pm timer is available on systems with Advanced Configuration + and Power Interface support. The pm timer is available on these + systems even if you don't use or enable ACPI in the software or the + BIOS (but see Default ACPI pm timer address). The timer has a + resolution of about 280 nanoseconds, however, the access time is a bit + higher that that of the TSC. Since it is part of ACPI it is intended + to keep track of time while the system is under power management, thus + it is not subject to the problems of the TSC. + + If you enable the ACPI pm timer and it can not 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 timer. + +Default ACPI pm timer address +CONFIG_HIGH_RES_TIMER_ACPI_PM_ADD + 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 can not 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. + CONFIG_X86 This is Linux's home port. Linux was originally native to the Intel 386, and runs on all the later x86 processors including the Intel
arch/i386/config.in +18 -0
@@ -156,6 +156,23 @@ bool 'Huge TLB Page Support' CONFIG_HUGETLB_PAGE bool 'Symmetric multi-processing support' CONFIG_SMP +bool 'Configure High-Resolution-Timers' CONFIG_HIGH_RES_TIMERS +# +# We assume that if the box doesn't have a TSC it doesn't have ACPI either. +# +if [ "$CONFIG_HIGH_RES_TIMERS" = "y" -a "$CONFIG_X86_TSC" = "y" ]; then + choice 'Clock source?' \ + "ACPI-pm-timer CONFIG_HIGH_RES_TIMER_ACPI_PM \ + Time-stamp-counter/TSC CONFIG_HIGH_RES_TIMER_TSC \ + Programable-interrupt-timer/PIT CONFIG_HIGH_RES_TIMER_PIT" Time-stamp-counter/TSC +else + if [ "$CONFIG_HIGH_RES_TIMERS" = "y" ]; then + define_bool CONFIG_HIGH_RES_TIMER_PIT y + fi +fi +if [ "$CONFIG_HIGH_RES_TIMER_ACPI_PM" = "y" ]; then + int 'Default ACPI pm timer address' CONFIG_HIGH_RES_TIMER_ACPI_PM_ADD 0 +fi bool 'Preemptible Kernel' CONFIG_PREEMPT if [ "$CONFIG_SMP" != "y" ]; then bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC
@@ -355,6 +372,7 @@ else define_bool CONFIG_BLK_DEV_HD n fi + endmenu mainmenu_option next_comment
arch/i386/kernel/apic.c +13 -3
@@ -800,7 +800,7 @@* P5 APIC double write bug. */ -#define APIC_DIVISOR 16 +#define APIC_DIVISOR 1void __setup_APIC_LVTT (unsigned int clocks) {
@@ -811,12 +811,12 @@apic_write_around (APIC_LVTT , lvtt1_value);/* -* Divide PICLK by 16 +* Divide PICLK by 1 */ tmp_value =apic_read (APIC_TDCR );apic_write_around (APIC_TDCR , (tmp_value & ~(APIC_TDR_DIV_1 |APIC_TDR_DIV_TMBASE )) - |APIC_TDR_DIV_16 ); + |APIC_TDR_DIV_1 );apic_write_around (APIC_TMICT , clocks/APIC_DIVISOR ); }
@@ -1021,10 +1021,20 @@* Interrupts are already masked off at this point. */ prof_counter[cpu] = prof_multiplier[cpu]; +/* +* deal with profiling later... +*/ +#ifndef CONFIG_HIGH_RES_TIMERS if (prof_counter[cpu] != prof_old_multiplier[cpu]) {__setup_APIC_LVTT (calibration_result/prof_counter[cpu]); prof_old_multiplier[cpu] = prof_counter[cpu]; } +#else +/* +* This is the 1/HZ count, can be changed by HRT code. +*/ +__setup_APIC_LVTT (calibration_result); +#endif #ifdef CONFIG_SMP update_process_times (user_mode (regs));
arch/i386/kernel/time.c +97 -25
194 lines not on this page · raw message
arch/i386/kernel/timers/Makefile +6 -0
@@ -6,6 +6,12 @@ obj-y += timer_tsc.o obj-y += timer_pit.o +obj-$(CONFIG_X86_TSC) -= timer_pit.o +obj-$(CONFIG_HIGH_RES_TIMERS) -= timer_tsc.o obj-$(CONFIG_X86_CYCLONE) += timer_cyclone.o +obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += hrtimer_pm.o +obj-$(CONFIG_HIGH_RES_TIMER_ACPI_PM) += high-res-tbxfroot.o +obj-$(CONFIG_HIGH_RES_TIMER_TSC) += hrtimer_tsc.o +obj-$(CONFIG_HIGH_RES_TIMER_PIT) += hrtimer_pit.o include $(TOPDIR)/Rules.make
arch/i386/kernel/timers/high-res-tbxfroot.c +273 -0
273 lines not on this page · raw message
arch/i386/kernel/timers/hrtimer_pit.c +163 -0
163 lines not on this page · raw message
arch/i386/kernel/timers/hrtimer_pm.c +196 -0
196 lines not on this page · raw message
arch/i386/kernel/timers/hrtimer_tsc.c +288 -0
288 lines not on this page · raw message
arch/i386/kernel/timers/timer.c +18 -1
@@ -1,15 +1,32 @@#include <linux/kernel.h> +#include <linux/hrtime.h> #include <asm/timer.h> - +/* +* export this here so it can be used by more than one clock source +*/ +unsigned long fast_gettimeoffset_quotient;/* list of externed timers */ extern struct timer_opts timer_pit;extern struct timer_opts timer_tsc; +extern struct timer_opts hrtimer_tsc; +extern struct timer_opts hrtimer_pm; +extern struct timer_opts hrtimer_pit;/* list of timers, ordered by preference, NULL terminated */ static struct timer_opts* timers[] = { +#ifdef CONFIG_HIGH_RES_TIMERS +#ifdef CONFIG_HIGH_RES_TIMER_ACPI_PM + &hrtimer_pm, +#elif CONFIG_HIGH_RES_TIMER_TSC + &hrtimer_tsc, +#elif CONFIG_HIGH_RES_TIMER_PIT + &hrtimer_pit, +#endif +#else &timer_tsc, #ifndef CONFIG_X86_TSC &timer_pit, +#endif #endif NULL, };
arch/i386/kernel/timers/timer_pit.c +1 -0
@@ -9,6 +9,7 @@#include <asm/mpspec.h> #include <asm/timer.h> #include <asm/io.h> +#include <linux/hrtime.h> extern spinlock_t i8259A_lock;extern spinlock_t i8253_lock;
arch/i386/kernel/timers/timer_tsc.c +1 -1
@@ -26,7 +26,7 @@* Equal to 2^32 * (1 / (clocks per usec) ). * Initialized in time_init. */ -unsigned long fast_gettimeoffset_quotient; +extern unsigned long fast_gettimeoffset_quotient;static unsigned long get_offset_tsc (void ) {
arch/i386/mach-generic/do_timer.h +5 -0
@@ -14,6 +14,11 @@static inline void do_timer_interrupt_hook (struct pt_regs *regs) {do_timer (regs); +IF_HIGH_RES ( + if (!(new_jiffie() & 1)) + return; + jiffies_intr = 0; + )/* * In the SMP case we use the local APIC timer interrupt to do the * profiling, except when we simulate SMP mode on a uniprocessor
include/asm-i386/hrtime-M386.h +247 -0
247 lines not on this page · raw message
include/asm-i386/hrtime-M586.h +165 -0
165 lines not on this page · raw message
include/asm-i386/hrtime-Macpi.h +184 -0
184 lines not on this page · raw message
include/asm-i386/hrtime.h +486 -0
486 lines not on this page · raw message
include/asm-i386/sc_math.h +143 -0
143 lines not on this page · raw message
include/asm-i386/signal.h +2 -0
@@ -3,6 +3,8 @@#include <linux/types.h> #include <linux/linkage.h> +#include <linux/time.h> +#include <asm/ptrace.h> /* Avoid too many header ordering problems. */ struct siginfo ;
kernel/posix-timers.c +5 -0
@@ -186,6 +186,11 @@unsigned long sec = tp->tv_sec;long nsec = tp->tv_nsec + res -1 ; +if ( nsec >NSEC_PER_SEC ){ + sec++; + nsec -=NSEC_PER_SEC ; + } +/* * A note on jiffy overflow: It is possible for the system to * have been up long enough for the jiffies quanity to overflow.