Compare commits

...

27 Commits

Author SHA1 Message Date
Dias Alberto, Ethan
c24f9a2804 Merge branch 'BSD-merged' into 'ethan-BSD'
Bring personal branch up to date

See merge request lab2425_autumn/pintos_22!7
2024-10-17 15:57:03 +00:00
Dias Alberto, Ethan
0b5d8b1bb8 Merge branch 'gleb/BSD' into 'BSD-merged'
Merge contributions from gleb-bsd to main merged repo

See merge request lab2425_autumn/pintos_22!6
2024-10-17 15:55:23 +00:00
1e09712cc2 fix mlfqs tests, complete BSD scheduling 2024-10-17 02:38:57 +01:00
c767cfe159 Ignore thread_set_priority when BSD enabled 2024-10-16 22:58:03 +01:00
eacd93b32d Optimise load_avg and recent_cpu updates
- only run when BSD scheduler is enabled
2024-10-16 22:56:47 +01:00
de8f303fa2 Implement BSD calculations
- load_avg, recent_cpu, priority calculations
- reduce frac bits to 14
2024-10-16 22:50:46 +01:00
5967257bb0 Fix fixed-point returns 2024-10-16 19:48:08 +01:00
EDiasAlberto
4a5de13d1e implement recent_cpu calculations on every second 2024-10-16 18:45:28 +01:00
EDiasAlberto
7a1aa21e1e implement logic to increment recent_cpu on every timer_interrupt () call 2024-10-16 18:34:56 +01:00
EDiasAlberto
0db3551a9a implement behaviour for thread recent_cpu to be defined based on parent recent_cpu, 0 for initial thread 2024-10-16 18:27:21 +01:00
Dias Alberto, Ethan
96fa718be1 Merge branch 'BSD-merged' into 'ethan-BSD'
Bring personal branch up to date

See merge request lab2425_autumn/pintos_22!5
2024-10-16 17:03:17 +00:00
Dias Alberto, Ethan
51d208f3ef Merge branch 'gleb/BSD' into 'BSD-merged'
Merge rewritten inline funcs into main BSD repo

See merge request lab2425_autumn/pintos_22!4
2024-10-16 17:02:13 +00:00
63742c5717 implement thread_get_nice & thread_get_recent_cpu 2024-10-15 19:56:46 +01:00
27d564ab49 inline funcs instead of macros for fixed-point 2024-10-15 19:45:11 +01:00
EDiasAlberto
efed660968 implement thread_set_nice and make skeleton for calculate_priority 2024-10-15 19:25:02 +01:00
EDiasAlberto
ab66551c06 implement thread_get_nice 2024-10-15 19:21:15 +01:00
EDiasAlberto
3e379acd5e modify gitignore to ignore vscode files 2024-10-15 17:27:16 +01:00
EDiasAlberto
2834af032d fix bracketing issue in ROUNDING_FP_TO_INT 2024-10-15 17:23:03 +01:00
EDiasAlberto
df89bda71e modify thread struct to track thread niceness and recent_cpu time 2024-10-15 17:09:06 +01:00
EDiasAlberto
5178b72370 comment fixed point arithmetic header 2024-10-15 15:34:06 +01:00
EDiasAlberto
724b6065f7 implement macros for fp multiplication and division 2024-10-15 15:24:34 +01:00
EDiasAlberto
1f1ffe4470 add brackets to fixed-point conversion_const calculation for clarity 2024-10-15 15:15:16 +01:00
EDiasAlberto
42b0ff9d17 define basic fixed-point arithmetic operations 2024-10-15 15:13:40 +01:00
EDiasAlberto
4e271ea5ab rewrite fixed-point.h to not have magic numbers 2024-10-15 15:04:26 +01:00
EDiasAlberto
4f6849c4a4 fix gitignore formatting 2024-10-15 14:59:57 +01:00
EDiasAlberto
1eb9abfdcd update gitignore to remove CLion files 2024-10-15 14:58:35 +01:00
EDiasAlberto
1042295e5f define fixed point arithmetic constants 2024-10-15 14:57:37 +01:00
5 changed files with 215 additions and 18 deletions

3
.gitignore vendored
View File

@@ -24,3 +24,6 @@
*.nav *.nav
*.toc *.toc
#ignore files from CLion/VSCode IDEs
.idea
.vscode

