2.4.18 includes a patch to set a local symbol for the start of out-of-line .text.lock (now subsection 1 of .text) code, but it merges the entire translation unit's out of line code under the one symbol, and can give erroneous results when two files have the same KBUILD_BASENAME. The patch below details exactly where such code comes from, so you can get : ... 53 __stabslock-at-dec_and_lock.c-line-35 2.2083 233 __stabs&pagemap_lru_lock-at-swap.c-line-49 14.5625 381 __stabs&kernel_flag-at-sched.c-line-701 23.8125 ... from readprofile (actually you need a modified version, attached). (I haven't yet updated this for kaos' LOCK_START etc. patch) regards john --- linux/arch/i386/config.in.old Sun Mar 10 23:21:42 2002 +++ linux/arch/i386/config.in Sun Mar 10 23:32:05 2002 @@ -421,6 +421,7 @@ bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK + bool ' .text.lock debugging symbols' CONFIG_DEBUG_TEXT_LOCK_STABS bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE fi --- /dev/null Thu Aug 24 10:00:32 2000 +++ linux/include/asm-i386/text_lock_stabs.h Mon Mar 11 15:09:59 2002 @@ -0,0 +1,44 @@ +/* text_lock_stabs.h - common stabs symbol code for .text.lock code + * + * Copyright John Levon 2002 + */ + +#ifndef TEXT_LOCK_STABS_H +#define TEXT_LOCK_STABS_H + +#include +#include + +#ifdef CONFIG_DEBUG_TEXT_LOCK_STABS + +#define __stabs_string(l) \ + /* set label to the current address */ \ + /* in .text.lock */ \ + "\t.subsection 1\n" \ + "\t7:\n" \ + "\t.subsection 0\n" \ + \ + /* make a file .stabs */ \ + "\t.stabs \"" __FILE__ "\"" \ + ",100,0,0,0\n" \ + \ + /* and generate the useful entry */ \ + "\t.stabs " "\"__stabs" #l \ + "-at-" __FILE__ \ + "-line-" __stringify(__LINE__) \ + ":F(0,0)\",36,0,6,7b\n" \ + +#define __stabs_common(o,l) \ + ({ \ + __asm__ __volatile__( \ + __stabs_string(l) \ + : : ); \ + o(l); \ + }) + +#else +#define __stabs_string(l) +#define __stabs_common(o,l) o(l) +#endif /* CONFIG_DEBUG_SPINLOCK_STABS */ + +#endif /* TEXT_LOCK_STABS_H */ --- linux/include/linux/rwsem.old.h Sun Mar 10 23:21:52 2002 +++ linux/include/linux/rwsem.h Mon Mar 11 00:24:17 2002 @@ -35,45 +35,33 @@ #endif #endif -/* - * lock for reading - */ -static inline void down_read(struct rw_semaphore *sem) -{ - rwsemtrace(sem,"Entering down_read"); - __down_read(sem); - rwsemtrace(sem,"Leaving down_read"); -} - -/* - * lock for writing - */ -static inline void down_write(struct rw_semaphore *sem) -{ - rwsemtrace(sem,"Entering down_write"); - __down_write(sem); - rwsemtrace(sem,"Leaving down_write"); -} - -/* - * release a read lock - */ -static inline void up_read(struct rw_semaphore *sem) -{ - rwsemtrace(sem,"Entering up_read"); - __up_read(sem); - rwsemtrace(sem,"Leaving up_read"); -} - -/* - * release a write lock - */ -static inline void up_write(struct rw_semaphore *sem) -{ - rwsemtrace(sem,"Entering up_write"); - __up_write(sem); - rwsemtrace(sem,"Leaving up_write"); -} - +#define down_read(sem) \ + do { \ + rwsemtrace(sem,"Entering down_read"); \ + __down_read(sem); \ + rwsemtrace(sem,"Leaving down_read"); \ + } while (0) \ + +#define down_write(sem) \ + do { \ + rwsemtrace(sem,"Entering down_write"); \ + __down_write(sem); \ + rwsemtrace(sem,"Leaving down_write"); \ + } while (0) \ + +#define up_read(sem) \ + do { \ + rwsemtrace(sem,"Entering up_read"); \ + __up_read(sem); \ + rwsemtrace(sem,"Leaving up_read"); \ + } while (0) \ + +#define up_write(sem) \ + do { \ + rwsemtrace(sem,"Entering up_write"); \ + __up_write(sem); \ + rwsemtrace(sem,"Leaving up_write"); \ + } while (0) \ + #endif /* __KERNEL__ */ #endif /* _LINUX_RWSEM_H */ --- linux/include/asm-i386/semaphore.old.h Sun Mar 10 23:21:59 2002 +++ linux/include/asm-i386/semaphore.h Mon Mar 11 00:24:17 2002 @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -112,7 +113,7 @@ * "__down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/i386/kernel/semaphore.c */ -static inline void down(struct semaphore * sem) +static inline void p__down(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -124,9 +125,6 @@ "js 2f\n" "1:\n" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\tcall __down_failed\n\t" "jmp 1b\n" ".subsection 0\n" @@ -139,7 +137,7 @@ * Interruptible try to acquire a semaphore. If we obtained * it, return zero. If we were interrupted, returns -EINTR */ -static inline int down_interruptible(struct semaphore * sem) +static inline int p__down_interruptible(struct semaphore * sem) { int result; @@ -154,9 +152,6 @@ "xorl %0,%0\n" "1:\n" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\tcall __down_failed_interruptible\n\t" "jmp 1b\n" ".subsection 0\n" @@ -170,7 +165,7 @@ * Non-blockingly attempt to down() a semaphore. * Returns zero if we acquired it */ -static inline int down_trylock(struct semaphore * sem) +static inline int p__down_trylock(struct semaphore * sem) { int result; @@ -185,9 +180,6 @@ "xorl %0,%0\n" "1:\n" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\tcall __down_failed_trylock\n\t" "jmp 1b\n" ".subsection 0\n" @@ -203,7 +195,7 @@ * The default case (no contention) will result in NO * jumps for both down() and up(). */ -static inline void up(struct semaphore * sem) +static inline void p__up(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -214,9 +206,6 @@ "jle 2f\n" "1:\n" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\tcall __up_wakeup\n\t" "jmp 1b\n" ".subsection 0\n" @@ -224,6 +213,11 @@ :"c" (sem) :"memory"); } + +#define down(s) __stabs_common(p__down, s) +#define down_interruptible(s) __stabs_common(p__down_interruptible, s) +#define down_trylock(s) __stabs_common(p__down_trylock, s) +#define up(s) __stabs_common(p__up, s) #endif #endif --- linux/include/asm-i386/rwsem.old.h Sun Mar 10 23:22:05 2002 +++ linux/include/asm-i386/rwsem.h Mon Mar 11 00:24:17 2002 @@ -38,6 +38,7 @@ #ifdef __KERNEL__ +#include #include #include #include @@ -95,7 +96,7 @@ /* * lock for reading */ -static inline void __down_read(struct rw_semaphore *sem) +static inline void p__down_read(struct rw_semaphore *sem) { __asm__ __volatile__( "# beginning down_read\n\t" @@ -103,9 +104,6 @@ " js 2f\n\t" /* jump if we weren't granted the lock */ "1:\n\t" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\n\t" " pushl %%ecx\n\t" " pushl %%edx\n\t" @@ -123,7 +121,7 @@ /* * lock for writing */ -static inline void __down_write(struct rw_semaphore *sem) +static inline void p__down_write(struct rw_semaphore *sem) { int tmp; @@ -135,9 +133,6 @@ " jnz 2f\n\t" /* jump if we weren't granted the lock */ "1:\n\t" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\n\t" " pushl %%ecx\n\t" " call rwsem_down_write_failed\n\t" @@ -153,7 +148,7 @@ /* * unlock after reading */ -static inline void __up_read(struct rw_semaphore *sem) +static inline void p__up_read(struct rw_semaphore *sem) { __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; __asm__ __volatile__( @@ -162,9 +157,6 @@ " js 2f\n\t" /* jump if the lock is being waited upon */ "1:\n\t" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\n\t" " decw %%dx\n\t" /* do nothing if still outstanding active readers */ " jnz 1b\n\t" @@ -182,7 +174,7 @@ /* * unlock after writing */ -static inline void __up_write(struct rw_semaphore *sem) +static inline void p__up_write(struct rw_semaphore *sem) { __asm__ __volatile__( "# beginning __up_write\n\t" @@ -191,9 +183,6 @@ " jnz 2f\n\t" /* jump if the lock is being waited upon */ "1:\n\t" ".subsection 1\n" - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" - ".endif\n" "2:\n\t" " decw %%dx\n\t" /* did the active count reduce to 0? */ " jnz 1b\n\t" /* jump back if not */ @@ -235,5 +224,10 @@ return tmp+delta; } +#define __down_read(s) __stabs_common(p__down_read, s) +#define __down_write(s) __stabs_common(p__down_write, s) +#define __up_read(s) __stabs_common(p__up_read, s) +#define __up_write(s) __stabs_common(p__up_write, s) + #endif /* __KERNEL__ */ #endif /* _I386_RWSEM_H */ --- linux/include/asm-i386/spinlock.old.h Sun Mar 10 23:22:10 2002 +++ linux/include/asm-i386/spinlock.h Mon Mar 11 00:24:17 2002 @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -58,9 +59,6 @@ "lock ; decb %0\n\t" \ "js 2f\n" \ ".subsection 1\n" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2:\t" \ "cmpb $0,%0\n\t" \ "rep;nop\n\t" \ @@ -127,7 +125,7 @@ return oldval > 0; } -static inline void spin_lock(spinlock_t *lock) +static inline void p__spin_lock(spinlock_t *lock) { #if SPINLOCK_DEBUG __label__ here; @@ -142,6 +140,7 @@ :"=m" (lock->lock) : : "memory"); } +#define spin_lock(l) __stabs_common(p__spin_lock,l) /* * Read-write spinlocks, allowing multiple readers @@ -183,7 +182,7 @@ */ /* the spinlock helpers are in arch/i386/kernel/semaphore.c */ -static inline void read_lock(rwlock_t *rw) +static inline void p__read_lock(rwlock_t *rw) { #if SPINLOCK_DEBUG if (rw->magic != RWLOCK_MAGIC) @@ -192,7 +191,7 @@ __build_read_lock(rw, "__read_lock_failed"); } -static inline void write_lock(rwlock_t *rw) +static inline void p__write_lock(rwlock_t *rw) { #if SPINLOCK_DEBUG if (rw->magic != RWLOCK_MAGIC) @@ -200,6 +199,9 @@ #endif __build_write_lock(rw, "__write_lock_failed"); } + +#define read_lock(r) __stabs_common(p__read_lock, r) +#define write_lock(r) __stabs_common(p__write_lock, r) #define read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") #define write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") --- linux/include/asm-i386/rwlock.old.h Sun Mar 10 23:22:14 2002 +++ linux/include/asm-i386/rwlock.h Mon Mar 11 00:14:04 2002 @@ -27,9 +27,6 @@ "js 2f\n" \ "1:\n" \ ".subsection 1\n" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2:\tcall " helper "\n\t" \ "jmp 1b\n" \ ".subsection 0\n" \ @@ -40,9 +37,6 @@ "js 2f\n" \ "1:\n" \ ".subsection 1\n" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2:\tpushl %%eax\n\t" \ "leal %0,%%eax\n\t" \ "call " helper "\n\t" \ @@ -63,9 +57,6 @@ "jnz 2f\n" \ "1:\n" \ ".subsection 1\n" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2:\tcall " helper "\n\t" \ "jmp 1b\n" \ ".subsection 0\n" \ @@ -76,9 +67,6 @@ "jnz 2f\n" \ "1:\n" \ ".subsection 1\n" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2:\tpushl %%eax\n\t" \ "leal %0,%%eax\n\t" \ "call " helper "\n\t" \ --- linux/include/asm-i386/softirq.old.h Sun Mar 10 23:22:20 2002 +++ linux/include/asm-i386/softirq.h Mon Mar 11 15:10:40 2002 @@ -3,6 +3,7 @@ #include #include +#include #include #define __cpu_bh_enable(cpu) \ @@ -34,10 +35,9 @@ "jnz 2f;" \ "1:;" \ \ + __stabs_string(local_bh_enable) \ + \ ".subsection 1;" \ - ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \ - "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \ - ".endif\n" \ "2: pushl %%eax; pushl %%ecx; pushl %%edx;" \ "call %c1;" \ "popl %%edx; popl %%ecx; popl %%eax;" \ --- linux/include/asm-i386/smplock.old.h Sun Mar 10 23:22:24 2002 +++ linux/include/asm-i386/smplock.h Mon Mar 11 00:24:17 2002 @@ -40,36 +40,15 @@ * so we only need to worry about other * CPU's. */ -static __inline__ void lock_kernel(void) -{ -#if 1 - if (!++current->lock_depth) - spin_lock(&kernel_flag); -#else - __asm__ __volatile__( - "incl %1\n\t" - "jne 9f" - spin_lock_string - "\n9:" - :"=m" (__dummy_lock(&kernel_flag)), - "=m" (current->lock_depth)); -#endif -} +#define lock_kernel() do { \ + if (!++current->lock_depth) \ + __stabs_common(p__spin_lock, &kernel_flag); \ + } while (0) static __inline__ void unlock_kernel(void) { if (current->lock_depth < 0) BUG(); -#if 1 if (--current->lock_depth < 0) spin_unlock(&kernel_flag); -#else - __asm__ __volatile__( - "decl %1\n\t" - "jns 9f\n\t" - spin_unlock_string - "\n9:" - :"=m" (__dummy_lock(&kernel_flag)), - "=m" (current->lock_depth)); -#endif } --- linux/Documentation/Configure.help.old Sun Mar 10 23:22:30 2002 +++ linux/Documentation/Configure.help Sun Mar 10 23:32:05 2002 @@ -24006,6 +24006,12 @@ verbose debugging messages. If you suspect a semaphore problem or a kernel hacker asks for this option then say Y. Otherwise say N. +Lock debugging +CONFIG_DEBUG_TEXT_LOCK_STABS + If you say Y here then debugging symbols will be created for each + piece of .text.lock code that corresponds to the contention path for + the locking primitives. + Verbose BUG() reporting (adds 70K) CONFIG_DEBUG_BUGVERBOSE Say Y here to make BUG() panics output the file name and line number --- linux/Makefile.old Sun Mar 10 23:24:33 2002 +++ linux//Makefile Mon Mar 11 13:13:49 2002 @@ -229,6 +229,7 @@ .version .config* config.in config.old \ scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ + scripts/add_lock_syms scripts/add_lock_syms.o \ .menuconfig.log \ include/asm \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ @@ -268,6 +269,17 @@ --end-group \ -o vmlinux $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + if [ "$(CONFIG_DEBUG_TEXT_LOCK_STABS)" = "y" ]; then \ + $(MAKE) map-stabs; \ + fi + +map-stabs: scripts/add_lock_syms + cp System.map System.map.tmp + scripts/add_lock_syms vmlinux >> System.map.tmp + cat System.map.tmp | sort -u >System.map + +scripts/add_lock_syms: scripts/add_lock_syms.c + $(MAKE) -C scripts add_lock_syms symlinks: rm -f include/asm --- linux/scripts/Makefile.old Sun Mar 10 23:28:10 2002 +++ linux/scripts/Makefile Sun Mar 10 23:29:15 2002 @@ -42,4 +42,7 @@ clean: rm -f *~ kconfig.tk *.o tkparse mkdep split-include docproc +add_lock_syms: add_lock_syms.c + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< + include $(TOPDIR)/Rules.make --- /dev/null Thu Aug 24 10:00:32 2000 +++ linux/scripts/add_lock_syms.c Sun Mar 10 23:53:28 2002 @@ -0,0 +1,102 @@ +/* Copyright 2002 John Levon + * + * usage: add_lock_syms vmlinux | sort -u >>System.map + */ + +#define _GNU_SOURCE +#include +#include +#include + +typedef unsigned long addr_t; + +char * get_lock_name(char * raw) +{ + char * name = strdup(raw); + + if (!name) { + fprintf(stderr, "add_lock_syms: Failed to strdup.\n"); + exit(1); + } + + name[strlen(name) - 3] = '\0'; + return name; +} + + +addr_t get_vma(char * raw) +{ + addr_t vma; + + if (sscanf(raw, "%lx", &vma) != 1) { + fprintf(stderr, "add_lock_syms: Malformed line.\n"); + exit(1); + } + + return vma; +} + + +#if 0 + text_lock_&bdev_lock-at-block_dev.c-line-333 () +{ /* 0xc01f9df4 */ +} /* 0x0 */ +#endif +void read_objdump_g(FILE * fp) +{ + char * lock_name = NULL; + char * line = NULL; + size_t max_len = 0; + ssize_t len; + + while ((len = getline(&line, &max_len, fp)) != -1) { + if ((size_t)len > strlen(" ") && line[0] == '<') { + lock_name = get_lock_name(line + strlen(" ")); + } else if ((size_t)len > strlen("{ /* 0x") && line[0] == '{') { + printf("%lx t %s\n", get_vma(line + 7), lock_name); + free(lock_name); + } + } + + if (line) { + free(line); + } +} + + +int main(int argc, char **argv) +{ + char * odcmd = "objdump -g "; + char * cmd; + char const * vmlinux; + FILE * fp; + + if (argc < 2) { + fprintf(stderr, "add_lock_syms: no vmlinux file specified.\n"); + return 1; + } + + vmlinux = argv[1]; + + cmd = malloc(strlen(odcmd) + strlen(vmlinux) + 1); + if (!cmd) { + fprintf(stderr, "add_lock_syms: malloc failed.\n"); + return 1; + } + + strcpy(cmd, odcmd); + strcat(cmd, vmlinux); + + fp = popen(cmd, "r"); + + if (!fp) { + fprintf(stderr, "add_lock_syms: couldn't open objdump pipe.\n"); + return 1; + } + + read_objdump_g(fp); + + pclose(fp); + + return 0; +}