Skip to contentSkip to conversation

oprofile - timer hook

PATCH In review John Levon 1 participant 1 message Oct 15, 2002

Subsystems (2)
lore
Share & tools
lore

John Levon

author
#0 lore raw

PATCH 3/7 oprofile - timer hook

This patch implements a simple hook into the profiling timer for x86 so that non-perfctr machines can still use oprofile. This has proven useful for laptops and the like.

It also reduces header dependencies a bit by centralising readprofile code

arch/i386/kernel/Makefile +1 -0
diff -Naur -X dontdiff linux-linus/arch/i386/kernel/Makefile linux-linus2/arch/i386/kernel/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
+obj-$(CONFIG_PROFILING)		+= profile.o
 
 EXTRA_AFLAGS   := -traditional
 
arch/i386/kernel/apic.c +2 -10
diff -Naur -X dontdiff linux-linus/arch/i386/kernel/apic.c linux-linus2/arch/i386/kernel/apic.c
@@ -1008,17 +1008,9 @@
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-	int user = user_mode(regs);
 	int cpu = smp_processor_id();
 
-	/*
-	 * The profiling function is SMP safe. (nothing can mess
-	 * around with "current", and the profiling counters are
-	 * updated with atomic operations). This is especially
-	 * useful with a profiling multiplier != 1
-	 */
-	if (!user)
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 
 	if (--prof_counter[cpu] <= 0) {
 		/*
@@ -1036,7 +1028,7 @@
 		}
 
 #ifdef CONFIG_SMP
-		update_process_times(user);
+		update_process_times(user_mode(regs));
 #endif
 	}
 
arch/i386/kernel/i386_ksyms.c +3 -0
diff -Naur -X dontdiff linux-linus/arch/i386/kernel/i386_ksyms.c linux-linus2/arch/i386/kernel/i386_ksyms.c
@@ -167,6 +167,9 @@
 
 EXPORT_SYMBOL(rtc_lock);
 
+EXPORT_SYMBOL_GPL(register_profile_notifier);
+EXPORT_SYMBOL_GPL(unregister_profile_notifier);
+ 
 #undef memcpy
 #undef memset
 extern void * memset(void *,int,__kernel_size_t);
arch/i386/kernel/profile.c +45 -0

45 lines not on this page · raw message

arch/i386/kernel/time.c +0 -5
diff -Naur -X dontdiff linux-linus/arch/i386/kernel/time.c linux-linus2/arch/i386/kernel/time.c
@@ -64,11 +64,6 @@
 
 #include "do_timer.h"
 
-/*
- * for x86_do_profile()
- */
-#include <linux/irq.h>
-
 u64 jiffies_64;
 
 unsigned long cpu_khz;	/* Detected as we calibrate the TSC */
arch/i386/mach-generic/do_timer.h +1 -2
diff -Naur -X dontdiff linux-linus/arch/i386/mach-generic/do_timer.h linux-linus2/arch/i386/mach-generic/do_timer.h
@@ -20,8 +20,7 @@
  * system, in that case we have to call the local interrupt handler.
  */
 #ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 #else
 	if (!using_apic_timer)
 		smp_local_timer_interrupt(regs);
arch/i386/mach-visws/do_timer.h +1 -2
diff -Naur -X dontdiff linux-linus/arch/i386/mach-visws/do_timer.h linux-linus2/arch/i386/mach-visws/do_timer.h
@@ -15,8 +15,7 @@
  * system, in that case we have to call the local interrupt handler.
  */
 #ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 #else
 	if (!using_apic_timer)
 		smp_local_timer_interrupt(regs);
fs/proc/proc_misc.c +1 -0
diff -Naur -X dontdiff linux-linus/fs/proc/proc_misc.c linux-linus2/fs/proc/proc_misc.c
@@ -38,6 +38,7 @@
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/times.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
include/asm-i386/hw_irq.h +41 -8

74 lines not on this page · raw message

include/linux/profile.h +11 -0
diff -Naur -X dontdiff linux-linus/include/linux/profile.h linux-linus2/include/linux/profile.h
@@ -8,6 +8,17 @@
 #include <linux/init.h>
 #include <asm/errno.h>
  
+/* parse command line */
+int __init profile_setup(char * str);
+ 
+/* init basic kernel profiler */
+void __init profile_init(void);
+
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+
 enum profile_type {
 	EXIT_TASK,
 	EXIT_MMAP,
include/linux/sched.h +0 -4
diff -Naur -X dontdiff linux-linus/include/linux/sched.h linux-linus2/include/linux/sched.h
@@ -492,10 +492,6 @@
 extern unsigned long itimer_next;
 extern void do_timer(struct pt_regs *);
 
-extern unsigned int * prof_buffer;
-extern unsigned long prof_len;
-extern unsigned long prof_shift;
-
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
init/main.c +2 -18
diff -Naur -X dontdiff linux-linus/init/main.c linux-linus2/init/main.c
@@ -30,6 +30,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/security.h>
 #include <linux/workqueue.h>
+#include <linux/profile.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -52,7 +53,6 @@
 #error Sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
-extern char _stext, _etext;
 extern char *linux_banner;
 
 static int init(void *);
@@ -130,13 +130,6 @@
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 
-static int __init profile_setup(char *str)
-{
-    int par;
-    if (get_option(&str,&par)) prof_shift = par;
-	return 1;
-}
-
 __setup("profile=", profile_setup);
 
 static int __init checksetup(char *line)
@@ -411,16 +404,7 @@
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
-	if (prof_shift) {
-		unsigned int size;
-		/* only text is profiled */
-		prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
-		prof_len >>= prof_shift;
-		
-		size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1;
-		prof_buffer = (unsigned int *) alloc_bootmem(size);
-	}
-
+	profile_init();
 	kmem_cache_init();
 	local_irq_enable();
 	calibrate_delay();
kernel/profile.c +30 -0
diff -Naur -X dontdiff linux-linus/kernel/profile.c linux-linus2/kernel/profile.c
@@ -9,6 +9,36 @@
 #include <linux/notifier.h>
 #include <linux/mm.h>
 
+extern char _stext, _etext;
+
+unsigned int * prof_buffer;
+unsigned long prof_len;
+unsigned long prof_shift;
+
+int __init profile_setup(char * str)
+{
+	int par;
+	if (get_option(&str,&par))
+		prof_shift = par;
+	return 1;
+}
+
+
+void __init profile_init(void)
+{
+	unsigned int size;
+ 
+	if (!prof_shift) 
+		return;
+ 
+	/* only text is profiled */
+	prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
+	prof_len >>= prof_shift;
+		
+	size = prof_len * sizeof(unsigned int) + PAGE_SIZE - 1;
+	prof_buffer = (unsigned int *) alloc_bootmem(size);
+}
+
 /* Profile event notifications */
  
 #ifdef CONFIG_PROFILING
kernel/timer.c +0 -4
diff -Naur -X dontdiff linux-linus/kernel/timer.c linux-linus2/kernel/timer.c
@@ -406,10 +406,6 @@
 long time_reftime;			/* time at last adjustment (s)	*/
 long time_adjust;
 
-unsigned int * prof_buffer;
-unsigned long prof_len;
-unsigned long prof_shift;
-
 /*
  * this routine handles the overflow of the microsecond field
  *