95
src/threads/fixed-point.h Normal file
View File

@@ -0,0 +1,95 @@
#include <stdint.h>
#ifndef FIXED_POINT_H
#define FIXED_POINT_H
typedef struct
{
int32_t raw;
} fp32_t;
/* Fixed Point Arithmetic bit count constants */
#define NUM_FRAC_BITS 14
#define NUM_INT_BITS (31 - NUM_FRAC_BITS)
#define CONVERSION_CONST (1 << NUM_FRAC_BITS) /* f = 2^q, (2^20) */
/* Fixed Point Arithmetic conversion operations */
/* Converts an integer n to a fixed point number */
inline fp32_t
int_to_fp (int32_t n)
{
return (fp32_t){ n * CONVERSION_CONST };
}
/* Handles conversion of fixed point to integer. First version truncates, second one rounds */
inline int32_t
fp_floor (fp32_t x)
{
return x.raw / CONVERSION_CONST;
}
inline int32_t
fp_round (fp32_t x)
{
if (x.raw >= 0)
return (x.raw + CONVERSION_CONST / 2) / CONVERSION_CONST;
else
return (x.raw - CONVERSION_CONST / 2) / CONVERSION_CONST;
}
/* Add two fixed points */
inline fp32_t
fp_add (fp32_t x, fp32_t y)
{
return (fp32_t){ x.raw + y.raw };
}
/* Subtract two fixed points */
inline fp32_t
fp_sub (fp32_t x, fp32_t y)
{
return (fp32_t){ x.raw - y.raw };
}
/* Add fixed point to integer */
inline fp32_t
fp_add_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw + n * CONVERSION_CONST };
}
/* Subtract integer from fixed point */
inline fp32_t
fp_sub_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw - n * CONVERSION_CONST };
}
/* Multiple two fixed points */
inline fp32_t
fp_mul (fp32_t x, fp32_t y)
{
return (fp32_t){ ((int64_t)x.raw) * y.raw / CONVERSION_CONST };
}
/* Divide two fixed points */
inline fp32_t
fp_div (fp32_t x, fp32_t y)
{
return (fp32_t){ ((int64_t)x.raw) * CONVERSION_CONST / y.raw };
}
/* Multiply fixed point and integer */
inline fp32_t
fp_mul_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw * n };
}
/* Divide fixed point by integer */
inline fp32_t
fp_div_int (fp32_t x, int32_t n)
{
return (fp32_t){ x.raw / n };
}
#endif //FIXED_POINT_H

View File

