linux_2.5.44_vsyscall_A1
PATCH 1/1 linux_2.5.44_vsyscall_A1
Linus,
Here is the current rev of the i386 vsyscall gettimeofday port synced
up w/ today's BK. Same as last time, this patch contains a fix for the linker trouble in _A0, as well as wraps the whole thing in CONFIG_VSYSCALL.
This patch implements gettimeofday in a user readable page, allowing for calls to gettimeofday to execute completely in userspace, giving a significant performance boost.
Changes to glibc are unnecessary, because users that want to use the vsyscall can do so by LD_PRELOADING a library which alias gettimeofday before executing their application. This will not affect any other application and allows the backward compatibility issue to be ignored. I've created an example library (to be attached in a following email) and ran a quick performance test w/ and w/o the preloaded library, giving the following results:
[jstultz@elm3b52 vsyscall_test]$ ./run.sh Normal gettimeofday
gettimeofday ( 1388049us / 1000000runs ) = 1.388048us vsyscall LD_PRELOAD gettimeofday
gettimeofday ( 286024us / 1000000runs ) = 0.286024us
Since this code uses the TSC for calculating time of day, this patch will not help systems that suffer from TSC skew (ie: many NUMA systems, etc). However, for UP and SMP boxes this is a pretty major win. Alternative methods to use the cyclone/HPET registers for NUMA boxes are also feasible in the future.
Please consider for 2.5 integration.
thanks
-john
arch/i386/kernel/Makefile +1 -0
@@ -29,6 +29,7 @@ obj-$(CONFIG_X86_NUMAQ) += numaq.o obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_VSYSCALL) += vsyscall.o EXTRA_AFLAGS := -traditional
arch/i386/kernel/time.c +13 -3
@@ -69,8 +69,15 @@unsigned long cpu_khz;/* Detected as we calibrate the TSC */ extern rwlock_t xtime_lock; +#ifdef CONFIG_VSYSCALL +unsigned long __wall_jiffies __section_wall_jiffies; +struct timespec __xtime __section_xtime; +struct timezone __sys_tz __section_sys_tz; +volatile unsigned long __jiffies __section_jiffies; +#else /* CONFIG_VSYSCALL */ extern unsigned long wall_jiffies; - +#endif /* CONFIG_VSYSCALL */ +spinlock_t rtc_lock =SPIN_LOCK_UNLOCKED ;spinlock_t i8253_lock =SPIN_LOCK_UNLOCKED ;
@@ -110,6 +117,7 @@void do_settimeofday (struct timeval *tv) {write_lock_irq (&xtime_lock); +vxtime_lock ();/* * This is revolting. We need to set "xtime" correctly. However, the * value in this location is the value at the most recent update of
@@ -126,6 +134,8 @@ xtime.tv_sec = tv->tv_sec; xtime.tv_nsec = (tv->tv_usec *1000 ); +vxtime_unlock (); + time_adjust =0 ;/* stop active adjtime() */ time_status |=STA_UNSYNC ; time_maxerror =NTP_PHASE_LIMIT ;
@@ -277,11 +287,11 @@* locally disabled. -arca */ write_lock (&xtime_lock); - +vxtime_lock (); timer->mark_offset ();do_timer_interrupt (irq,NULL , regs); - +vxtime_unlock ();write_unlock (&xtime_lock); }
arch/i386/kernel/timers/timer_tsc.c +7 -2
@@ -10,23 +10,28 @@#include <linux/cpufreq.h> #include <asm/timer.h> +#include <asm/vsyscall.h> #include <asm/io.h> extern int x86_udelay_tsc;extern spinlock_t i8253_lock;static int use_tsc; +#ifndef CONFIG_VSYSCALL /* Number of usecs that the last interrupt was delayed */ static int delay_at_last_interrupt; -static unsigned long last_tsc_low;/* lsb 32 bits of Time Stamp Counter */ -/* Cached *multiplier* to convert TSC counts to microseconds. * (see the equation below). * Equal to 2^32 * (1 / (clocks per usec) ). * Initialized in time_init. */ unsigned long fast_gettimeoffset_quotient; +#else /* CONFIG_VSYSCALL */ +int __delay_at_last_interrupt __section_delay_at_last_interrupt; +unsigned long __last_tsc_low __section_last_tsc_low; +unsigned long __fast_gettimeoffset_quotient __section_fast_gettimeoffset_quotient; +#endif /* CONFIG_VSYSCALL */ static unsigned long get_offset_tsc (void ) {
arch/i386/kernel/vsyscall.c new file +199 -0
199 lines not on this page · raw message
arch/i386/vmlinux.lds.S +29 -1
@@ -4,7 +4,7 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) -jiffies = jiffies_64; +jiffies_64 = jiffies; SECTIONS { . = 0xC0000000 + 0x100000;
@@ -54,6 +54,34 @@ _edata = .; /* End of data section */ + /* VSYSCALL data */ + . = ALIGN(64); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + .vsyscall_0 0xffffe000: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) } + __vsyscall_0 = LOADADDR(.vsyscall_0); + . = ALIGN(64); + .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) } + vxtime_sequence = LOADADDR(.vxtime_sequence); + .last_tsc_low : AT (LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence)) { *(.last_tsc_low) } + last_tsc_low = LOADADDR(.last_tsc_low); + .delay_at_last_interrupt : AT (LOADADDR(.last_tsc_low) + SIZEOF(.last_tsc_low)) { *(.delay_at_last_interrupt) } + delay_at_last_interrupt = LOADADDR(.delay_at_last_interrupt); + .fast_gettimeoffset_quotient : AT (LOADADDR(.delay_at_last_interrupt) + SIZEOF(.delay_at_last_interrupt)) { *(.fast_gettimeoffset_quotient) } + fast_gettimeoffset_quotient = LOADADDR(.fast_gettimeoffset_quotient); + .wall_jiffies : AT (LOADADDR(.fast_gettimeoffset_quotient) + SIZEOF(.fast_gettimeoffset_quotient)) { *(.wall_jiffies) } + wall_jiffies = LOADADDR(.wall_jiffies); + .sys_tz : AT (LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies)) { *(.sys_tz) } + sys_tz = LOADADDR(.sys_tz); + . = ALIGN(16); + .jiffies : AT ((LOADADDR(.sys_tz) + SIZEOF(.sys_tz) + 15) & ~(15)) { *(.jiffies) } + jiffies = LOADADDR(.jiffies); + . = ALIGN(16); + .xtime : AT ((LOADADDR(.jiffies) + SIZEOF(.jiffies) + 15) & ~(15)) { *(.xtime) } + xtime = LOADADDR(.xtime); + .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) } + . = LOADADDR(.vsyscall_0) + 4096; + /* END of VSYSCALL data*/ + . = ALIGN(8192); /* init_task */ .data.init_task : { *(.data.init_task) }
include/asm-i386/fixmap.h +5 -0
@@ -18,6 +18,7 @@#include <asm/acpi.h> #include <asm/apicdef.h> #include <asm/page.h> +#include <asm/vsyscall.h> #ifdef CONFIG_HIGHMEM #include <linux/threads.h> #include <asm/kmap_types.h>
@@ -49,6 +50,10 @@* fix-mapped? */ enum fixed_addresses { +#ifdef CONFIG_VSYSCALL +VSYSCALL_LAST_PAGE , +VSYSCALL_FIRST_PAGE =VSYSCALL_LAST_PAGE + ((VSYSCALL_END -VSYSCALL_START ) >>PAGE_SHIFT ) -1 , +#endif /* CONFIG_VSYSCALL */ #ifdef CONFIG_X86_LOCAL_APIC FIX_APIC_BASE ,/* local (CPU) APIC) -- required for SMP or not */ #endif
include/asm-i386/pgtable.h +4 -1
@@ -139,11 +139,14 @@#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) - +#define __PAGE_KERNEL_VSYSCALL \ + (_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE) +#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL)/* * The i386 can't do page protection for execute, and considers that
include/asm-i386/vsyscall.h new file +53 -0
53 lines not on this page · raw message
init/Config.in +3 -0
@@ -9,6 +9,9 @@ bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +bool 'VSYSCALL interface' CONFIG_VSYSCALL +fi endmenu mainmenu_option next_comment
[EXAMPLE CODE] linux-2.5.44_vsyscall_A1
Linus, All,
Here again is the tarball containing the example vsyscall LD_PRELOAD
library, and the quick/rough performance measuring tool.
thanks
-john