From c6c8c95690f60b5e0b2bbd84c3a078164d9fff08 Mon Sep 17 00:00:00 2001 From: Claudio Maggioni Date: Mon, 13 Apr 2020 14:24:44 +0200 Subject: [PATCH] WIP on hw3 --- pintos-env/pintos/threads/fpr_arith.h | 156 +++++++++++++++++++++++ pintos-env/pintos/threads/thread.c | 174 +++++++++++++++++++------- pintos-env/pintos/threads/thread.h | 4 + 3 files changed, 292 insertions(+), 42 deletions(-) create mode 100644 pintos-env/pintos/threads/fpr_arith.h mode change 100755 => 100644 pintos-env/pintos/threads/thread.c diff --git a/pintos-env/pintos/threads/fpr_arith.h b/pintos-env/pintos/threads/fpr_arith.h new file mode 100644 index 0000000..680c553 --- /dev/null +++ b/pintos-env/pintos/threads/fpr_arith.h @@ -0,0 +1,156 @@ +/* + * fpr_arith.h + * + * Created on: 20/03/2013 + * Author: Eduardo Bezerra - kdubezerra@gmail.com + */ + +#ifndef FPR_ARITH_H_ +#define FPR_ARITH_H_ + +/* FIXED POINT REAL + + This header contains the definition of the FPReal type, which + is a signed 32 bits integer. It has the following structure: + + 32 bits: + 1 for sign + 17 for integer part + 14 for fractional part + + See section B.6 of Pintos documentation for a detailed explanation: + http://www2.icorsi.ch/mod/resource/view.php?id=91264 + +*/ + +/* Fixed-point real type. */ +typedef int FPReal; + +/* Number of bits reserved for the fractional part. */ +#define FRACBITS 14 + +/* Convert an FPReal to int */ +static inline int FPR_TO_INT (FPReal fpr); + +/* Convert an int to FPReal */ +static inline FPReal INT_TO_FPR (int); + +/* Increment an FPReal by 1 */ +static inline FPReal FPR_INC (FPReal *); + +/* Add two FPReals */ +static inline FPReal FPR_ADD_FPR (FPReal, FPReal); + +/* Subtract one FPReal from another */ +static inline FPReal FPR_SUB_FPR (FPReal, FPReal); + +/* Multiply an FPReal by an int */ +static inline FPReal FPR_MUL_INT (FPReal, int); + +/* Divide an FPReal by an int */ +static inline FPReal FPR_DIV_INT (FPReal, int); + +/* Add an int to an FPReal */ +static inline FPReal FPR_ADD_INT (FPReal, int); + +/* Subtract an int from an FPReal */ +static inline FPReal FPR_SUB_INT (FPReal, int); + +/* Multiply two FPReals */ +static inline FPReal FPR_MUL_FPR (FPReal, FPReal); + +/* Divide an FPReal by another */ +static inline FPReal FPR_DIV_FPR (FPReal, FPReal); + +/* Divide two ints and return the real result as an FPReal */ +static inline FPReal INT_DIV_INT (int, int); + + + + +/* ==================================*/ +/* FPReal functions implementations. */ + +/* Convert an FPReal to int */ +static inline int +FPR_TO_INT (FPReal fpr) { + return fpr >> FRACBITS; +} + +/* Convert an int to FPReal */ +static inline FPReal +INT_TO_FPR (int i) { + return i << FRACBITS; +} + +/* Increment an FPReal by 1 */ +static inline +FPReal FPR_INC (FPReal * fpr) { + (*fpr) += (1 << FRACBITS); + return *fpr; +} + +/* Add two FPReals */ +static inline +FPReal FPR_ADD_FPR (FPReal fpr_a, FPReal fpr_b) { + return fpr_a + fpr_b; +} + +/* Subtract one FPReal from another */ +static inline +FPReal FPR_SUB_FPR (FPReal fpr_a, FPReal fpr_b) { + return fpr_a - fpr_b; +} + +/* Multiply an FPReal by an int */ +static inline +FPReal FPR_MUL_INT (FPReal fpr_a, int b) { + return fpr_a * b; +} + +/* Divide an FPReal by an int */ +static inline +FPReal FPR_DIV_INT (FPReal fpr_a, int b) { + return fpr_a / b; +} + +/* Add an int to an FPReal */ +static inline +FPReal FPR_ADD_INT (FPReal fpr_a, int b) { + return fpr_a + (b << FRACBITS); +} + +/* Subtract an int from an FPReal */ +static inline +FPReal FPR_SUB_INT (FPReal fpr_a, int b) { + return fpr_a - (b << FRACBITS); +} + +/* Multiply two FPReals */ +static inline +FPReal FPR_MUL_FPR (FPReal fpr_a, FPReal fpr_b) { + int64_t extended_a = fpr_a; + extended_a *= (int64_t) fpr_b; + extended_a >>= FRACBITS; + return (FPReal) extended_a; +} + +/* Divide an FPReal by another */ +static inline +FPReal FPR_DIV_FPR (FPReal fpr_a, FPReal fpr_b) { + int64_t extended_a = fpr_a; + extended_a <<= FRACBITS; + extended_a /= (int64_t) fpr_b; + return (FPReal) extended_a; +} + +/* Divide two ints and return the real result as an FPReal */ +static inline +FPReal INT_DIV_INT (int a, int b) { + int64_t exta = a; + exta <<= FRACBITS; + exta /= b; + return (FPReal) exta; +} + +#endif /* FPR_ARITH_H_ */ diff --git a/pintos-env/pintos/threads/thread.c b/pintos-env/pintos/threads/thread.c old mode 100755 new mode 100644 index 4629e8c..a720051 --- a/pintos-env/pintos/threads/thread.c +++ b/pintos-env/pintos/threads/thread.c @@ -43,6 +43,8 @@ static struct lock tid_lock; static struct list sleeping; +static FPReal load_avg; + /* Stack frame for kernel_thread(). */ struct kernel_thread_frame { @@ -76,6 +78,9 @@ static void *alloc_frame (struct thread *, size_t size); static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); +void thread_yield_for_higher_priority(void); +static void compute_mlfqs_priority(struct thread* t); +bool comp_priority(struct list_elem *, struct list_elem *, void *); /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in @@ -106,6 +111,7 @@ thread_init (void) initial_thread->tid = allocate_tid (); list_init(&sleeping); + load_avg = INT_TO_FPR(0); } static bool @@ -163,6 +169,8 @@ thread_start (void) sema_down (&idle_started); } +static int tick_count = 0; + /* Called by the timer interrupt handler at each timer tick. Thus, this function runs in an external interrupt context. */ void @@ -180,11 +188,77 @@ thread_tick (void) else kernel_ticks++; + ++thread_ticks; + ++tick_count; + + if (thread_mlfqs) { + if (thread_ticks % 4 == 0) { + compute_mlfqs_priority(t); + } + t->recent_cpu = FPR_ADD_INT(t->recent_cpu, 1); + + if (tick_count >= TIMER_FREQ) { // this is true every second + tick_count = 0; + + int thr_running = thread_current() == idle_thread ? 0 : 1; + thr_running += list_size(&ready_list); + + load_avg = FPR_ADD_FPR( + FPR_MUL_FPR(INT_DIV_INT(59, 60), load_avg), + FPR_MUL_INT(INT_DIV_INT(1, 60), thr_running)); + + FPReal dag = FPR_MUL_INT(load_avg, 2); + + t->recent_cpu = FPR_MUL_FPR(t->recent_cpu, + FPR_DIV_FPR(dag, FPR_ADD_INT(dag, 1))) + INT_TO_FPR(t->nice); + + if (t->recent_cpu > INT_TO_FPR(100)) { + t->recent_cpu = INT_TO_FPR(100); + } else if (t->recent_cpu < INT_TO_FPR(0)) { + t->recent_cpu = INT_TO_FPR(0); + } + + printf("recent_cpu: %d\n", t->recent_cpu); + //printf("load_avg: %d - threads_ready: %d\n", load_avg, thr_running); + } + } + /* Enforce preemption. */ - if (++thread_ticks >= TIME_SLICE) + if (thread_ticks >= TIME_SLICE) intr_yield_on_return (); } +int +thread_get_nice (void) +{ + return thread_current()->nice; +} + +void +thread_set_nice (int nice) +{ + struct thread* t = thread_current(); + + enum intr_level old_level = intr_disable(); + t->nice = nice > 20 || nice < -20 ? 0 : nice; + compute_mlfqs_priority(t); + intr_set_level(old_level); + + thread_yield_for_higher_priority(); +} + +int +thread_get_recent_cpu (void) +{ + return FPR_TO_INT(FPR_MUL_INT(thread_current()->recent_cpu, 100)); +} + +int +thread_get_load_avg (void) +{ + return FPR_TO_INT(FPR_MUL_INT(load_avg, 100)); +} + /* Prints thread statistics. */ void thread_print_stats (void) @@ -255,6 +329,8 @@ thread_create (const char *name, int priority, /* Add to run queue. */ thread_unblock (t); + thread_yield_for_higher_priority(); + return tid; } @@ -385,51 +461,19 @@ thread_foreach (thread_action_func *func, void *aux) } } +int +thread_get_priority (void) { + return thread_current()->priority; +} + /* Sets the current thread's priority to NEW_PRIORITY. */ void thread_set_priority (int new_priority) { thread_current ()->priority = new_priority; + thread_yield_for_higher_priority(); } -/* Returns the current thread's priority. */ -int -thread_get_priority (void) -{ - return thread_current ()->priority; -} - -/* Sets the current thread's nice value to NICE. */ -void -thread_set_nice (int nice UNUSED) -{ - /* Not yet implemented. */ -} - -/* Returns the current thread's nice value. */ -int -thread_get_nice (void) -{ - /* Not yet implemented. */ - return 0; -} - -/* Returns 100 times the system load average. */ -int -thread_get_load_avg (void) -{ - /* Not yet implemented. */ - return 0; -} - -/* Returns 100 times the current thread's recent_cpu value. */ -int -thread_get_recent_cpu (void) -{ - /* Not yet implemented. */ - return 0; -} - /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by @@ -500,6 +544,15 @@ is_thread (struct thread *t) return t != NULL && t->magic == THREAD_MAGIC; } +static void +compute_mlfqs_priority(struct thread* t) { + t->priority = PRI_MAX - FPR_TO_INT(FPR_DIV_INT(t->recent_cpu, 4)) + - (t->nice * 2); + + if (t->priority < PRI_MIN) t->priority = PRI_MIN; + else if (t->priority > PRI_MAX) t->priority = PRI_MAX; +} + /* Does basic initialization of T as a blocked thread named NAME. */ static void @@ -513,7 +566,16 @@ init_thread (struct thread *t, const char *name, int priority) t->status = THREAD_BLOCKED; strlcpy (t->name, name, sizeof t->name); t->stack = (uint8_t *) t + PGSIZE; - t->priority = priority; + + if (thread_mlfqs) { + t->nice_init = priority > 20 || priority < 20 ? 0 : priority; + t->nice = t->nice_init; + t->recent_cpu = 0; + compute_mlfqs_priority(t); + } else { + t->priority = priority; + } + t->magic = THREAD_MAGIC; list_push_back (&all_list, &t->allelem); } @@ -541,8 +603,36 @@ next_thread_to_run (void) { if (list_empty (&ready_list)) return idle_thread; - else - return list_entry (list_pop_front (&ready_list), struct thread, elem); + else { + // return list_entry (list_pop_front (&ready_list), struct thread, elem); + + struct list_elem * th_max_elem = list_max(&ready_list, comp_priority, NULL); + struct thread * th_max = list_entry(th_max_elem, struct thread, elem); + list_remove(th_max_elem); + return th_max; + } +} + +bool comp_priority(struct list_elem * a, struct list_elem * b, void *aux) { + struct thread * at = list_entry(a, struct thread, elem); + struct thread * bt = list_entry(b, struct thread, elem); + + return at -> priority < bt -> priority; +} + +void thread_yield_for_higher_priority(void) { + enum intr_level old_level = intr_disable(); + + if (!list_empty(&ready_list)) { + struct list_elem * th_max_elem = list_max(&ready_list, comp_priority, NULL); + struct thread * th_max = list_entry(th_max_elem, struct thread, elem); + + struct thread * th_cur = thread_current(); + if (th_cur -> priority < th_max -> priority) + thread_yield(); + } + +intr_set_level(old_level); } /* Completes a thread switch by activating the new thread's page diff --git a/pintos-env/pintos/threads/thread.h b/pintos-env/pintos/threads/thread.h index 10d3206..a37b265 100755 --- a/pintos-env/pintos/threads/thread.h +++ b/pintos-env/pintos/threads/thread.h @@ -7,6 +7,7 @@ #include #include #include +#include "threads/fpr_arith.h" /* States in a thread's life cycle. */ enum thread_status @@ -95,6 +96,9 @@ struct thread uint64_t wakeup; /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ + int nice; + int nice_init; + FPReal recent_cpu; #ifdef USERPROG /* Owned by userprog/process.c. */