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
|
// thread.c: used to force a reschedule at quantum expiration time
|
||||||
int preempted;
|
int preempted;
|
||||||
timer quantum_timer;
|
timer quantum_timer;
|
||||||
|
|
||||||
|
// keeping track of CPU activity
|
||||||
|
bigtime_t active_time;
|
||||||
|
bigtime_t last_kernel_time;
|
||||||
|
bigtime_t last_user_time;
|
||||||
|
|
||||||
bool disabled;
|
bool disabled;
|
||||||
} info;
|
} info;
|
||||||
} cpu_ent __attribute__((aligned(64)));
|
} 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(struct kernel_args *args);
|
||||||
status_t cpu_init_post_vm(struct kernel_args *args);
|
status_t cpu_init_post_vm(struct kernel_args *args);
|
||||||
status_t cpu_init_post_modules(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);
|
cpu_ent *get_cpu_struct(void);
|
||||||
extern inline cpu_ent *get_cpu_struct(void) { return &gCPU[smp_get_current_cpu()]; }
|
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_yield(void);
|
||||||
void thread_exit(void);
|
void thread_exit(void);
|
||||||
|
|
||||||
bigtime_t thread_get_active_cpu_time(int32 cpuNum);
|
|
||||||
int32 thread_max_threads(void);
|
int32 thread_max_threads(void);
|
||||||
int32 thread_used_threads(void);
|
int32 thread_used_threads(void);
|
||||||
|
|
||||||
@@ -47,8 +46,14 @@ static thread_id thread_get_current_thread_id(void);
|
|||||||
static inline thread_id
|
static inline thread_id
|
||||||
thread_get_current_thread_id(void)
|
thread_get_current_thread_id(void)
|
||||||
{
|
{
|
||||||
struct thread *t = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
return t ? t->id : 0;
|
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);
|
thread_id allocate_thread_id(void);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ KernelMergeObject kernel_core.o :
|
|||||||
module.c
|
module.c
|
||||||
port.c
|
port.c
|
||||||
real_time_clock.c
|
real_time_clock.c
|
||||||
scheduler.c
|
scheduler.cpp
|
||||||
sem.c
|
sem.c
|
||||||
shutdown.c
|
shutdown.c
|
||||||
signal.c
|
signal.c
|
||||||
|
|||||||
+26
-2
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
/* This file contains the cpu functions (init, etc). */
|
/* This file contains the cpu functions (init, etc). */
|
||||||
|
|
||||||
#include <kernel.h>
|
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <vm.h>
|
#include <thread_types.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <boot/kernel_args.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
|
void
|
||||||
clear_caches(void *address, size_t length, uint32 flags)
|
clear_caches(void *address, size_t length, uint32 flags)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -127,11 +127,6 @@ scheduler_remove_from_run_queue(struct thread *thread)
|
|||||||
static void
|
static void
|
||||||
context_switch(struct thread *fromThread, struct thread *toThread)
|
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;
|
toThread->cpu = fromThread->cpu;
|
||||||
fromThread->cpu = NULL;
|
fromThread->cpu = NULL;
|
||||||
|
|
||||||
@@ -223,6 +218,23 @@ scheduler_reschedule(void)
|
|||||||
nextThread->state = B_THREAD_RUNNING;
|
nextThread->state = B_THREAD_RUNNING;
|
||||||
nextThread->next_state = B_THREAD_READY;
|
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) {
|
if (nextThread != oldThread || oldThread->cpu->info.preempted) {
|
||||||
bigtime_t quantum = 3000; // ToDo: calculate quantum!
|
bigtime_t quantum = 3000; // ToDo: calculate quantum!
|
||||||
timer *quantumTimer = &oldThread->cpu->info.quantum_timer;
|
timer *quantumTimer = &oldThread->cpu->info.quantum_timer;
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <system_info.h>
|
#include <system_info.h>
|
||||||
#include <arch/system_info.h>
|
#include <arch/system_info.h>
|
||||||
|
|
||||||
#include <vm.h>
|
#include <cpu.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <port.h>
|
#include <port.h>
|
||||||
#include <real_time_clock.h>
|
#include <real_time_clock.h>
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <team.h>
|
#include <team.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
|
#include <vm.h>
|
||||||
#include <vm_page.h>
|
#include <vm_page.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -41,7 +42,7 @@ _get_system_info(system_info *info, size_t size)
|
|||||||
info->cpu_count = smp_get_num_cpus();
|
info->cpu_count = smp_get_num_cpus();
|
||||||
|
|
||||||
for (i = 0; i < info->cpu_count; i++)
|
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
|
// ToDo: Add page_faults
|
||||||
info->max_pages = vm_page_num_pages();
|
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
|
int32
|
||||||
thread_max_threads(void)
|
thread_max_threads(void)
|
||||||
{
|
{
|
||||||
@@ -1371,6 +1343,7 @@ thread_init(kernel_args *args)
|
|||||||
thread->next_state = B_THREAD_READY;
|
thread->next_state = B_THREAD_READY;
|
||||||
sprintf(name, "idle thread %lu kstack", i + 1);
|
sprintf(name, "idle thread %lu kstack", i + 1);
|
||||||
thread->kernel_stack_area = find_area(name);
|
thread->kernel_stack_area = find_area(name);
|
||||||
|
thread->entry = NULL;
|
||||||
|
|
||||||
if (get_area_info(thread->kernel_stack_area, &info) != B_OK)
|
if (get_area_info(thread->kernel_stack_area, &info) != B_OK)
|
||||||
panic("error finding idle kstack area\n");
|
panic("error finding idle kstack area\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user