From 865e21b884e8d2f2c93f7a0b93cae62c36ba7f0d Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Wed, 15 Sep 2010 14:10:21 +0000 Subject: [PATCH] SMP - CPU local idle stub - each CPU has its own pseudo idle process and its structure - idle cycles accounting is agregated when exporting to userspace --- kernel/arch/i386/arch_smp.c | 1 - kernel/cpulocals.h | 1 + kernel/proc.c | 53 ++++++++++++++++++++++++++++++++++--- kernel/system/do_getinfo.c | 14 ++++++++++ 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/kernel/arch/i386/arch_smp.c b/kernel/arch/i386/arch_smp.c index f381b7b9a..7c72ca124 100644 --- a/kernel/arch/i386/arch_smp.c +++ b/kernel/arch/i386/arch_smp.c @@ -223,7 +223,6 @@ PRIVATE void ap_finish_booting(void) ap_boot_finished(cpu); spinlock_unlock(&boot_lock); - for(;;); /* finish processor initialisation. */ lapic_enable(cpu); diff --git a/kernel/cpulocals.h b/kernel/cpulocals.h index 9c9be2db0..f9faefa9a 100644 --- a/kernel/cpulocals.h +++ b/kernel/cpulocals.h @@ -55,6 +55,7 @@ DECLARE_CPULOCAL_START /* Process scheduling information and the kernel reentry count. */ DECLARE_CPULOCAL(struct proc *,proc_ptr);/* pointer to currently running process */ DECLARE_CPULOCAL(struct proc *,bill_ptr);/* process to bill for clock ticks */ +DECLARE_CPULOCAL(struct proc ,idle_proc);/* stub for an idle process */ /* * signal whether pagefault is already being handled to detect recursive diff --git a/kernel/proc.c b/kernel/proc.c index 90d5d87ba..3ded1a331 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -65,6 +65,42 @@ FORWARD _PROTOTYPE( int try_one, (struct proc *src_ptr, struct proc *dst_ptr, FORWARD _PROTOTYPE( struct proc * pick_proc, (void)); FORWARD _PROTOTYPE( void enqueue_head, (struct proc *rp)); +/* all idles share the same idle_priv structure */ +PRIVATE struct priv idle_priv; + +PRIVATE void set_idle_name(char * name, int n) +{ + int i, c; + int p_z = 0; + /* + * P_NAME_LEN limits us to 3 characters for the idle task numer. 999 + * should be enough though. + */ + if (n > 999) + n = 999; + + name[0] = 'i'; + name[1] = 'd'; + name[2] = 'l'; + name[3] = 'e'; + + for (i = 4, c = 100; c > 0; c /= 10) { + int digit; + + digit = n / c; + n -= digit * c; + + if (p_z || digit != 0 || c == 1) { + p_z = 1; + name[i++] = '0' + digit; + } + } + + name[i] = '\0'; + +} + + #define PICK_ANY 1 #define PICK_HIGHERONLY 2 @@ -108,6 +144,14 @@ PUBLIC void proc_init(void) sp->s_sig_mgr = NONE; /* clear signal managers */ sp->s_bak_sig_mgr = NONE; } + + idle_priv.s_flags = IDL_F; + /* initialize IDLE structures for every CPU */ + for (i = 0; i < CONFIG_MAX_CPUS; i++) { + struct proc * ip = get_cpu_var_ptr(i, idle_proc); + ip->p_priv = &idle_priv; + set_idle_name(ip->p_name, i); + } } PRIVATE void switch_address_space_idle(void) @@ -127,12 +171,18 @@ PRIVATE void switch_address_space_idle(void) *===========================================================================*/ PRIVATE void idle(void) { + struct proc * p; + /* This function is called whenever there is no work to do. * Halt the CPU, and measure how many timestamp counter ticks are * spent not doing anything. This allows test setups to measure * the CPU utiliziation of certain workloads with high precision. */ + p = get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc); + if (priv(p)->s_flags & BILLABLE) + get_cpulocal_var(bill_ptr) = p; + switch_address_space_idle(); /* start accounting for the idle time */ @@ -184,9 +234,6 @@ not_runnable_pick_new: * process. If there is still nothing runnable we "schedule" IDLE again */ while (!(p = pick_proc())) { - p = get_cpulocal_var(proc_ptr) = proc_addr(IDLE); - if (priv(p)->s_flags & BILLABLE) - get_cpulocal_var(bill_ptr) = p; idle(); } diff --git a/kernel/system/do_getinfo.c b/kernel/system/do_getinfo.c index 342ebf83e..5bcfc9b31 100644 --- a/kernel/system/do_getinfo.c +++ b/kernel/system/do_getinfo.c @@ -17,6 +17,19 @@ #if USE_GETINFO +#include + +PRIVATE void update_idle_time(void) +{ + int i; + struct proc * idl = proc_addr(IDLE); + + for (i = 0; i < CONFIG_MAX_CPUS ; i++) { + idl->p_cycles = add64(idl->p_cycles, + get_cpu_var(i, idle_proc).p_cycles); + } +} + /*===========================================================================* * do_getinfo * *===========================================================================*/ @@ -64,6 +77,7 @@ PUBLIC int do_getinfo(struct proc * caller, message * m_ptr) break; } case GET_PROCTAB: { + update_idle_time(); length = sizeof(struct proc) * (NR_PROCS + NR_TASKS); src_vir = (vir_bytes) proc; break; -- 2.44.0