From ef92583c3a0f14c164f8017a8cff6c0e27a40dcf Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Thu, 23 Sep 2010 10:49:52 +0000 Subject: [PATCH] Busy idle loop when profiling - 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 | 4 ++++ kernel/arch/i386/klib.S | 8 ++++++++ kernel/cpulocals.h | 3 +++ kernel/proc.c | 14 +++++++++++++- kernel/proto.h | 3 +++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/kernel/arch/i386/arch_clock.c b/kernel/arch/i386/arch_clock.c index 59d06652a..b9439cec6 100644 --- a/kernel/arch/i386/arch_clock.c +++ b/kernel/arch/i386/arch_clock.c @@ -11,6 +11,7 @@ #include "kernel/interrupt.h" #include #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) diff --git a/kernel/arch/i386/klib.S b/kernel/arch/i386/klib.S index 515ea5ea1..6915501e1 100644 --- a/kernel/arch/i386/klib.S +++ b/kernel/arch/i386/klib.S @@ -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)); diff --git a/kernel/cpulocals.h b/kernel/cpulocals.h index 0d3c0ade4..b12978a65 100644 --- a/kernel/cpulocals.h +++ b/kernel/cpulocals.h @@ -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 */ diff --git a/kernel/proc.c b/kernel/proc.c index 3f541b479..3e416ae4d 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -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! diff --git a/kernel/proto.h b/kernel/proto.h index ba99268a1..b040c8a52 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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 -- 2.44.0