Messages in this thread | | | From | Nick Rasmussen <> | Date | Thu, 13 Jan 2000 11:44:37 -0600 | Subject | [patch] High-resolution process timers |
| |
This patch enables very low-overhead access to high-resolution process virtual time and, optionally, high-resolution virtualized user and system time.
If enabled, a page of memory containing timing values is allocated with each task_struct, and an extra per-pid proc entry (/proc/PID/hrtime) is created which, when mmapped, maps the timing page into the user's address space. All process timing queries can be then be performed at memory reference speeds, without the overhead of a system call. Timers work at the resolution of the hardware timestamp counters. For convenience, a library is provided which can be used to perform the mapping and timer querying.
In the current implementation, permissions on /proc/PID/hrtime are set to 400.
The library and the latest version of the patch against various 2.2 and 2.3 kernels is available at http://www.cs.wisc.edu/paradyn/libhrtime/. The following patch is against 2.3.39
These timers were developed as part of the Paradyn Parallel Performance Tools project at the University of Wisconsin.
-nick
diff -rc5N linux-2.3.39/Documentation/Configure.help linux-2.3.39-hrtime/Documentation/Configure.help *** linux-2.3.39/Documentation/Configure.help Mon Jan 10 20:25:32 2000 --- linux-2.3.39-hrtime/Documentation/Configure.help Tue Jan 11 13:47:39 2000 *************** *** 116,125 **** --- 116,142 ---- Documentation/smp.txt, and Documentation/IO-APIC.txt. Also see the SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ . If you don't know what to do here, say N. + High-resolution process virtual time + CONFIG_HRTIME + This enables cycle-counter precision for process virtual time. + A timing page per task is allocated where the values are kept. + /proc/PID/hrtime can then be mmapped to access these values from + user space without having to do a syscall. + + If you don't know what to do here, say N. + + High-resolution process user and system time + CONFIG_HRUSTIME + This enables cycle-counter precision for virtualized user and system + time. Warning: Turning this option on will add code to the system + call path. + + If you don't know what to do here, say N. + Kernel math emulation CONFIG_MATH_EMULATION Linux can emulate a math coprocessor (used for floating point operations) if you don't have one. 486DX and Pentium processors have a math coprocessor built in, 486SX and 386 do not, unless you added diff -rc5N linux-2.3.39/arch/i386/config.in linux-2.3.39-hrtime/arch/i386/config.in *** linux-2.3.39/arch/i386/config.in Thu Jan 6 17:01:56 2000 --- linux-2.3.39-hrtime/arch/i386/config.in Tue Jan 11 13:47:39 2000 *************** *** 28,45 **** define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y define_bool CONFIG_X86_BSWAP y define_bool CONFIG_X86_POPAD_OK y fi ! if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" ]; then define_bool CONFIG_X86_TSC y fi if [ "$CONFIG_M686" = "y" ]; then define_bool CONFIG_X86_GOOD_APIC y fi if [ "$CONFIG_MK7" = "y" ]; then - define_bool CONFIG_X86_TSC y define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y fi choice 'High Memory Support' \ --- 28,48 ---- define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y define_bool CONFIG_X86_BSWAP y define_bool CONFIG_X86_POPAD_OK y fi ! ! if [ "$CONFIG_M686" = "y" -o "$CONFIG_M586TSC" = "y" -o "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_TSC y + else + define_bool CONFIG_X86_TSC n fi + if [ "$CONFIG_M686" = "y" ]; then define_bool CONFIG_X86_GOOD_APIC y fi if [ "$CONFIG_MK7" = "y" ]; then define_bool CONFIG_X86_GOOD_APIC y define_bool CONFIG_X86_USE_3DNOW y fi choice 'High Memory Support' \ *************** *** 55,64 **** --- 58,75 ---- fi bool 'Math emulation' CONFIG_MATH_EMULATION bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR bool 'Symmetric multi-processing support' CONFIG_SMP + + if [ "$CONFIG_X86_TSC" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'High-resolution process virtual time support' CONFIG_HRTIME + if [ "$CONFIG_HRTIME" = "y" ]; then + bool 'High-resolution process utime/stime support' CONFIG_HRUSTIME + fi + fi + endmenu mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES diff -rc5N linux-2.3.39/arch/i386/defconfig linux-2.3.39-hrtime/arch/i386/defconfig *** linux-2.3.39/arch/i386/defconfig Sat Jan 8 15:16:30 2000 --- linux-2.3.39-hrtime/arch/i386/defconfig Tue Jan 11 13:47:39 2000 *************** *** 28,37 **** --- 28,39 ---- # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set # CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y + # CONFIG_HRTIME is not set + # CONFIG_HRUSTIME is not set # # Loadable module support # CONFIG_MODULES=y diff -rc5N linux-2.3.39/arch/i386/kernel/entry.S linux-2.3.39-hrtime/arch/i386/kernel/entry.S *** linux-2.3.39/arch/i386/kernel/entry.S Mon Jan 10 20:15:58 2000 --- linux-2.3.39-hrtime/arch/i386/kernel/entry.S Tue Jan 11 13:47:39 2000 *************** *** 41,50 **** --- 41,51 ---- */ #include <linux/sys.h> #include <linux/linkage.h> #include <asm/segment.h> + #include <linux/config.h> #define ASSEMBLY #include <asm/smp.h> EBX = 0x00 ECX = 0x04 *************** *** 74,83 **** --- 75,96 ---- flags = 4 sigpending = 8 addr_limit = 12 exec_domain = 16 need_resched = 20 + #ifdef CONFIG_HRUSTIME + hrtime = 24 + + /* The following are offsets into the hrtime_struct, not the task_struct */ + last_us_dispatch_low = 0 + last_us_dispatch_high = 4 + utime_low = 8 + utime_high = 12 + stime_low = 16 + stime_high = 20 + in_system = 24 + #endif ENOSYS = 38 #define SAVE_ALL \ *************** *** 195,206 **** --- 208,245 ---- GET_CURRENT(%ebx) cmpl $(NR_syscalls),%eax jae badsys testb $0x20,flags(%ebx) # PF_TRACESYS jne tracesys + #ifdef CONFIG_HRUSTIME + pushl %eax + rdtsc # edx:eax has current timespamp value + movl hrtime(%ebx), %ebx # ebx now points to the htrime_struct + subl last_us_dispatch_low(%ebx), %eax + sbbl last_us_dispatch_high(%ebx), %edx # edx:eax has number of tics since last dispatch + addl %eax, utime_low(%ebx) + adcl %edx, utime_high(%ebx) + addl %eax, last_us_dispatch_low(%ebx) + adcl %edx, last_us_dispatch_high(%ebx) + addl $1, in_system(%ebx) + GET_CURRENT(%ebx) + popl %eax # reload the system call number XXX - fixme + #endif call *SYMBOL_NAME(sys_call_table)(,%eax,4) movl %eax,EAX(%esp) # save the return value + #ifdef CONFIG_HRUSTIME + rdtsc # edx:eax has current timespamp value + movl hrtime(%ebx), %ebx # ebx now points to the htrime_struct + subl last_us_dispatch_low(%ebx), %eax + sbbl last_us_dispatch_high(%ebx), %edx # edx:eax has number of tics since last dispatch + addl %eax, stime_low(%ebx) + adcl %edx, stime_high(%ebx) + addl %eax, last_us_dispatch_low(%ebx) + adcl %edx, last_us_dispatch_high(%ebx) + subl $1, in_system(%ebx) + GET_CURRENT(%ebx) + #endif ALIGN .globl ret_from_sys_call .globl ret_from_intr ret_from_sys_call: movl SYMBOL_NAME(bh_mask),%eax diff -rc5N linux-2.3.39/arch/i386/kernel/init_task.c linux-2.3.39-hrtime/arch/i386/kernel/init_task.c *** linux-2.3.39/arch/i386/kernel/init_task.c Tue Aug 3 12:32:57 1999 --- linux-2.3.39-hrtime/arch/i386/kernel/init_task.c Tue Jan 11 13:47:39 2000 *************** *** 1,18 **** --- 1,25 ---- #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> + #include <linux/config.h> + #ifdef CONFIG_HRTIME + #include <linux/hrtime.h> + #endif #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/desc.h> static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); + #ifdef CONFIG_HRTIME + static struct hrtime_struct init_hrtime = INIT_HRTIME; + #endif /* * Initial task structure. * * We need to make sure that this is 8192-byte aligned due to the diff -rc5N linux-2.3.39/fs/proc/Makefile linux-2.3.39-hrtime/fs/proc/Makefile *** linux-2.3.39/fs/proc/Makefile Tue Dec 21 00:05:10 1999 --- linux-2.3.39-hrtime/fs/proc/Makefile Tue Jan 11 13:47:39 2000 *************** *** 11,20 **** --- 11,23 ---- O_OBJS := inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o kcore.o ifdef CONFIG_OMIRR O_OBJS := $(O_OBJS) omirr.o endif + ifdef CONFIG_HRTIME + O_OBJS := $(O_OBJS) hrtime.o + endif OX_OBJS := procfs_syms.o M_OBJS := ifeq ($(CONFIG_PROC_DEVICETREE),y) O_OBJS += proc_devtree.o diff -rc5N linux-2.3.39/fs/proc/base.c linux-2.3.39-hrtime/fs/proc/base.c *** linux-2.3.39/fs/proc/base.c Fri Jan 7 14:59:42 2000 --- linux-2.3.39-hrtime/fs/proc/base.c Tue Jan 11 13:47:39 2000 *************** *** 496,505 **** --- 496,508 ---- PROC_PID_ENVIRON, PROC_PID_CMDLINE, PROC_PID_STAT, PROC_PID_STATM, PROC_PID_MAPS, + #if CONFIG_HRTIME + PROC_PID_HRTIME, + #endif #if CONFIG_AP1000 PROC_PID_RINGBUF, #endif PROC_PID_CPU, PROC_PID_FD_DIR = 0x8000, /* 0x8000-0xffff */ *************** *** 514,523 **** --- 517,529 ---- E(PROC_PID_STAT, "stat", S_IFREG|S_IRUGO), E(PROC_PID_STATM, "statm", S_IFREG|S_IRUGO), #ifdef __SMP__ E(PROC_PID_CPU, "cpu", S_IFREG|S_IRUGO), #endif + #ifdef CONFIG_HRTIME + E(PROC_PID_HRTIME, "hrtime", S_IFREG|S_IRUSR), + #endif #if CONFIG_AP1000 E(PROC_PID_RINGBUF, "ringbuf", S_IFREG|S_IRUGO|S_IWUSR), #endif E(PROC_PID_MAPS, "maps", S_IFREG|S_IRUGO), E(PROC_PID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR), *************** *** 867,876 **** --- 873,887 ---- break; #ifdef __SMP__ case PROC_PID_CPU: inode->i_op = &proc_info_inode_operations; inode->u.proc_i.op.proc_read = proc_pid_cpu; + break; + #endif + #ifdef CONFIG_HRTIME + case PROC_PID_HRTIME: + inode->i_op = &proc_hrtime_inode_operations; break; #endif #if CONFIG_AP1000 case PROC_PID_RINGBUF: inode->i_op = &proc_ringbuf_inode_operations; diff -rc5N linux-2.3.39/fs/proc/hrtime.c linux-2.3.39-hrtime/fs/proc/hrtime.c *** linux-2.3.39/fs/proc/hrtime.c Wed Dec 31 19:00:00 1969 --- linux-2.3.39-hrtime/fs/proc/hrtime.c Tue Jan 11 13:47:39 2000 *************** *** 0 **** --- 1,252 ---- + /* + * linux/fs/proc/hrtime.c + * + * Copyright (C) 1999, Nick Rasmussen <nick@jive.org> + */ + + #include <linux/types.h> + #include <linux/errno.h> + #include <linux/sched.h> + #include <linux/kernel.h> + #include <linux/mm.h> + #include <linux/proc_fs.h> + #include <linux/hrtime.h> + #include <linux/config.h> + + #include <asm/page.h> + #include <asm/mman.h> + #include <asm/uaccess.h> + #include <asm/io.h> + #include <asm/pgtable.h> + + #define PROC_BLOCK_SIZE (3*1024) + + static void hrtime_vm_close(struct vm_area_struct *area) + { + unref_hrtime_struct((struct hrtime_struct *) area->vm_file->private_data); + } + + static struct vm_operations_struct hrtime_vm_ops = { + NULL, /* open */ + hrtime_vm_close, /* close */ + NULL, /* unmap */ + NULL, /* protect */ + NULL, /* sync */ + NULL, /* advise */ + NULL, /* nopage */ + NULL, /* wppage */ + NULL /* swapout */ + }; + + #define HRTIME_ENABLE_READ 0 + + #if HRTIME_ENABLE_READ + static int print_hrtime(struct hrtime_struct *h, char * buffer) + { + int len = 0; + + /* XXX - this assumes little endian - FIXME */ + len += sprintf(buffer + len, + "hrtime: start_time 0x%08x%08x", + ((unsigned int *) &h->start_time)[1], + ((unsigned int *) &h->start_time)[0]); + + len += sprintf(buffer + len, + " vtime 0x%08x%08x", + ((unsigned int *) &h->vtime)[1], + ((unsigned int *) &h->vtime)[0]); + + #ifdef CONFIG_HRUSTIME + len += sprintf(buffer + len, + " utime 0x%08x%08x", + ((unsigned int *) &h->utime)[1], + ((unsigned int *) &h->utime)[0]); + + len += sprintf(buffer + len, + " stime 0x%08x%08x", + ((unsigned int *) &h->stime)[1], + ((unsigned int *) &h->stime)[0]); + + len += sprintf(buffer + len, + " in_system %ld", + h->in_system); + #endif + + len += sprintf(buffer + len, + " ref %ld\n", + h->refcount); + + return len; + } + + + static ssize_t hrtime_read(struct file * file, char * buf, + size_t count, loff_t *ppos) + { + unsigned long page; + ssize_t length; + ssize_t end; + + if (count > PROC_BLOCK_SIZE) + count = PROC_BLOCK_SIZE; + if (!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + length = print_hrtime((struct hrtime_struct *) file->private_data, + (char *) page); + + if (length < 0) { + free_page(page); + return length; + } + + if (*ppos >= length) { + free_page(page); + return 0; + } + + if (count + *ppos > length) + count = length - *ppos; + + end = count + *ppos; + copy_to_user(buf, (char *) page + *ppos, count); + *ppos = end; + free_page(page); + return count; + } + + #endif /* HRTIME_ENABLE_READ */ + + /* + * hrtime_mmap will map another (or your own) process' hrtime_struct + * into your address space. + */ + int hrtime_mmap(struct file *file, struct vm_area_struct * vma) + { + int error = 0; + + vma->vm_ops = &hrtime_vm_ops; + + read_lock(&tasklist_lock); + + /* The timing page can only be mapped readonly */ + if ((pgprot_val(vma->vm_page_prot) & PROT_WRITE) != 0) { + error = -EPERM; + goto exit_with_unlock; + } + + /* We only allow mapping exactly one page -- the hrtime page */ + if (vma->vm_end - vma->vm_start != PAGE_SIZE) { + error = -EINVAL; + goto exit_with_unlock; + } + + error = remap_page_range(vma->vm_start, + virt_to_phys(file->private_data), + PAGE_SIZE, vma->vm_page_prot); + + if (error == 0) + ref_hrtime_struct((struct hrtime_struct *) file->private_data); + + exit_with_unlock: + + read_unlock(&tasklist_lock); + + return error; + } + + static int hrtime_open(struct inode *inode, struct file *file) + { + unsigned int pid; + int error = 0; + struct task_struct * tsk; + + pid = inode->i_ino >> 16; + + if (!pid) { + return -EBADF; + } + + file->private_data = 0; + + read_lock(&tasklist_lock); + + tsk = current; + + if (pid != tsk->pid) + tsk = find_task_by_pid(pid); + + if (tsk == NULL) + { + error = -ESRCH; + goto exit_with_unlock; + } + + file->private_data = tsk->hrtime; + + ref_hrtime_struct(file->private_data); + + exit_with_unlock: + + read_unlock(&tasklist_lock); + return error; + } + + /* + * When closing /proc/PID/hrtime, unref the respective processes hrtime field + */ + static int hrtime_release(struct inode *inode, struct file *file) + { + /* Do I really need to grab the tasklist lock here? I am changing + * fields inside a potential task. + */ + read_lock(&tasklist_lock); + + if (file->private_data != 0) { + unref_hrtime_struct(file->private_data); + } + + read_unlock(&tasklist_lock); + + return 0; + } + + static struct file_operations proc_hrtime_operations = { + NULL, /* no lseek */ + #if HRTIME_ENABLE_READ + hrtime_read, /* read */ + #else + NULL, /* no read */ + #endif + NULL, /* no write */ + NULL, /* no readdir */ + NULL, /* no poll */ + NULL, /* no ioctl */ + hrtime_mmap, /* mmap */ + hrtime_open, /* open */ + NULL, /* flush */ + hrtime_release, /* release */ + NULL /* can't fsync */ + }; + + struct inode_operations proc_hrtime_inode_operations = { + &proc_hrtime_operations, /* file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* revalidate */ + }; + diff -rc5N linux-2.3.39/include/asm-i386/hrtime.h linux-2.3.39-hrtime/include/asm-i386/hrtime.h *** linux-2.3.39/include/asm-i386/hrtime.h Wed Dec 31 19:00:00 1969 --- linux-2.3.39-hrtime/include/asm-i386/hrtime.h Tue Jan 11 13:47:39 2000 *************** *** 0 **** --- 1,23 ---- + #ifndef _ASM_HRTIME_H + #define _ASM_HRTIME_H + /* + * linux/include/asm-i386/hrtime.h + * + * Copyright (C) 1999, Nick Rasmussen <nick@jive.org> + */ + + #include <linux/config.h> + + #include <asm/msr.h> + + typedef unsigned long long hrtime_t; + + static inline void get_current_hrtime(volatile hrtime_t *t) + { + volatile unsigned long *parts = (volatile unsigned long *) t; + + rdtsc(parts[0], parts[1]); + return; + } + + #endif diff -rc5N linux-2.3.39/include/linux/hrtime.h linux-2.3.39-hrtime/include/linux/hrtime.h *** linux-2.3.39/include/linux/hrtime.h Wed Dec 31 19:00:00 1969 --- linux-2.3.39-hrtime/include/linux/hrtime.h Tue Jan 11 13:47:39 2000 *************** *** 0 **** --- 1,68 ---- + #ifndef _LINUX_HRTIME_H + #define _LINUX_HRTIME_H + /* + * include/linux/hrtime.h + * + * High-resolution process timing + * + * Copyright (C) 1999, Nick Rasmussen <nick@jive.org> + */ + + #include <linux/config.h> + #include <linux/spinlock.h> + + #include <asm/hrtime.h> + + /* Will be 1 once the cpu-cpu offset code for smp boxes is written */ + #define HRTIME_HAS_OFFSETS 0 + + /* + * Careful if you add fields to this struct - the offsets to utime and + * stime are hard-coded in arch/i386/kernel/entry.S + */ + struct hrtime_struct + { + /* These fields are only used if CONFIG_USTIME is enabled */ + /* dispatch times are non-zero only when the process is executing */ + volatile hrtime_t last_us_dispatch; + volatile hrtime_t utime; + volatile hrtime_t stime; + volatile long in_system; + + /* A flag as to wether CONFIG_USTIME is enabled. This is so that + * the hrtime interface can be binary compatible between kernels + * compiled with and without CONFIG_USTIME + */ + long has_ustime; + + /* start_time's value is with reference to cpu0 */ + hrtime_t start_time; + + /* dispatch times are non-zero only when the process is executing */ + volatile hrtime_t last_dispatch; + volatile hrtime_t vtime; + + volatile long offset_to_cpu0; + + long refcount; + spinlock_t reflock; + }; + + #ifdef __KERNEL__ + + #ifdef CONFIG_HRUSTIME + #define INIT_HRTIME { 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, SPIN_LOCK_UNLOCKED } + #else + #define INIT_HRTIME { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, SPIN_LOCK_UNLOCKED } + #endif + + extern struct hrtime_struct init_hrtime; + + extern struct hrtime_struct *alloc_hrtime_struct(void); + extern void init_hrtime_struct(struct hrtime_struct *s); + extern void ref_hrtime_struct(struct hrtime_struct *s); + extern void unref_hrtime_struct(struct hrtime_struct *s); + + #endif /* __KERNEL__ */ + + #endif diff -rc5N linux-2.3.39/include/linux/proc_fs.h linux-2.3.39-hrtime/include/linux/proc_fs.h *** linux-2.3.39/include/linux/proc_fs.h Mon Jan 10 20:30:03 2000 --- linux-2.3.39-hrtime/include/linux/proc_fs.h Tue Jan 11 13:47:39 2000 *************** *** 113,122 **** --- 113,125 ---- extern struct dentry *proc_lookup(struct inode *, struct dentry *); extern struct inode_operations proc_sys_inode_operations; extern struct inode_operations proc_kcore_inode_operations; extern struct inode_operations proc_kmsg_inode_operations; + #if CONFIG_HRTIME + extern struct inode_operations proc_hrtime_inode_operations; + #endif #if CONFIG_AP1000 extern struct inode_operations proc_ringbuf_inode_operations; #endif extern struct inode_operations proc_omirr_inode_operations; extern struct inode_operations proc_ppc_htab_inode_operations; diff -rc5N linux-2.3.39/include/linux/sched.h linux-2.3.39-hrtime/include/linux/sched.h *** linux-2.3.39/include/linux/sched.h Mon Jan 10 20:29:22 2000 --- linux-2.3.39-hrtime/include/linux/sched.h Tue Jan 11 13:51:43 2000 *************** *** 22,31 **** --- 22,35 ---- #include <linux/tty.h> #include <linux/sem.h> #include <linux/signal.h> #include <linux/securebits.h> + #ifdef CONFIG_HRTIME + #include <linux/hrtime.h> + #endif + /* * cloning flags: */ #define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ #define CLONE_VM 0x00000100 /* set if VM shared between processes */ *************** *** 272,281 **** --- 276,289 ---- 0-0xFFFFFFFF for kernel-thread */ struct exec_domain *exec_domain; volatile long need_resched; + #ifdef CONFIG_HRTIME + struct hrtime_struct *hrtime; + #endif + cycles_t avg_slice; int lock_depth; /* Lock depth. We can context switch in and out of holding a syscall kernel lock... */ /* begin intel cache line */ long counter; long priority; *************** *** 392,401 **** --- 400,450 ---- /* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ + #ifdef CONFIG_HRTIME + #define INIT_TASK(name) \ + /* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ + /* hrtime */ &init_hrtime, \ + /* avg_slice */ 0, -1, \ + /* counter */ DEF_PRIORITY,DEF_PRIORITY,SCHED_OTHER, \ + /* mm */ NULL, &init_mm, \ + /* has_cpu */ 0,0, \ + /* run_list */ LIST_HEAD_INIT(init_task.run_list), \ + /* next_task */ &init_task,&init_task, \ + /* last_proc */ 0, \ + /* binfmt */ NULL, \ + /* ec,brk... */ 0,0,0,0,0,0, \ + /* pid etc.. */ 0,0,0,0,0, \ + /* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \ + /* pidhash */ NULL, NULL, \ + /* chld wait */ __WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \ + /* timeout */ 0,0,0,0,0,0,0, \ + /* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ + /* utime */ {0,0,0,0},0, \ + /* per CPU times */ {0, }, {0, }, \ + /* flt */ 0,0,0,0,0,0, \ + /* swp */ 0, \ + /* process credentials */ \ + /* uid etc */ 0,0,0,0,0,0,0,0, \ + /* suppl grps*/ 0, {0,}, \ + /* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ + /* user */ NULL, \ + /* rlimits */ INIT_RLIMITS, \ + /* math */ 0, \ + /* comm */ "swapper", \ + /* fs info */ 0,NULL, \ + /* ipc */ NULL, NULL, \ + /* thread */ INIT_THREAD, \ + /* fs */ &init_fs, \ + /* files */ &init_files, \ + /* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ + /* exec cts */ 0,0, \ + /* exit_sem */ __MUTEX_INITIALIZER(name.exit_sem), \ + } + #else #define INIT_TASK(name) \ /* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ /* avg_slice */ 0, -1, \ /* counter */ DEF_PRIORITY,DEF_PRIORITY,SCHED_OTHER, \ /* mm */ NULL, &init_mm, \ *************** *** 430,439 **** --- 479,489 ---- /* files */ &init_files, \ /* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ /* exec cts */ 0,0, \ /* exit_sem */ __MUTEX_INITIALIZER(name.exit_sem), \ } + #endif #ifndef INIT_TASK_SIZE # define INIT_TASK_SIZE 2048*sizeof(long) #endif diff -rc5N linux-2.3.39/kernel/Makefile linux-2.3.39-hrtime/kernel/Makefile *** linux-2.3.39/kernel/Makefile Mon Jan 10 20:15:58 2000 --- linux-2.3.39-hrtime/kernel/Makefile Tue Jan 11 13:47:39 2000 *************** *** 23,30 **** --- 23,34 ---- ifeq ($(CONFIG_MODULES),y) OX_OBJS += ksyms.o endif + ifeq ($(CONFIG_HRTIME),y) + OX_OBJS += hrtime.o + endif + CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer include $(TOPDIR)/Rules.make diff -rc5N linux-2.3.39/kernel/exit.c linux-2.3.39-hrtime/kernel/exit.c *** linux-2.3.39/kernel/exit.c Mon Nov 8 12:19:19 1999 --- linux-2.3.39-hrtime/kernel/exit.c Tue Jan 11 13:47:39 2000 *************** *** 43,52 **** --- 43,75 ---- release_thread(p); current->cmin_flt += p->min_flt + p->cmin_flt; current->cmaj_flt += p->maj_flt + p->cmaj_flt; current->cnswap += p->nswap + p->cnswap; + #ifdef CONFIG_HRTIME + { + hrtime_t t; + get_current_hrtime(&t); + + p->hrtime->vtime += t - p->hrtime->last_dispatch; + + /* see sched.c for why we set this to zero */ + p->hrtime->last_dispatch = 0; + #ifdef CONFIG_HRUSTIME + t -= p->hrtime->last_us_dispatch; + if (p->hrtime->in_system) + p->hrtime->stime += t; + else + p->hrtime->utime += t; + + /* see sched.c for why we set this to zero */ + p->hrtime->last_us_dispatch = 0; + #endif + } + unref_hrtime_struct(p->hrtime); + p->hrtime = 0; + #endif free_task_struct(p); } else { printk("task releasing itself\n"); } } *************** *** 410,419 **** --- 433,458 ---- #endif __exit_files(tsk); __exit_fs(tsk); __exit_sighand(tsk); exit_thread(); + #ifdef CONFIG_HRTIME + { + hrtime_t t; + get_current_hrtime(&t); + + tsk->hrtime->vtime += t - tsk->hrtime->last_dispatch; + + #ifdef CONFIG_HRUSTIME + t -= tsk->hrtime->last_us_dispatch; + if (tsk->hrtime->in_system) + tsk->hrtime->stime += t; + else + tsk->hrtime->utime += t; + #endif + } + #endif tsk->state = TASK_ZOMBIE; tsk->exit_code = code; exit_notify(); task_unlock(tsk); #ifdef DEBUG_PROC_TREE diff -rc5N linux-2.3.39/kernel/fork.c linux-2.3.39-hrtime/kernel/fork.c *** linux-2.3.39/kernel/fork.c Mon Dec 13 17:39:24 1999 --- linux-2.3.39-hrtime/kernel/fork.c Tue Jan 11 13:47:39 2000 *************** *** 589,598 **** --- 589,601 ---- */ int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs) { int retval = -ENOMEM; struct task_struct *p; + #ifdef CONFIG_HRTIME + struct hrtime_struct *h; + #endif DECLARE_MUTEX_LOCKED(sem); if (clone_flags & CLONE_PID) { /* This is only allowed from the boot up thread */ if (current->pid) *************** *** 603,612 **** --- 606,624 ---- p = alloc_task_struct(); if (!p) goto fork_out; + #ifdef CONFIG_HRTIME + h = alloc_hrtime_struct(); + if (!h) + { + free_task_struct(p); + goto fork_out; + } + #endif + *p = *current; lock_kernel(); retval = -EAGAIN; *************** *** 665,674 **** --- 677,694 ---- p->leader = 0; /* session leadership doesn't inherit */ p->tty_old_pgrp = 0; p->times.tms_utime = p->times.tms_stime = 0; p->times.tms_cutime = p->times.tms_cstime = 0; + + #ifdef CONFIG_HRTIME + p->hrtime = h; + /* re-zero on fork - is this the semantic that we want? */ + init_hrtime_struct(p->hrtime); + ref_hrtime_struct(p->hrtime); + #endif + #ifdef __SMP__ { int i; p->has_cpu = 0; p->processor = current->processor; diff -rc5N linux-2.3.39/kernel/hrtime.c linux-2.3.39-hrtime/kernel/hrtime.c *** linux-2.3.39/kernel/hrtime.c Wed Dec 31 19:00:00 1969 --- linux-2.3.39-hrtime/kernel/hrtime.c Tue Jan 11 13:47:39 2000 *************** *** 0 **** --- 1,119 ---- + /* + * linux/kernel/hrtime.c + * + * Copyright (C) 1999, Nick Rasmussen <nick@jive.org> + */ + + #include <linux/hrtime.h> + #include <linux/sched.h> + #include <linux/linkage.h> + #include <linux/mm.h> + #include <linux/wrapper.h> + #include <linux/spinlock.h> + + #include <asm/hrtime.h> + #include <asm/io.h> + #include <asm/uaccess.h> + #include <asm/atomic.h> + + #define HRTIME_DEBUG_ALLOC 0 + + #if HRTIME_DEBUG_ALLOC + static volatile atomic_t num_hrtime_structs = ATOMIC_INIT(1); /* due to init_hrtime */ + #endif + + struct hrtime_struct *alloc_hrtime_struct() + { + unsigned long page; + + /* Should this be using vmalloc etc. as does drivers/char/bttv.c? */ + struct hrtime_struct *hr = (struct hrtime_struct *) __get_free_page(GFP_KERNEL); + if (hr != 0) + { + page = virt_to_phys(hr); + mem_map_reserve(MAP_NR(__va(page))); + #if HRTIME_DEBUG_ALLOC + atomic_inc(&num_hrtime_structs); + printk("alloc_hrtime_struct: num_hrtime_structs are %d\n", atomic_read(&num_hrtime_structs)); + #endif + } + return hr; + } + + static void free_hrtime_struct(struct hrtime_struct *s) + { + unsigned long page; + if (s == 0) + return; + + page = virt_to_phys(s); + mem_map_unreserve(MAP_NR(__va(page))); + free_page((unsigned long) s); + + #if HRTIME_DEBUG_ALLOC + atomic_dec(&num_hrtime_structs); + printk("free_hrtime_struct: num_hrtime_structs are %d\n", atomic_read(&num_hrtime_structs)); + #endif + } + + void init_hrtime_struct(struct hrtime_struct *s) + { + get_current_hrtime(&s->start_time); + + /* These are meaningless when CONFIG_HRUSTIME is not defined */ + s->last_us_dispatch = s->start_time; + s->utime = 0; + s->stime = 0; + + /* in_system starts out as zero since processes exiting from fork + * do not leave on the system call return path. */ + s->in_system = 0; + + #ifdef CONFIG_HRUSTIME + s->has_ustime = 1; + #else + s->has_ustime = 0; + #endif + + s->last_dispatch = s->start_time; + s->vtime = 0; + + /* XXX - FIXME when we do the cpu offset timings */ + s->offset_to_cpu0 = 0; + + s->refcount = 0; + s->reflock = SPIN_LOCK_UNLOCKED; + } + + void ref_hrtime_struct(struct hrtime_struct *s) + { + unsigned long flags; + + if (s == 0) + return; + + spin_lock_irqsave(&s->reflock, flags); + s->refcount += 1; + spin_unlock_irqrestore(&s->reflock, flags); + } + + void unref_hrtime_struct(struct hrtime_struct *s) + { + unsigned long flags; + + if (s == 0) + return; + + spin_lock_irqsave(&s->reflock, flags); + s->refcount -= 1; + + if (s->refcount == 0) + free_hrtime_struct(s); + + if (s->refcount < 0) + printk("unref_hrtime_struct: unreffing s@0x%08lx, " + "refcount %ld is now negative\n", + (unsigned long) s, s->refcount); + + spin_unlock_irqrestore(&s->reflock, flags); + } diff -rc5N linux-2.3.39/kernel/sched.c linux-2.3.39-hrtime/kernel/sched.c *** linux-2.3.39/kernel/sched.c Sat Jan 8 15:12:22 2000 --- linux-2.3.39-hrtime/kernel/sched.c Tue Jan 11 13:47:39 2000 *************** *** 25,35 **** #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> ! extern void timer_bh(void); extern void tqueue_bh(void); extern void immediate_bh(void); --- 25,37 ---- #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> ! #ifdef CONFIG_HRTIME ! #include <asm/hrtime.h> ! #endif extern void timer_bh(void); extern void tqueue_bh(void); extern void immediate_bh(void); *************** *** 561,570 **** --- 563,602 ---- * rescheduled during switch_to(). */ #endif /* __SMP__ */ + #ifdef CONFIG_HRTIME + { + hrtime_t t; + get_current_hrtime(&t); + + prev->hrtime->vtime += t - prev->hrtime->last_dispatch; + + /* A poor man's interprocess synchronization - by overloading + * last_dispatch to also indicate that the process is currently + * executing, the spin-loop in the get_hr[usv]time to make sure + * that this process' hrtime_struct is self-consistent is + * simplified a bit. With no good way of doing atomic operations + * between the two processes, having last_dispatch change both + * when the process is swapped out and swapped in is an almost + * foolproof way of doing this. + */ + prev->hrtime->last_dispatch = 0; + #ifdef CONFIG_HRUSTIME + t -= prev->hrtime->last_us_dispatch; + if (prev->hrtime->in_system) + prev->hrtime->stime += t; + else + prev->hrtime->utime += t; + + /* ditto for last_us_dispatch */ + prev->hrtime->last_us_dispatch = 0; + #endif + } + #endif + kstat.context_swtch++; /* * there are 3 processes which are affected by a context switch: * * prev == .... ==> (last => next) *************** *** 596,605 **** --- 628,647 ---- * This just switches the register state and the * stack. */ switch_to(prev, next, prev); __schedule_tail(prev); + + #ifdef CONFIG_HRTIME + #if HRTIME_HAS_OFFSETS + /* XXX - FIXME - find CPU and insert offset */ + #endif + get_current_hrtime(¤t->hrtime->last_dispatch); + #ifdef CONFIG_HRUSTIME + get_current_hrtime(¤t->hrtime->last_us_dispatch); + #endif + #endif same_process: reacquire_kernel_lock(current); return;
| |