Implement BSD calculations

- load_avg, recent_cpu, priority calculations
- reduce frac bits to 14
- ignore thread_set_priority when BSD enabled
This commit is contained in:
2024-10-16 22:50:46 +01:00
parent a7a6d0b9d4
commit c5e41db9b0
3 changed files with 71 additions and 42 deletions

View File

@@ -8,7 +8,7 @@ typedef struct
} fp32_t; } fp32_t;
/* Fixed Point Arithmetic bit count constants */ /* Fixed Point Arithmetic bit count constants */
#define NUM_FRAC_BITS 20 #define NUM_FRAC_BITS 14
#define NUM_INT_BITS (31 - NUM_FRAC_BITS) #define NUM_INT_BITS (31 - NUM_FRAC_BITS)
#define CONVERSION_CONST (1 << NUM_FRAC_BITS) /* f = 2^q, (2^20) */ #define CONVERSION_CONST (1 << NUM_FRAC_BITS) /* f = 2^q, (2^20) */

View File

@@ -4,6 +4,7 @@
#include <random.h> #include <random.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "devices/timer.h"
#include "threads/fixed-point.h" #include "threads/fixed-point.h"
#include "threads/flags.h" #include "threads/flags.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
@@ -50,6 +51,7 @@ struct kernel_thread_frame
static long long idle_ticks; /* # of timer ticks spent idle. */ static long long idle_ticks; /* # of timer ticks spent idle. */
static long long kernel_ticks; /* # of timer ticks in kernel threads. */ static long long kernel_ticks; /* # of timer ticks in kernel threads. */
static long long user_ticks; /* # of timer ticks in user programs. */ static long long user_ticks; /* # of timer ticks in user programs. */
static fp32_t load_avg = { 0 }; /* System load average. */
/* Scheduling. */ /* Scheduling. */
#define TIME_SLICE 4 /* # of timer ticks to give each thread. */ #define TIME_SLICE 4 /* # of timer ticks to give each thread. */
@@ -65,9 +67,12 @@ static void kernel_thread (thread_func *, void *aux);
static void idle (void *aux UNUSED); static void idle (void *aux UNUSED);
static struct thread *running_thread (void); static struct thread *running_thread (void);
static struct thread *next_thread_to_run (void); static struct thread *next_thread_to_run (void);
static void init_thread (struct thread *, const char *name, int priority, fp32_t recent_cpu); static void init_thread (struct thread *, const char *name, int nice,
int priority, fp32_t recent_cpu);
static bool is_thread (struct thread *) UNUSED; static bool is_thread (struct thread *) UNUSED;
static void *alloc_frame (struct thread *, size_t size); static void *alloc_frame (struct thread *, size_t size);
static int calculate_bsd_priority (fp32_t recent_cpu, int nice);
static void thread_update_recent_cpu (struct thread *t, void *aux UNUSED);
static void schedule (void); static void schedule (void);
void thread_schedule_tail (struct thread *prev); void thread_schedule_tail (struct thread *prev);
static tid_t allocate_tid (void); static tid_t allocate_tid (void);
@@ -97,7 +102,8 @@ thread_init (void)
/* Set up a thread structure for the running thread. */ /* Set up a thread structure for the running thread. */
initial_thread = running_thread (); initial_thread = running_thread ();
fp32_t initial_thread_recent_cpu = { 0 }; fp32_t initial_thread_recent_cpu = { 0 };
init_thread (initial_thread, "main", PRI_DEFAULT, initial_thread_recent_cpu); init_thread (initial_thread, "main", NICE_DEFAULT, PRI_DEFAULT,
initial_thread_recent_cpu);
initial_thread->status = THREAD_RUNNING; initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid (); initial_thread->tid = allocate_tid ();
} }
@@ -147,6 +153,25 @@ thread_tick (void)
else else
kernel_ticks++; kernel_ticks++;
/* Update system load_avg and all threads recent_cpu every second. */
int64_t ticks = timer_ticks ();
if (thread_mlfqs && (ticks % TIMER_FREQ == 0))
{
fp32_t old_coeff = fp_mul (fp_div_int (int_to_fp (59), 60), load_avg);
fp32_t new_coeff = fp_div_int (int_to_fp (threads_ready ()), 60);
load_avg = fp_add (old_coeff, new_coeff);
thread_foreach (thread_update_recent_cpu, NULL);
}
/* Update current thread's recent_cpu. */
if (thread_mlfqs && (t != idle_thread))
{
t->recent_cpu = fp_add_int (t->recent_cpu, 1);
if (ticks % 4 == 0) // recent_cpu was updated, update priority.
t->priority = calculate_bsd_priority (t->recent_cpu, t->nice);
}
/* Enforce preemption. */ /* Enforce preemption. */
if (++thread_ticks >= TIME_SLICE) if (++thread_ticks >= TIME_SLICE)
intr_yield_on_return (); intr_yield_on_return ();
@@ -194,8 +219,8 @@ thread_create (const char *name, int priority,
return TID_ERROR; return TID_ERROR;
/* Initialize thread. */ /* Initialize thread. */
fp32_t parent_recent_cpu = thread_current ()->recent_cpu; struct thread *pt = thread_current ();
init_thread (t, name, priority, parent_recent_cpu); init_thread (t, name, pt->nice, priority, pt->recent_cpu);
tid = t->tid = allocate_tid (); tid = t->tid = allocate_tid ();
/* Prepare thread for first run by initializing its stack. /* Prepare thread for first run by initializing its stack.
@@ -357,6 +382,8 @@ thread_foreach (thread_action_func *func, void *aux)
void void
thread_set_priority (int new_priority) thread_set_priority (int new_priority)
{ {
if (thread_mlfqs)
return;
thread_current ()->priority = new_priority; thread_current ()->priority = new_priority;
} }
@@ -367,44 +394,29 @@ thread_get_priority (void)
return thread_current ()->priority; return thread_current ()->priority;
} }
/* Calculates priority for the current thread */ /* Updates recent_cpu for a thread. */
int static void
calculate_priority (void) thread_update_recent_cpu (struct thread *t, void *aux UNUSED)
{ {
/* Not yet implemented */
return 0;
}
void
calculate_recent_cpu (void)
{
struct thread *t = thread_current ();
fp32_t curr_recent_cpu = t->recent_cpu; fp32_t curr_recent_cpu = t->recent_cpu;
fp32_t curr_load_avg = fp_mul_int(thread_get_load_avg (), 2); fp32_t dbl_load_avg = fp_mul_int (load_avg, 2);
fp32_t recent_cpu_coeff = fp_div(curr_load_avg, fp_add_int(curr_load_avg, 1)); fp32_t recent_cpu_coeff
fp32_t new_recent_cpu = fp_add_int(fp_mul(recent_cpu_coeff, curr_recent_cpu), thread_get_nice ()); = fp_div (dbl_load_avg, fp_add_int (dbl_load_avg, 1));
t->recent_cpu = new_recent_cpu; t->recent_cpu
} = fp_add_int (fp_mul (recent_cpu_coeff, curr_recent_cpu), t->nice);
// recent_cpu was updated, update priority.
void t->priority = calculate_bsd_priority (t->recent_cpu, t->nice);
thread_increment_recent_cpu (void)
{
struct thread *t = thread_current ();
if (t == idle_thread)
{
return;
}
fp32_t old_recent_cpu = t->recent_cpu;
old_recent_cpu.raw = old_recent_cpu.raw + 1;
t->recent_cpu = old_recent_cpu;
} }
/* Sets the current thread's nice value to NICE. */ /* Sets the current thread's nice value to NICE. */
void void
thread_set_nice (int nice) thread_set_nice (int nice)
{ {
thread_current ()->nice = nice; ASSERT (NICE_MIN <= nice && nice <= NICE_MAX);
calculate_priority ();
struct thread *t = thread_current ();
t->nice = nice;
int priority = calculate_bsd_priority (t->recent_cpu, t->nice);
} }
/* Returns the current thread's nice value. */ /* Returns the current thread's nice value. */
@@ -418,8 +430,7 @@ thread_get_nice (void)
int int
thread_get_load_avg (void) thread_get_load_avg (void)
{ {
/* Not yet implemented. */ return fp_round (fp_mul_int (load_avg, 100));
return 0;
} }
/* Returns 100 times the current thread's recent_cpu value. */ /* Returns 100 times the current thread's recent_cpu value. */
@@ -502,7 +513,8 @@ is_thread (struct thread *t)
/* Does basic initialization of T as a blocked thread named /* Does basic initialization of T as a blocked thread named
NAME. */ NAME. */
static void static void
init_thread (struct thread *t, const char *name, int priority, fp32_t recent_cpu) init_thread (struct thread *t, const char *name, int nice, int priority,
fp32_t recent_cpu)
{ {
enum intr_level old_level; enum intr_level old_level;
@@ -514,9 +526,11 @@ init_thread (struct thread *t, const char *name, int priority, fp32_t recent_cpu
t->status = THREAD_BLOCKED; t->status = THREAD_BLOCKED;
strlcpy (t->name, name, sizeof t->name); strlcpy (t->name, name, sizeof t->name);
t->stack = (uint8_t *) t + PGSIZE; t->stack = (uint8_t *) t + PGSIZE;
t->priority = priority; t->priority
t->magic = THREAD_MAGIC; = thread_mlfqs ? calculate_bsd_priority (recent_cpu, nice) : priority;
t->nice = nice;
t->recent_cpu = recent_cpu; t->recent_cpu = recent_cpu;
t->magic = THREAD_MAGIC;
old_level = intr_disable (); old_level = intr_disable ();
list_push_back (&all_list, &t->allelem); list_push_back (&all_list, &t->allelem);
@@ -596,8 +610,19 @@ thread_schedule_tail (struct thread *prev)
} }
} }
/* Schedules a new process. At entry, interrupts must be off and /* Calculates BSD priority for a thread */
the running process's state must have been changed from static int
calculate_bsd_priority (fp32_t recent_cpu, int nice)
{
int priority = PRI_MAX - (fp_round (recent_cpu) / 4) - (nice * 2);
if (priority < PRI_MIN)
return PRI_MIN;
if (priority > PRI_MAX)
return PRI_MAX;
return priority;
}
/* ss's state must have been changed from
running to some other state. This function finds another running to some other state. This function finds another
thread to run and switches to it. thread to run and switches to it.

View File

@@ -25,6 +25,10 @@ typedef int tid_t;
#define PRI_DEFAULT 31 /* Default priority. */ #define PRI_DEFAULT 31 /* Default priority. */
#define PRI_MAX 63 /* Highest priority. */ #define PRI_MAX 63 /* Highest priority. */
#define NICE_MIN -20 /* Lowest niceness. */
#define NICE_DEFAULT 0 /* Default niceness. */
#define NICE_MAX 20 /* Highest niceness. */
/* A kernel thread or user process. /* A kernel thread or user process.
Each thread structure is stored in its own 4 kB page. The Each thread structure is stored in its own 4 kB page. The