finish_task_switch high in profiles in 2.6.7
Subsystems (10)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 4 lines · Yusuf Goolamabbas
Hi, I have a fairly busy mailserver which also has a simple iptables ruleset (blocking some IP's) running 2.6.7 with the deadline i/o scheduler. vmstat was reporting that system time was around 80%. I did the following
How many context switches do you get in vmstat?
Most likely you just have far too many of them. readprofile will attribute most of the cost to finish_task_switch, because that one reenables the interrupts (and the profiling only works with interrupts on)
Too many context switches are usually caused by user space.
-Andi
Quoted 1 line
How many context switches do you get in vmstat?
Mentioned in a subsequent message
http://marc.theaimsgroup.com/?l=linux-kernel&m=108806991921498&w=2
Quoted 5 lines
Most likely you just have far too many of them. readprofile will attribute most of the cost to
finish_task_switch, because that one reenables the interrupts (and the profiling only works with interrupts on)Too many context switches are usually caused by user space.
Hmm, Is there a way to determine which syscall would be the culprit. I guess this is where something like DTrace would be invaluable
Quoted 2 lines
Hmm, Is there a way to determine which syscall would be the culprit. I guess this is where something like DTrace would be invaluable
Find out which program does it (most likely those with the most system time) and then strace it.
Quoted 2 lines
Sounds like a inferior clone of dprobes to me. But I doubt it would help tracking this down.
-Andi
Quoted 2 lines · Andi Kleen
Sounds like a inferior clone of dprobes to me. But I doubt it would help tracking this down.
The schedprof thing I wrote to track down the source of context switches during database creation may prove useful, since it has at least demonstrated where thundering herds came from properly once before and is damn near idiotproof -- it requires no more than readprofile(1) from userspace. I'll dredge that up again and maybe we'll see if it helps here. It will also properly point to sys_sched_yield() and the like in the event of badly-behaved userspace.
-- wli
Quoted 7 lines · William Lee Irwin III
The schedprof thing I wrote to track down the source of context switches during database creation may prove useful, since it has at least demonstrated where thundering herds came from properly once before and is damn near idiotproof -- it requires no more than readprofile(1) from userspace. I'll dredge that up again and maybe we'll see if it helps here. It will also properly point to
sys_sched_yield()and the like in the event of badly-behaved userspace.
Brute-force port of schedprof to 2.6.7-final. Compiletested on sparc64 only. No runtime testing.
Given that the context switch rate is actually *reduced* in 2.6.7 vs. 2.6.5, I expect that this will not, in fact, reveal anything useful.
-- wli
include/linux/sched.h +4 -0
@@ -180,7 +180,11 @@#define MAX_SCHEDULE_TIMEOUT LONG_MAXextern signed long FASTCALL (schedule_timeout (signed long timeout)); +extern signed long FASTCALL (__schedule_timeout (signed long timeout)); asmlinkage void schedule(void); +asmlinkage void __schedule(void); +void __sched_profile (void *); +#define sched_profile () __sched_profile(__builtin_return_address(0))struct namespace ;
include/linux/profile.h +1 -0
@@ -13,6 +13,7 @@/* init basic kernel profiler */ void __init profile_init (void ); +void schedprof_init (void );extern unsigned int * prof_buffer;extern unsigned long prof_len;
kernel/sched.c +124 -13
225 lines not on this page · raw message
kernel/timer.c +8 -3
@@ -1100,7 +1100,7 @@* * In all cases the return value is guaranteed to be non-negative. */ -fastcall signed long __sched schedule_timeout(signed long timeout) +fastcall signed long __sched __schedule_timeout(signed long timeout) {struct timer_list timer;unsigned long expire;
@@ -1115,7 +1115,7 @@* but I' d like to return a valid offset (>=0) to allow * the caller to do everything it want with the retval. */ -schedule (); +__schedule (); goto out;default :/*
@@ -1143,7 +1143,7 @@ timer.function = process_timeout;add_timer (&timer); -schedule (); +__schedule ();del_singleshot_timer_sync (&timer); timeout = expire - jiffies;
@@ -1152,6 +1152,11 @@return timeout <0 ?0 : timeout; } +fastcall signed long __sched schedule_timeout(signed long timeout) +{ +sched_profile (); +return __schedule_timeout (timeout); +}EXPORT_SYMBOL (schedule_timeout);/* Thread ID - the internal kernel "pid" */
arch/alpha/kernel/semaphore.c +4 -4
@@ -66,7 +66,6 @@ {struct task_struct *tsk = current;DECLARE_WAITQUEUE (wait, tsk); -#ifdef CONFIG_DEBUG_SEMAPHORE printk ("%s(%d): down failed(%p)\n" , tsk->comm, tsk->pid, sem);
@@ -83,7 +82,8 @@* that we are asleep, and then sleep. */ while (__sem_update_count (sem,-1 ) <=0 ) { -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_UNINTERRUPTIBLE ); }remove_wait_queue (&sem->wait, &wait);
@@ -108,7 +108,6 @@struct task_struct *tsk = current;DECLARE_WAITQUEUE (wait, tsk);long ret =0 ; -#ifdef CONFIG_DEBUG_SEMAPHORE printk ("%s(%d): down failed(%p)\n" , tsk->comm, tsk->pid, sem);
@@ -129,7 +128,8 @@ ret = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_INTERRUPTIBLE ); }
arch/arm/kernel/semaphore.c +4 -4
@@ -78,8 +78,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
@@ -128,8 +128,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
arch/arm26/kernel/semaphore.c +4 -4
@@ -79,8 +79,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
@@ -129,8 +129,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
arch/cris/kernel/semaphore.c +4 -2
@@ -101,7 +101,8 @@DOWN_HEAD (TASK_UNINTERRUPTIBLE) if (waking_non_zero(sem)) break; -schedule (); +sched_profile (); +__schedule (); DOWN_TAIL(TASK_UNINTERRUPTIBLE) }
@@ -119,7 +120,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();DOWN_TAIL (TASK_INTERRUPTIBLE) return ret; }
arch/h8300/kernel/semaphore.c +4 -2
@@ -103,7 +103,8 @@DOWN_HEAD (TASK_UNINTERRUPTIBLE) if (waking_non_zero(sem)) break; -schedule (); +sched_profile (); +__schedule (); DOWN_TAIL(TASK_UNINTERRUPTIBLE) }
@@ -122,7 +123,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();DOWN_TAIL (TASK_INTERRUPTIBLE) return ret; }
arch/i386/kernel/semaphore.c +4 -4
@@ -79,8 +79,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_UNINTERRUPTIBLE ;
@@ -132,8 +132,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_INTERRUPTIBLE ;
arch/ia64/kernel/semaphore.c +4 -4
@@ -70,8 +70,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_UNINTERRUPTIBLE ;
@@ -123,8 +123,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_INTERRUPTIBLE ;
arch/m68k/kernel/semaphore.c +4 -2
@@ -103,7 +103,8 @@DOWN_HEAD (TASK_UNINTERRUPTIBLE) if (waking_non_zero(sem)) break; -schedule (); +sched_profile (); +__schedule (); DOWN_TAIL(TASK_UNINTERRUPTIBLE) }
@@ -122,7 +123,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();DOWN_TAIL (TASK_INTERRUPTIBLE) return ret; }
arch/m68knommu/kernel/semaphore.c +4 -2
@@ -104,7 +104,8 @@DOWN_HEAD (TASK_UNINTERRUPTIBLE) if (waking_non_zero(sem)) break; -schedule (); +sched_profile (); +__schedule (); DOWN_TAIL(TASK_UNINTERRUPTIBLE) }
@@ -123,7 +124,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();DOWN_TAIL (TASK_INTERRUPTIBLE) return ret; }
arch/mips/kernel/semaphore.c +4 -2
@@ -132,7 +132,8 @@for (;;) {if (waking_non_zero (sem))break ; -schedule (); +sched_profile (); +__schedule ();__set_current_state (TASK_UNINTERRUPTIBLE ); }__set_current_state (TASK_RUNNING );
@@ -261,7 +262,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();__set_current_state (TASK_INTERRUPTIBLE ); }__set_current_state (TASK_RUNNING );
arch/parisc/kernel/semaphore.c +4 -2
@@ -68,7 +68,8 @@/* we can _read_ this without the sentry */ if (sem->count !=-1 )break ; -schedule (); +sched_profile (); +__schedule (); }DOWN_TAIL
@@ -89,7 +90,8 @@ ret = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule (); }DOWN_TAIL
arch/ppc/kernel/semaphore.c +4 -2
@@ -86,7 +86,8 @@* that we are asleep, and then sleep. */ while (__sem_update_count (sem,-1 ) <=0 ) { -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ; }remove_wait_queue (&sem->wait, &wait);
@@ -121,7 +122,8 @@ retval = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ; } tsk->state =TASK_RUNNING ;
arch/ppc64/kernel/semaphore.c +4 -2
@@ -86,7 +86,8 @@* that we are asleep, and then sleep. */ while (__sem_update_count (sem,-1 ) <=0 ) { -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_UNINTERRUPTIBLE ); }remove_wait_queue (&sem->wait, &wait);
@@ -120,7 +121,8 @@ retval = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_INTERRUPTIBLE ); }remove_wait_queue (&sem->wait, &wait);
arch/s390/kernel/semaphore.c +4 -2
@@ -69,7 +69,8 @@__set_task_state (tsk,TASK_UNINTERRUPTIBLE );add_wait_queue_exclusive (&sem->wait, &wait);while (__sem_update_count (sem,-1 ) <=0 ) { -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_UNINTERRUPTIBLE ); }remove_wait_queue (&sem->wait, &wait);
@@ -97,7 +98,8 @@ retval = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule ();set_task_state (tsk,TASK_INTERRUPTIBLE ); }remove_wait_queue (&sem->wait, &wait);
arch/sh/kernel/semaphore.c +4 -2
@@ -110,7 +110,8 @@DOWN_HEAD (TASK_UNINTERRUPTIBLE) if (waking_non_zero(sem)) break; -schedule (); +sched_profile (); +__schedule (); DOWN_TAIL(TASK_UNINTERRUPTIBLE) }
@@ -128,7 +129,8 @@ ret =0 ;break ; } -schedule (); +sched_profile (); +__schedule ();DOWN_TAIL (TASK_INTERRUPTIBLE) return ret; }
arch/sparc/kernel/semaphore.c +4 -4
@@ -68,8 +68,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
@@ -118,8 +118,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
arch/sparc64/kernel/semaphore.c +4 -2
@@ -100,7 +100,8 @@add_wait_queue_exclusive (&sem->wait, &wait);while (__sem_update_count (sem,-1 ) <=0 ) { -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ; }remove_wait_queue (&sem->wait, &wait);
@@ -208,7 +209,8 @@ retval = -EINTR ;break ; } -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ; } tsk->state =TASK_RUNNING ;
arch/v850/kernel/semaphore.c +4 -4
@@ -79,8 +79,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_UNINTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
@@ -129,8 +129,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irq (&semaphore_lock); - -schedule (); +sched_profile (); +__schedule (); tsk->state =TASK_INTERRUPTIBLE ;spin_lock_irq (&semaphore_lock); }
arch/x86_64/kernel/semaphore.c +4 -4
@@ -80,8 +80,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_UNINTERRUPTIBLE ;
@@ -133,8 +133,8 @@ } sem->sleepers =1 ;/* us - see -1 above */ spin_unlock_irqrestore (&sem->wait.lock, flags); - -schedule (); +sched_profile (); +__schedule ();spin_lock_irqsave (&sem->wait.lock, flags); tsk->state =TASK_INTERRUPTIBLE ;
lib/rwsem.c +3 -3
@@ -163,7 +163,7 @@for (;;) {if (!waiter->task)break ; -schedule (); +__schedule ();set_task_state (tsk,TASK_UNINTERRUPTIBLE ); }
@@ -178,7 +178,7 @@ struct rw_semaphore fastcall __sched *rwsem_down_read_failed(struct rw_semaphore *sem) {struct rwsem_waiter waiter; - +sched_profile ();rwsemtrace (sem,"Entering rwsem_down_read_failed" ); waiter.flags =RWSEM_WAITING_FOR_READ ;
@@ -194,7 +194,7 @@ struct rw_semaphore fastcall __sched *rwsem_down_write_failed(struct rw_semaphore *sem) {struct rwsem_waiter waiter; - +sched_profile ();rwsemtrace (sem,"Entering rwsem_down_write_failed" ); waiter.flags =RWSEM_WAITING_FOR_WRITE ;
init/main.c +1 -0
@@ -445,6 +445,7 @@if (panic_later)panic (panic_later, panic_param);profile_init (); +schedprof_init ();local_irq_enable ();#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok &&
Quoted 4 lines · William Lee Irwin III
Brute-force port of schedprof to 2.6.7-final. Compiletested on sparc64 only. No runtime testing.
Given that the context switch rate is actually *reduced* in 2.6.7 vs. 2.6.5, I expect that this will not, in fact, reveal anything useful.
While I'm spraying out untested code, I might as well do these, which I've not even compiled. =)
-- wli
kernel/sched.c +42 -20
@@ -4063,7 +4063,7 @@if (schedprof_buf) {unsigned long pc = (unsigned long )__pc; pc -=min (pc, (unsigned long )_stext); -atomic_inc (&schedprof_buf[min (pc, schedprof_len)]); +atomic_inc (&schedprof_buf[min (pc +1 , schedprof_len -1 )]); } }
@@ -4081,8 +4081,9 @@if (!sched_profiling)return ; schedprof_len = (unsigned long )(_etext - _stext) +1 ; - schedprof_buf =alloc_bootmem (schedprof_len*sizeof (atomic_t)); + schedprof_buf =alloc_bootmem (sizeof (atomic_t)*schedprof_len);printk (KERN_INFO "Scheduler call profiling enabled\n" ); + schedprof_buf[0 ] =1 ; }#ifdef CONFIG_PROC_FS
@@ -4092,38 +4093,59 @@ read_sched_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; -ssize_t read; -char * pnt;unsigned int sample_step =1 ; -if (p >= (schedprof_len+1 )*sizeof (atomic_t)) +if (p >=sizeof (atomic_t)*schedprof_len)return 0 ; -if (count > (schedprof_len+1 )*sizeof (atomic_t) - p) - count = (schedprof_len+1 )*sizeof (atomic_t) - p; - read =0 ; - -while (p <sizeof (atomic_t) && count >0 ) { -put_user (*((char *)(&sample_step)+p),buf); - buf++; p++; count--; read++; - } - pnt = (char *)schedprof_buf + p -sizeof (atomic_t); -if (copy_to_user (buf,(void *)pnt,count)) + count =min (schedprof_len*sizeof (atomic_t) - p, count); +if (copy_to_user (buf, (char *)schedprof_buf + p, count))return -EFAULT ; - read += count; - *ppos += read; -return read; + *ppos += count; +return count; }static ssize_t write_sched_profile (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -memset (schedprof_buf,0 ,sizeof (atomic_t)*schedprof_len); +memset (&schedprof_buf[1 ],0 , (schedprof_len-1 )*sizeof (atomic_t));return count; } +static int mmap_sched_profile (struct file *file,struct vm_area_struct *vma) +{ +unsigned long pfn, vaddr, base_pfn =__pa (schedprof_buf)/PAGE_SIZE ; +if (vma->vm_pgoff +vma_pages (vma) > schedprof_pages) +return -ENODEV ; + vma->vm_flags |=VM_RESERVED |VM_IO ; +for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr +=PAGE_SIZE ) { +pgd_t *pgd =pgd_offset (vma->vm_mm, vaddr); +pmd_t *pmd; +pte_t *pte, pte_val; + +spin_lock (&vma->vm_mm->page_table_lock); + pmd =pmd_alloc (vma->vm_mm, pgd, vaddr); +if (!pmd) + goto enomem; + pte =pte_alloc_map (vma->vm_mm, pmd, vaddr); +if (!pte) + goto enomem; + pfn = base_pfn +linear_page_index (vma, vaddr); + pte_val =pfn_pte (pfn, vma->vm_page_prot); +set_pte (pte, pte_val); +update_mmu_cache (vma, vaddr, pte_val); +pte_unmap (pte); +spin_unlock (&vma->vm_mm->page_table_lock); + } +return 0 ; +enomem: +spin_unlock (&vma->vm_mm->page_table_lock); +return -ENOMEM ; +} +static struct file_operations sched_profile_operations = { .read = read_sched_profile, .write = write_sched_profile, + .mmap = mmap_sched_profile, };static int proc_schedprof_init (void )
@@ -4134,7 +4156,7 @@ entry =create_proc_entry ("schedprof" ,S_IWUSR |S_IRUGO ,NULL );if (entry) { entry->proc_fops = &sched_profile_operations; - entry->size =sizeof (atomic_t)*(schedprof_len +1 ); + entry->size =sizeof (atomic_t)*schedprof_len; }return !!entry; }
kernel/sched.c +2 -2
@@ -4152,13 +4152,13 @@ {struct proc_dir_entry *entry;if (!sched_profiling) -return 1 ; +return 0 ; entry =create_proc_entry ("schedprof" ,S_IWUSR |S_IRUGO ,NULL );if (entry) { entry->proc_fops = &sched_profile_operations; entry->size =sizeof (atomic_t)*schedprof_len; } -return !!entry; +return !entry; }module_init (proc_schedprof_init);#endif
kernel/sched.c +15 -4
@@ -4052,7 +4052,7 @@#endif /* defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) */ static atomic_t *schedprof_buf; -static int sched_profiling; +static int sched_profiling, schedprof_shift;static unsigned long schedprof_len;#include <linux/bootmem.h>
@@ -4062,11 +4062,22 @@ {if (schedprof_buf) {unsigned long pc = (unsigned long )__pc; - pc -=min (pc, (unsigned long )_stext); + pc = (pc -min (pc, (unsigned long )_stext)) >> schedprof_shift;atomic_inc (&schedprof_buf[min (pc +1 , schedprof_len -1 )]); } } +static int __init schedprof_shift_setup (char *s) +{ +int n; +if (get_option (&s, &n)) { + scheprof_shift = n; + sched_profiling =1 ; + } +return 1 ; +} +__setup ("schedprof_shift=" , schedprof_shift_setup); +static int __init schedprof_setup (char *s) {int n;
@@ -4080,10 +4091,10 @@ {if (!sched_profiling)return ; - schedprof_len = (unsigned long )(_etext - _stext) +1 ; + schedprof_len = ((unsigned long )(_etext - _stext) >> schedprof_shift) +1 ; schedprof_buf =alloc_bootmem (sizeof (atomic_t)*schedprof_len);printk (KERN_INFO "Scheduler call profiling enabled\n" ); - schedprof_buf[0 ] =1 ; + schedprof_buf[0 ] =1 << schedprof_shift; }#ifdef CONFIG_PROC_FS
Quoted 2 lines · William Lee Irwin III
While I'm spraying out untested code, I might as well do these, which I've not even compiled. =)
Okay, these compile -- ship it! =)
-- wli
kernel/sched.c +44 -22
@@ -4053,7 +4053,7 @@static atomic_t *schedprof_buf;static int sched_profiling; -static unsigned long schedprof_len; +static unsigned long schedprof_len, schedprof_pages;#include <linux/bootmem.h> #include <asm/sections.h>
@@ -4063,7 +4063,7 @@if (schedprof_buf) {unsigned long pc = (unsigned long )__pc; pc -=min (pc, (unsigned long )_stext); -atomic_inc (&schedprof_buf[min (pc, schedprof_len)]); +atomic_inc (&schedprof_buf[min (pc +1 , schedprof_len -1 )]); } }
@@ -4081,8 +4081,10 @@if (!sched_profiling)return ; schedprof_len = (unsigned long )(_etext - _stext) +1 ; - schedprof_buf =alloc_bootmem (schedprof_len*sizeof (atomic_t)); + schedprof_buf =alloc_bootmem_pages (sizeof (atomic_t)*schedprof_len); + schedprof_pages =PAGE_ALIGN (sizeof (atomic_t)*schedprof_len)/PAGE_SIZE ;printk (KERN_INFO "Scheduler call profiling enabled\n" ); +atomic_set (&schedprof_buf[0 ],1 ); }#ifdef CONFIG_PROC_FS
@@ -4092,38 +4094,58 @@ read_sched_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; -ssize_t read; -char * pnt; -unsigned int sample_step =1 ; -if (p >= (schedprof_len+1 )*sizeof (atomic_t)) +if (p >=sizeof (atomic_t)*schedprof_len)return 0 ; -if (count > (schedprof_len+1 )*sizeof (atomic_t) - p) - count = (schedprof_len+1 )*sizeof (atomic_t) - p; - read =0 ; - -while (p <sizeof (atomic_t) && count >0 ) { -put_user (*((char *)(&sample_step)+p),buf); - buf++; p++; count--; read++; - } - pnt = (char *)schedprof_buf + p -sizeof (atomic_t); -if (copy_to_user (buf,(void *)pnt,count)) + count =min (schedprof_len*sizeof (atomic_t) - p, count); +if (copy_to_user (buf, (char *)schedprof_buf + p, count))return -EFAULT ; - read += count; - *ppos += read; -return read; + *ppos += count; +return count; }static ssize_t write_sched_profile (struct file *file,const char __user *buf,size_t count,loff_t *ppos) { -memset (schedprof_buf,0 ,sizeof (atomic_t)*schedprof_len); +memset (&schedprof_buf[1 ],0 , (schedprof_len-1 )*sizeof (atomic_t));return count; } +static int mmap_sched_profile (struct file *file,struct vm_area_struct *vma) +{ +unsigned long pfn, vaddr, base_pfn =__pa (schedprof_buf)/PAGE_SIZE ; +if (vma->vm_pgoff +vma_pages (vma) > schedprof_pages) +return -ENODEV ; + vma->vm_flags |=VM_RESERVED |VM_IO ; +for (vaddr = vma->vm_start; vaddr < vma->vm_end; vaddr +=PAGE_SIZE ) { +pgd_t *pgd =pgd_offset (vma->vm_mm, vaddr); +pmd_t *pmd; +pte_t *pte, pte_val; + +spin_lock (&vma->vm_mm->page_table_lock); + pmd =pmd_alloc (vma->vm_mm, pgd, vaddr); +if (!pmd) + goto enomem; + pte =pte_alloc_map (vma->vm_mm, pmd, vaddr); +if (!pte) + goto enomem; + pfn = base_pfn +linear_page_index (vma, vaddr); + pte_val =pfn_pte (pfn, vma->vm_page_prot); +set_pte (pte, pte_val); +update_mmu_cache (vma, vaddr, pte_val); +pte_unmap (pte); +spin_unlock (&vma->vm_mm->page_table_lock); + } +return 0 ; +enomem: +spin_unlock (&vma->vm_mm->page_table_lock); +return -ENOMEM ; +} +static struct file_operations sched_profile_operations = { .read = read_sched_profile, .write = write_sched_profile, + .mmap = mmap_sched_profile, };static int proc_schedprof_init (void )
@@ -4134,7 +4156,7 @@ entry =create_proc_entry ("schedprof" ,S_IWUSR |S_IRUGO ,NULL );if (entry) { entry->proc_fops = &sched_profile_operations; - entry->size =sizeof (atomic_t)*(schedprof_len +1 ); + entry->size =sizeof (atomic_t)*schedprof_len; }return !!entry; }
kernel/sched.c +2 -2
@@ -4152,13 +4152,13 @@ {struct proc_dir_entry *entry;if (!sched_profiling) -return 1 ; +return 0 ; entry =create_proc_entry ("schedprof" ,S_IWUSR |S_IRUGO ,NULL );if (entry) { entry->proc_fops = &sched_profile_operations; entry->size =sizeof (atomic_t)*schedprof_len; } -return !!entry; +return !entry; }module_init (proc_schedprof_init);#endif
kernel/sched.c +15 -4
@@ -4052,7 +4052,7 @@#endif /* defined(CONFIG_SMP) && defined(CONFIG_PREEMPT) */ static atomic_t *schedprof_buf; -static int sched_profiling; +static int sched_profiling, schedprof_shift;static unsigned long schedprof_len, schedprof_pages;#include <linux/bootmem.h>
@@ -4062,11 +4062,22 @@ {if (schedprof_buf) {unsigned long pc = (unsigned long )__pc; - pc -=min (pc, (unsigned long )_stext); + pc = (pc -min (pc, (unsigned long )_stext)) >> schedprof_shift;atomic_inc (&schedprof_buf[min (pc +1 , schedprof_len -1 )]); } } +static int __init schedprof_shift_setup (char *s) +{ +int n; +if (get_option (&s, &n)) { + schedprof_shift = n; + sched_profiling =1 ; + } +return 1 ; +} +__setup ("schedprof_shift=" , schedprof_shift_setup); +static int __init schedprof_setup (char *s) {int n;
@@ -4080,11 +4091,11 @@ {if (!sched_profiling)return ; - schedprof_len = (unsigned long )(_etext - _stext) +1 ; + schedprof_len = ((unsigned long )(_etext-_stext)>>schedprof_shift) +1 ; schedprof_buf =alloc_bootmem_pages (sizeof (atomic_t)*schedprof_len); schedprof_pages =PAGE_ALIGN (sizeof (atomic_t)*schedprof_len)/PAGE_SIZE ;printk (KERN_INFO "Scheduler call profiling enabled\n" ); -atomic_set (&schedprof_buf[0 ],1 ); +atomic_set (&schedprof_buf[0 ],1 << schedprof_shift); }#ifdef CONFIG_PROC_FS