Changed the way how CPU activity is monitored: instead of taking the active
time of the idle thread as a measure, we now compute the CPU activity on each thread switch - the time the CPU worked is the total of user and kernel time a thread spent during its quantum. Unlike before, this mechanism works correctly on SMP machines. I hope this works as expected :) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16193 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -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()]; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+26
-2
@@ -8,9 +8,9 @@
|
||||
|
||||
/* This file contains the cpu functions (init, etc). */
|
||||
|
||||
#include <kernel.h>
|
||||
|
||||
#include <cpu.h>
|
||||
#include <vm.h>
|
||||
#include <thread_types.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <boot/kernel_args.h>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <system_info.h>
|
||||
#include <arch/system_info.h>
|
||||
|
||||
#include <vm.h>
|
||||
#include <cpu.h>
|
||||
#include <debug.h>
|
||||
#include <port.h>
|
||||
#include <real_time_clock.h>
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <smp.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <vm.h>
|
||||
#include <vm_page.h>
|
||||
|
||||
#include <string.h>
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user