WIP on hw3
This commit is contained in:
parent
45efb57647
commit
c6c8c95690
3 changed files with 292 additions and 42 deletions
156
pintos-env/pintos/threads/fpr_arith.h
Normal file
156
pintos-env/pintos/threads/fpr_arith.h
Normal file
|
@ -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_ */
|
174
pintos-env/pintos/threads/thread.c
Executable file → Normal file
174
pintos-env/pintos/threads/thread.c
Executable file → Normal file
|
@ -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
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <debug.h>
|
||||
#include <list.h>
|
||||
#include <stdint.h>
|
||||
#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. */
|
||||
|
|
Reference in a new issue