diff --git a/headers/private/kernel/cpu.h b/headers/private/kernel/cpu.h index 4960204a58..19cd41e5a2 100644 --- a/headers/private/kernel/cpu.h +++ b/headers/private/kernel/cpu.h @@ -23,6 +23,12 @@ typedef union cpu_ent { // thread.c: used to force a reschedule at quantum expiration time int preempted; timer quantum_timer; + + // keeping track of CPU activity + bigtime_t active_time; + bigtime_t last_kernel_time; + bigtime_t last_user_time; + bool disabled; } info; } cpu_ent __attribute__((aligned(64))); @@ -39,6 +45,7 @@ status_t cpu_preboot_init(struct kernel_args *args); status_t cpu_init(struct kernel_args *args); status_t cpu_init_post_vm(struct kernel_args *args); status_t cpu_init_post_modules(struct kernel_args *args); +bigtime_t cpu_get_active_time(int32 cpu); cpu_ent *get_cpu_struct(void); extern inline cpu_ent *get_cpu_struct(void) { return &gCPU[smp_get_current_cpu()]; } diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index bc5c037110..a22004d28a 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -34,7 +34,6 @@ status_t thread_per_cpu_init(int32 cpuNum); void thread_yield(void); void thread_exit(void); -bigtime_t thread_get_active_cpu_time(int32 cpuNum); int32 thread_max_threads(void); int32 thread_used_threads(void); @@ -47,8 +46,14 @@ static thread_id thread_get_current_thread_id(void); static inline thread_id thread_get_current_thread_id(void) { - struct thread *t = thread_get_current_thread(); - return t ? t->id : 0; + struct thread *thread = thread_get_current_thread(); + return thread ? thread->id : 0; +} + +static inline bool +thread_is_idle_thread(struct thread *thread) +{ + return thread->entry == NULL; } thread_id allocate_thread_id(void); diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index f7f05bc631..a5e5808a47 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -25,7 +25,7 @@ KernelMergeObject kernel_core.o : module.c port.c real_time_clock.c - scheduler.c + scheduler.cpp sem.c shutdown.c signal.c diff --git a/src/system/kernel/cpu.c b/src/system/kernel/cpu.c index 87c8f71585..1ec053eeba 100644 --- a/src/system/kernel/cpu.c +++ b/src/system/kernel/cpu.c @@ -8,9 +8,9 @@ /* This file contains the cpu functions (init, etc). */ -#include + #include -#include +#include #include #include @@ -58,6 +58,30 @@ cpu_preboot_init(kernel_args *args) } +bigtime_t +cpu_get_active_time(int32 cpu) +{ + bigtime_t activeTime; + cpu_status state; + + if (cpu < 0 || cpu > smp_get_num_cpus()) + return 0; + + // We need to grab the thread lock here, because the thread activity + // time is not maintained atomically (because there is no need to) + + state = disable_interrupts(); + GRAB_THREAD_LOCK(); + + activeTime = gCPU[cpu].info.active_time; + + RELEASE_THREAD_LOCK(); + restore_interrupts(state); + + return activeTime; +} + + void clear_caches(void *address, size_t length, uint32 flags) { diff --git a/src/system/kernel/scheduler.c b/src/system/kernel/scheduler.cpp similarity index 92% rename from src/system/kernel/scheduler.c rename to src/system/kernel/scheduler.cpp index 1ca3227060..5e3b21bc40 100644 --- a/src/system/kernel/scheduler.c +++ b/src/system/kernel/scheduler.cpp @@ -127,11 +127,6 @@ scheduler_remove_from_run_queue(struct thread *thread) static void context_switch(struct thread *fromThread, struct thread *toThread) { - // track kernel time (user time is tracked in thread_at_kernel_entry()) - bigtime_t now = system_time(); - fromThread->kernel_time += now - fromThread->last_time; - toThread->last_time = now; - toThread->cpu = fromThread->cpu; fromThread->cpu = NULL; @@ -223,6 +218,23 @@ scheduler_reschedule(void) nextThread->state = B_THREAD_RUNNING; nextThread->next_state = B_THREAD_READY; + // track kernel time (user time is tracked in thread_at_kernel_entry()) + bigtime_t now = system_time(); + oldThread->kernel_time += now - oldThread->last_time; + nextThread->last_time = now; + + // track CPU activity + if (!thread_is_idle_thread(oldThread)) { + oldThread->cpu->info.active_time += + (oldThread->kernel_time - oldThread->cpu->info.last_kernel_time) + + (oldThread->user_time - oldThread->cpu->info.last_user_time); + } + + if (!thread_is_idle_thread(nextThread)) { + oldThread->cpu->info.last_kernel_time = nextThread->kernel_time; + oldThread->cpu->info.last_user_time = nextThread->user_time; + } + if (nextThread != oldThread || oldThread->cpu->info.preempted) { bigtime_t quantum = 3000; // ToDo: calculate quantum! timer *quantumTimer = &oldThread->cpu->info.quantum_timer; diff --git a/src/system/kernel/system_info.c b/src/system/kernel/system_info.c index ecab23bb70..771e1ce31a 100644 --- a/src/system/kernel/system_info.c +++ b/src/system/kernel/system_info.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,7 @@ _get_system_info(system_info *info, size_t size) info->cpu_count = smp_get_num_cpus(); for (i = 0; i < info->cpu_count; i++) - info->cpu_infos[i].active_time = thread_get_active_cpu_time(i); + info->cpu_infos[i].active_time = cpu_get_active_time(i); // ToDo: Add page_faults info->max_pages = vm_page_num_pages(); diff --git a/src/system/kernel/thread.c b/src/system/kernel/thread.c index ea82bd76fd..2af224dd9f 100644 --- a/src/system/kernel/thread.c +++ b/src/system/kernel/thread.c @@ -1281,34 +1281,6 @@ spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority, } -bigtime_t -thread_get_active_cpu_time(int32 cpuNum) -{ - bigtime_t activeTime; - cpu_status state; - - if (cpuNum < 0 || cpuNum > B_MAX_CPU_COUNT || sIdleThreads[cpuNum] == NULL) - return 0; - - activeTime = system_time(); - - // we need to grab the thread lock here, because the thread activity - // time is not maintained atomically (because there is no need to) - - state = disable_interrupts(); - GRAB_THREAD_LOCK(); - - // TODO: this is wrong - the idle threads are arbitrarly executed by the CPUs - // there is no CPU affinity! - activeTime -= sIdleThreads[cpuNum]->kernel_time; - - RELEASE_THREAD_LOCK(); - restore_interrupts(state); - - return activeTime; -} - - int32 thread_max_threads(void) { @@ -1371,6 +1343,7 @@ thread_init(kernel_args *args) thread->next_state = B_THREAD_READY; sprintf(name, "idle thread %lu kstack", i + 1); thread->kernel_stack_area = find_area(name); + thread->entry = NULL; if (get_area_info(thread->kernel_stack_area, &info) != B_OK) panic("error finding idle kstack area\n");