@@ -233,6 +233,7 @@ lock_release (struct lock *lock)
lock->holder = NULL; lock->holder = NULL;
sema_up (&lock->semaphore); sema_up (&lock->semaphore);
thread_yield ();
} }
/* Returns true if the current thread holds LOCK, false /* Returns true if the current thread holds LOCK, false

View File

@@ -4,6 +4,8 @@
#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/flags.h" #include "threads/flags.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
#include "threads/intr-stubs.h" #include "threads/intr-stubs.h"
@@ -49,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. */
@@ -64,9 +67,14 @@ 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); 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 bool thread_priority_less (const struct list_elem *a,
const struct list_elem *b, 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);
@@ -95,7 +103,9 @@ 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 ();
init_thread (initial_thread, "main", PRI_DEFAULT); fp32_t initial_thread_recent_cpu = { 0 };
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 ();
} }
@@ -145,6 +155,28 @@ 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))
{
size_t ready = threads_ready ();
if (t != idle_thread)
ready++;
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 (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 ();
@@ -192,7 +224,8 @@ thread_create (const char *name, int priority,
return TID_ERROR; return TID_ERROR;
/* Initialize thread. */ /* Initialize thread. */
init_thread (t, name, priority); struct thread *pt = thread_current ();
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.
@@ -256,6 +289,9 @@ thread_unblock (struct thread *t)
old_level = intr_disable (); old_level = intr_disable ();
ASSERT (t->status == THREAD_BLOCKED); ASSERT (t->status == THREAD_BLOCKED);
if (thread_mlfqs)
list_insert_ordered (&ready_list, &t->elem, thread_priority_less, NULL);
else
list_push_back (&ready_list, &t->elem); list_push_back (&ready_list, &t->elem);
t->status = THREAD_READY; t->status = THREAD_READY;
intr_set_level (old_level); intr_set_level (old_level);
@@ -327,7 +363,13 @@ thread_yield (void)
old_level = intr_disable (); old_level = intr_disable ();
if (cur != idle_thread) if (cur != idle_thread)
{
if (thread_mlfqs)
list_insert_ordered (&ready_list, &cur->elem, thread_priority_less,
NULL);
else
list_push_back (&ready_list, &cur->elem); list_push_back (&ready_list, &cur->elem);
}
cur->status = THREAD_READY; cur->status = THREAD_READY;
schedule (); schedule ();
intr_set_level (old_level); intr_set_level (old_level);
@@ -354,6 +396,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;
} }
@@ -364,35 +408,54 @@ thread_get_priority (void)
return thread_current ()->priority; return thread_current ()->priority;
} }
/* Updates recent_cpu for a thread. */
static void
thread_update_recent_cpu (struct thread *t, void *aux UNUSED)
{
fp32_t curr_recent_cpu = t->recent_cpu;
fp32_t dbl_load_avg = fp_mul_int (load_avg, 2);
fp32_t recent_cpu_coeff
= fp_div (dbl_load_avg, fp_add_int (dbl_load_avg, 1));
t->recent_cpu
= fp_add_int (fp_mul (recent_cpu_coeff, curr_recent_cpu), t->nice);
// recent_cpu was updated, update priority.
t->priority = calculate_bsd_priority (t->recent_cpu, t->nice);
}
/* 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 UNUSED) thread_set_nice (int nice)
{ {
/* Not yet implemented. */ ASSERT (NICE_MIN <= nice && nice <= NICE_MAX);
struct thread *t = thread_current ();
t->nice = nice;
int priority = calculate_bsd_priority (t->recent_cpu, t->nice);
struct thread *next_t
= list_entry (list_begin (&ready_list), struct thread, elem);
if (priority < next_t->priority)
thread_yield ();
} }
/* Returns the current thread's nice value. */ /* Returns the current thread's nice value. */
int int
thread_get_nice (void) thread_get_nice (void)
{ {
/* Not yet implemented. */ return thread_current ()->nice;
return 0;
} }
/* Returns 100 times the system load average. */ /* Returns 100 times the system load average. */
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. */
int int
thread_get_recent_cpu (void) thread_get_recent_cpu (void)
{ {
/* Not yet implemented. */ return fp_round (fp_mul_int (thread_current ()->recent_cpu, 100));
return 0;
} }
/* Idle thread. Executes when no other thread is ready to run. /* Idle thread. Executes when no other thread is ready to run.
@@ -468,7 +531,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) 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;
@@ -480,7 +544,10 @@ init_thread (struct thread *t, const char *name, int priority)
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
= thread_mlfqs ? calculate_bsd_priority (recent_cpu, nice) : priority;
t->nice = nice;
t->recent_cpu = recent_cpu;
t->magic = THREAD_MAGIC; t->magic = THREAD_MAGIC;
old_level = intr_disable (); old_level = intr_disable ();
@@ -561,8 +628,30 @@ 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;
}
/* Returns true if thread a's priority is strictly greater than
thread b's priority. */
static bool
thread_priority_less (const struct list_elem *a, const struct list_elem *b,
void *aux UNUSED)
{
struct thread *ta = list_entry (a, struct thread, elem);
struct thread *tb = list_entry (b, struct thread, elem);
return ta->priority > tb->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

@@ -4,6 +4,7 @@
#include <debug.h> #include <debug.h>
#include <list.h> #include <list.h>
#include <stdint.h> #include <stdint.h>
#include "threads/fixed-point.h"
/* States in a thread's life cycle. */ /* States in a thread's life cycle. */
enum thread_status enum thread_status
@@ -24,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
@@ -93,6 +98,10 @@ struct thread
/* Shared between thread.c and synch.c. */ /* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */ struct list_elem elem; /* List element. */
/* MLFQS items */
int nice; /* Nice value for this thread */
fp32_t recent_cpu; /* Amount of time this process received */
#ifdef USERPROG #ifdef USERPROG
/* Owned by userprog/process.c. */ /* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */ uint32_t *pagedir; /* Page directory. */