mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
65 lines
2.4 KiB
C
65 lines
2.4 KiB
C
#include <kernel/scheduler.h>
|
|
#include <kernel/timekeeper.h>
|
|
#include <util.h>
|
|
|
|
#define SCALING_FACTOR (SCHED_MAX_INTERACTIVITY / 2)
|
|
|
|
#define HISTORY_LIMIT_USEC 5000000
|
|
|
|
static void update_interactivity(thread_t *thread) {
|
|
time_t sleep_time = thread->metrics.sleep_time_avg_us;
|
|
time_t run_time = thread->metrics.run_time_avg_us;
|
|
|
|
if (sleep_time > run_time)
|
|
thread->metrics.interactivity_score = (SCALING_FACTOR * run_time) / sleep_time;
|
|
else
|
|
thread->metrics.interactivity_score = (SCALING_FACTOR * sleep_time) / run_time + SCALING_FACTOR;
|
|
|
|
thread->metrics.interactivity_score += thread->nice + (thread->proc ? thread->proc->nice : 0);
|
|
thread->metrics.interactivity_score = max(min(thread->metrics.interactivity_score, SCHED_MAX_INTERACTIVITY - 1), 0);
|
|
}
|
|
|
|
static void offset_times(thread_t *thread, time_t run_us, time_t sleep_us) {
|
|
thread->metrics.run_time_avg_us += run_us;
|
|
thread->metrics.sleep_time_avg_us += sleep_us;
|
|
|
|
time_t total = thread->metrics.run_time_avg_us + thread->metrics.sleep_time_avg_us;
|
|
if (total > HISTORY_LIMIT_USEC) {
|
|
if (total > HISTORY_LIMIT_USEC * 2) {
|
|
// the thread has spent a lot of time sleeping, as this will not be reached normally otherwise
|
|
// set its sleep time to max and zero the run time before applying normal decay
|
|
thread->metrics.run_time_avg_us = 0;
|
|
thread->metrics.sleep_time_avg_us = HISTORY_LIMIT_USEC;
|
|
}
|
|
thread->metrics.run_time_avg_us = thread->metrics.run_time_avg_us * 4 / 5;
|
|
thread->metrics.sleep_time_avg_us = thread->metrics.sleep_time_avg_us * 4 / 5;
|
|
}
|
|
|
|
update_interactivity(thread);
|
|
}
|
|
|
|
void sched_thread_running_callback(thread_t *thread) {
|
|
thread->metrics.run_start = timekeeper_time();
|
|
}
|
|
|
|
void sched_thread_stopping_callback(thread_t *thread, bool sleeping) {
|
|
timespec_t now = timekeeper_time();
|
|
size_t us_diff = timespec_diffus(thread->metrics.run_start, now);
|
|
offset_times(thread, us_diff, 0);
|
|
|
|
if (thread->proc) {
|
|
spinlock_acquire(&thread->proc->runtime_lock);
|
|
thread->proc->total_runtime = timespec_add(thread->proc->total_runtime, timespec_from_us(us_diff));
|
|
spinlock_release(&thread->proc->runtime_lock);
|
|
}
|
|
|
|
if (sleeping)
|
|
thread->metrics.sleep_start = now;
|
|
}
|
|
|
|
// called right before the specified thread gets enqueued after sleeping
|
|
void sched_thread_wakeup_callback(thread_t *thread) {
|
|
thread->metrics.last_sleep_duration_us = timespec_diffus(thread->metrics.sleep_start, timekeeper_time());
|
|
offset_times(thread, 0, thread->metrics.last_sleep_duration_us);
|
|
}
|