]> Zhao Yanbai Git Server - minix.git/commitdiff
Busy idle loop when profiling
authorTomas Hruby <tom@minix3.org>
Thu, 23 Sep 2010 10:49:52 +0000 (10:49 +0000)
committerTomas Hruby <tom@minix3.org>
Thu, 23 Sep 2010 10:49:52 +0000 (10:49 +0000)
- the Intel architecture cycle counter (performance counter) does not
  count when the CPU is idle therefore we use busy loop instead of
  halting the cpu when there is nothing to schedule

- the downside is that handling interrupts may be accounted as idle
  time if a sample is taken before we get out of the nested trap and
  pick a new process

kernel/arch/i386/arch_clock.c
kernel/arch/i386/klib.S
kernel/cpulocals.h
kernel/proc.c
kernel/proto.h

index 59d06652a7d233a3e9a612d6fa1bafd56ab31dac..b9439cec634232d82110102793251a9a5d6cfaa5 100644 (file)
@@ -11,6 +11,7 @@
 #include "kernel/interrupt.h"
 #include <minix/u64.h>
 #include "glo.h"
+#include "profile.h"
 
 
 #ifdef CONFIG_APIC
@@ -272,6 +273,9 @@ PUBLIC void context_stop_idle(void)
 
        if (is_idle)
                restart_local_timer();
+
+       if (sprofiling)
+               get_cpulocal_var(idle_interrupted) = 1;
 }
 
 PUBLIC u64_t ms_2_cpu_time(unsigned ms)
index 515ea5ea1b3e8fbd07861f0c57c6ac0d5e8176c9..6915501e15aad3395ff3f0ce8f68b09d77eab26a 100644 (file)
@@ -1030,6 +1030,14 @@ ENTRY(read_ebp)
        mov     %ebp, %eax
        ret
 
+ENTRY(interrupts_enable)
+       sti
+       ret
+
+ENTRY(interrupts_disable)
+       cli
+       ret
+
 
 /*
  * void switch_k_stack(void * esp, void (* continuation)(void));
index 0d3c0ade461be17b8590bd7b89ea42f226791868..b12978a65bf4dea2ca6c1a80938737b99cc9dd35 100644 (file)
@@ -76,6 +76,9 @@ DECLARE_CPULOCAL(struct proc *, run_q_head[NR_SCHED_QUEUES]); /* ptrs to ready l
 DECLARE_CPULOCAL(struct proc *, run_q_tail[NR_SCHED_QUEUES]); /* ptrs to ready list tails */
 DECLARE_CPULOCAL(int, cpu_is_idle); /* let the others know that you are idle */
 
+DECLARE_CPULOCAL(volatile int, idle_interrupted); /* to interrupt busy-idle
+                                                    while profiling */
+
 DECLARE_CPULOCAL(u64_t ,tsc_ctr_switch); /* when did we switched time accounting */
 
 /* last values read from cpu when sending ooq msg to scheduler */
index 3f541b47999b48f9e725f7a981788bbe246a0048..3e416ae4dd78059b8ba4ad0a270ef229c10df19a 100644 (file)
@@ -43,6 +43,7 @@
 #include "vm.h"
 #include "clock.h"
 #include "spinlock.h"
+#include "profile.h"
 
 #include "arch_proto.h"
 
@@ -214,7 +215,18 @@ PRIVATE void idle(void)
 
        /* start accounting for the idle time */
        context_stop(proc_addr(KERNEL));
-       halt_cpu();
+       if (!sprofiling)
+               halt_cpu();
+       else {
+               volatile int * v;
+
+               v = get_cpulocal_var_ptr(idle_interrupted);
+               interrupts_enable();
+               while (!*v)
+                       arch_pause();
+               interrupts_disable();
+               *v = 0;
+       }
        /*
         * end of accounting for the idle task does not happen here, the kernel
         * is handling stuff for quite a while before it gets back here!
index ba99268a1d66a982734b6ded0c7d8a5fe7cb0669..b040c8a52f9b7ba2034f140c4c060e4b12e267d6 100644 (file)
@@ -103,6 +103,9 @@ _PROTOTYPE( void rm_irq_handler, (const irq_hook_t *hook)           );
 _PROTOTYPE( void enable_irq, (const irq_hook_t *hook)                  );
 _PROTOTYPE( int disable_irq, (const irq_hook_t *hook)                  );
 
+_PROTOTYPE(void interrupts_enable, (void));
+_PROTOTYPE(void interrupts_disable, (void));
+
 /* debug.c */
 _PROTOTYPE( int runqueues_ok, (void) );
 #ifndef CONFIG_SMP