๐ฉ๐ปโ๐ป GITHUB ๋ ํฌ์งํ ๋ฆฌ
๐ฉ๐ปโ๐ป GITHUB Priority Donation ์ด์
๐โโ๏ธ WIL-Advancde Scheduler ๋ฐํ์๋ฃ ๋ณด๋ฌ๊ฐ๊ธฐ
์ด์ ๊น์ง ๊ตฌํํ priority scheduler ๋ ๊ทธ ์คํ์ ์ค์ง priority ์๋ง ๋งก๊ธฐ๊ธฐ ๋๋ฌธ์ priority ๊ฐ ๋ฎ์ ์ค๋ ๋๋ค์ CPU ๋ฅผ ์ ์ ํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ต๊ณ ์ด๋ก ์ธํ์ฌ ํ๊ท ๋ฐ์์๊ฐ(Average response time) ์ ๊ธ๊ฒฉํ ์ปค์ง ๊ฐ๋ฅ์ฑ์ด ์๋ค. ๋ฌผ๋ก priority donation ์ ํตํ์ฌ priority ๊ฐ ๋์ ์ค๋ ๋๋ค์ด ์คํ๋๋ ๋ฐ ํ์ํ ์ค๋ ๋๋ priority ์ ๋ณด์ ์ ๋ฐ์ง๋ง, ์ด๋ง์ ๋ ๋ฐ์ง ๋ชปํ๋ ์ค๋ ๋๊ฐ ์กด์ฌํ ๊ฐ๋ฅ์ฑ๋ ๋งค์ฐ ํฌ๋ค. Advanced Scheduler ๋ ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ average response time ์ ์ค์ด๊ธฐ ์ํด multi-level feedback queue ์ค์ผ์ค๋ง ๋ฐฉ์์ ๋์ ํ๋ค. ์ด ์ค์ผ์ค๋ง ๋ฐฉ์์ ํน์ง์ ํฌ๊ฒ ๋ ๊ฐ์ง๊ฐ ์๋ค. ์ด ํ๋ก์ ํธ์์๋ 2๋ฒ์ ์ด์ฉํด์ ๊ตฌํํ๋ค.
- Priority ์ ๋ฐ๋ผ ์ฌ๋ฌ ๊ฐ์ Ready Queue ๊ฐ ์กด์ฌํ๋ค. (Multi-level)
- Priority ๋ ์ค์๊ฐ์ผ๋ก ์กฐ์ ํ๋ค. (Feedback)
๊ตฌํ์ ์ํด ์๋ก ์ถ๊ฐ๋๋ ์๋ฃ๊ตฌ์กฐ๋ค์ด ์๋ค.
1๏ธโฃ NICENESS
2๏ธโฃ PRIORITY
3๏ธโฃ RECENT_CPU
4๏ธโฃ LOAD AVG
PRIORITY, RECENT_CPU, LOAD_AVG๋ฅผ ๊ตฌํ๋ ์์ ๋ค์๊ณผ ๊ฐ๋ค.
PRIORITY๋ ์ ์๋ ๊ฐ์ค์น๋ก ๊ฒฐ์ ๋๊ฒ ๋๊ณ , RECENT CPU์ ๊ฒฝ์ฐ CPU ์ ์ ์๊ฐ์ ๊ฐ์ ์ง์ ๊ฐ์ค ํ๊ท ์ ์ฌ์ฉํ์ฌ ๊ณ์ฐํ๊ฒ ๋๋ค. LOAD AVERAGE๋ 1๋ถ ๋์ ์ํ ๊ฐ๋ฅํ ์ค๋ ๋์ ํ๊ท ๊ฐ์๋ฅผ ์ถ์ ํ๋ ๊ณ์ฐ์์ด๋ค.
NICENESS๊ฐ ์๋๋ฐ ์ด๋ Test Program์์ ์์๋ก ์ง์ ํด ์ค๋ค.
๐ก ์ด ๋ ์ฃผ์ํด์ผ ํ ์ ์ด ์๋ค. ๋ฐ๋ก ์ค์ํ์ด๋ผ๋ ๊ฒ!
๊ทธ๋ฌ๋ ํํ ์ค์์๋ ์ค์๋ฅผ ์ง์ํ์ง ์์!!! ์ด๋ฅผ ์ํด ๊ณ ์ ์์์ ํํ์ ์ฌ์ฉํ๊ฒ ๋จ..!!!
๊ณ ์ ์์์ ํํ์ด๋ 32๋นํธ์ง๋ฆฌ ์ ์ํ์ ๊ฐ๊ณ 14๋ฒ์งธ ์๋ฆฌ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ์ผ ์ 1์๋ฆฌ๋ ๋ถํธ, ์ผ์ชฝ 17์๋ฆฌ๋ ์ ์, ์ค๋ฅธ์ชฝ 14์๋ฆฌ๋ ์์๋ก ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ด๋ค.
๊ทธ๋์ F๋ผ๋ 2์14์น์ง๋ฆฌ ์ซ์๋ฅผ ๋ง๋ค์ด ์ค์์ ์ ์๋ฅผ ์ ํํ๊ฒ ๋๊ณ ์ด์ ๋ฐ๋ผ ํน์ํ ๋งคํฌ๋ก๋ฅผ ๋ง๋ค์ด ์ฐ์ฐ์ ์ํํด์ผ ํ๋ค. ์๋ฅผ ๋ค๋ฉด ๋ง์ ์ ํ ๋๋ ์ ์์ F๋ฅผ ๊ณฑํด ์ค์๋ก ๋ง๋ค์ด ์ค ์ ์๋ค. ์ค์๋ผ๋ฆฌ ๊ณฑ์ ์ ํ ๋๋ ๋ ๋ค F๊ฐ ๊ณฑํด์ง ์ํ์ด๋ฏ๋ก ์ค๋ณต๋ F๋ฅผ ์ญ์ ํ๊ธฐ ์ํด F๋ก ๋๋์ด ์ค๋ค.
Multi-Level Feedback Queue ์ค์ผ์ฅด๋ฌ( BSD ์ค์ผ์ค๋ฌ์ ์ ์ฌ) ๊ตฌํ
void thread_set_priority(int new_priority)
: ํ์ฌ ์ํ์ค์ธ ์ค๋ ๋์ ์ฐ์ ์์๋ฅผ ๋ณ๊ฒฝstatic void timer_interrupt(struct intr_frame *args UNUSED)
: timer interrupt ํธ๋ค๋ฌint thread_get_nice (void)
void thread_set_nice (int)
int thread_get_recent_cpu (void)
int thread_get_load_avg (void)
void mlfqs_priority (struct thread *t)
: ์ธ์๋ก ์ฃผ์ด์ง ์ค๋ ๋์ priority๋ฅผ ์
๋ฐ์ดํธvoid mlfqs_recent_cpu (struct thread *t)
: ์ธ์๋ก ์ฃผ์ด์ง ์ค๋ ๋์ recent_cpu๋ฅผ ์
๋ฐ์ดํธvoid mlfqs_load_avg (void)
: ์์คํ
์ load_avg๋ฅผ ์
๋ฐ์ดํธvoid mlfqs_increment (void)
: ํ์ฌ ์ํ์ค์ธ ์ค๋ ๋์ recent_cpu๋ฅผ 1์ฆ๊ฐ ์ํดvoid mlfqs_recalc (void)
: ๋ชจ๋ ์ค๋ ๋์ priority, recent_cpu๋ฅผ ์
๋ฐ์ดํธ๋์ ์์ ์ค
Source ./activate
์์น๊ฒ ํ๋๋ฒ!!
๋ฃจํธ ๋๋ ํ ๋ฆฌ๋ก ์ด๋
code .bashrc
์
๋ ฅ
ํ์ผ ์ ์ผ ๋ฐ์ ๋ณธ์ธ์ source activate ๊ฒฝ๋ก ์ถ๊ฐ
/pintos ๊ฒฝ๋ก์์ source ./activate
(์ฌ์ ํ๊ฒฝ ์ค์ ์ ํ๋ค๋ฉด ์ํด์ค๋ ๋๋ค!)
threads ํด๋ ๋ค์ด๊ฐ์ make clean
make check
๋ฅผ ์ํํ๋ฉด Test Case๋ค์ ๋ํด์ ์ฑ์ ์ ์ํํ๋ค.
Test Case ํ๊ฐ์ง๋ง ๋๋ฆฌ๊ณ ์ถ๋ค๋ฉด, pintos/(ํ๋ก์ ํธ๋ช
)/build์ ๋ค์ด๊ฐ์ ์๋ ๋ช
๋ น์ด๋ฅผ ์ํํ๋ฉด ๋๋ค.
pintos -T (Timout์ด ๊ฑธ๋ฆฌ๋ ์๊ฐ) -- -q -run (Test case ์ด๋ฆ)
ex) `pintos -T 30 -- -q run donate-one
.
.
.
/** project1-Advanced Scheduler */
#define NICE_DEFAULT 0
#define RECENT_CPU_DEFAULT 0
#define LOAD_AVG_DEFAULT 0
.
.
.
/** project1-Advanced Scheduler */
int niceness;
int recent_cpu;
.
.
.
/** project1-Advanced Scheduler */
void mlfqs_priority(struct thread *t);
void mlfqs_recent_cpu(struct thread *t);
void mlfqs_load_avg(void);
void mlfqs_increment(void);
void mlfqs_recalc_recent_cpu(void);
void mlfqs_recalc_priority(void);
int niceness;
int recent_cpu;
struct list_elem all_elem; /** project1-Advanced Scheduler */
static struct list ready_list;
/** project1-Advanced Scheduler */
static struct list all_list;
/* Idle thread. */
static struct thread *idle_thread;
.
.
.
all list ์ด๊ธฐํ
void
thread_init (void) {
ASSERT (intr_get_level () == INTR_OFF);
/* Reload the temporal gdt for the kernel
* This gdt does not include the user context.
* The kernel will rebuild the gdt with user context, in gdt_init (). */
struct desc_ptr gdt_ds = {
.size = sizeof (gdt) - 1,
.address = (uint64_t) gdt
};
lgdt (&gdt_ds);
/* Init the globla thread context */
lock_init (&tid_lock);
list_init (&ready_list);
list_init (&destruction_req);
list_init (&sleep_list); /** project1-Alarm Clock */
list_init(&all_list); /** project1-Advanced Scheduler */
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
/** project1-Advanced Scheduler */
if (thread_mlfqs)
list_push_back(&all_list, &(initial_thread->all_elem));
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
}
static void
init_thread (struct thread *t, const char *name, int priority) {
ASSERT (t != NULL);
ASSERT (PRI_MIN <= priority && priority <= PRI_MAX);
ASSERT (name != NULL);
memset (t, 0, sizeof *t);
t->status = THREAD_BLOCKED;
strlcpy (t->name, name, sizeof t->name);
t->tf.rsp = (uint64_t) t + PGSIZE - sizeof (void *);
/** project1-Advanced Scheduler */
if (thread_mlfqs) {
mlfqs_priority(t);
list_push_back(&all_list, &t->all_elem);
} else {
t->priority = priority;
}
t->wait_lock = NULL;
list_init(&t->donations);
t->magic = THREAD_MAGIC;
/** #Advanced Scheduler */
t->original_priority = t->priority;
t->niceness = NICE_DEFAULT;
t->recent_cpu = RECENT_CPU_DEFAULT;
}
/** project1-Advanced Scheduler */
#define F (1 << 14)
#define INT_MAX ((1 << 31) - 1)
#define INT_MIN (-(1 << 31))
/*
* ๊ณ ์ ์์์ ์ ์ํ ์ฐ์ ์ฐ์ฐ
* n: int ; x, y: ๊ณ ์ ์์์ ์ซ์ ; F: 17.14๋ก ํํํ 1
*/
int int_to_fp(int n); /* integer๋ฅผ fixed point๋ก ์ ํ */
int fp_to_int_round(int x); /* FP๋ฅผ int๋ก ์ ํ(๋ฐ์ฌ๋ฆผ) */
int fp_to_int(int x); /* FP๋ฅผ int๋ก ์ ํ(๋ฒ๋ฆผ) */
int add_fp(int x, int y); /* FP์ ๋ง์
*/
int add_mixed(int x, int n); /* FP์ int์ ๋ง์
*/
int sub_fp(int x, int y); /* FP์ ๋บ์
(x-y) */
int sub_mixed(int x, int n); /* FP์ int์ ๋บ์
(x-n) */
int mult_fp(int x, int y); /* FP์ ๊ณฑ์
*/
int mult_mixed(int x, int y); /* FP์ int์ ๊ณฑ์
*/
int div_fp(int x, int y); /* FP์ ๋๋์
(x/y) */
int div_mixed(int x, int n); /* FP์ int ๋๋์
(x/n) */
/* ํจ์ ๋ณธ์ฒด */
/* integer๋ฅผ fixed point๋ก ์ ํ */
int int_to_fp(int n) {
return n * F;
}
/* FP๋ฅผ int๋ก ์ ํ(๋ฐ์ฌ๋ฆผ) */
int fp_to_int_round(int x) {
if (x >= 0)
return (x + F / 2) / F;
else
return (x - F / 2) / F;
}
/* FP๋ฅผ int๋ก ์ ํ(๋ฒ๋ฆผ) */
int fp_to_int(int x) {
return x / F;
}
/* FP์ ๋ง์
*/
int add_fp(int x, int y) {
return x + y;
}
/* FP์ int์ ๋ง์
*/
int add_mixed(int x, int n) {
return x + n * F;
}
/* FP์ ๋บ์
(x-y) */
int sub_fp(int x, int y) {
return x - y;
}
/* FP์ int์ ๋บ์
(x-n) */
int sub_mixed(int x, int n) {
return x - n * F;
}
/* FP์ ๊ณฑ์
*/
int mult_fp(int x, int y) {
return ((int64_t)x) * y / F;
}
/* FP์ int์ ๊ณฑ์
*/
int mult_mixed(int x, int n) {
return x * n;
}
/* FP์ ๋๋์
(x/y) */
int div_fp(int x, int y) {
return ((int64_t)x) * F / y;
}
/* FP์ int ๋๋์
(x/n) */
int div_mixed(int x, int n) {
return x / n;
}
#include "threads/synch.h"
#include "threads/vaddr.h"
#include "intrinsic.h"
#include "threads/fixed_point.h" /** project1-Advanced Scheduler */
#ifdef USERPROG
#include "userprog/process.h"
#endif
.
.
.
bool thread_mlfqs;
/** project1-Advanced Scheduler */
int load_avg;
.
.
. struct semaphore idle_started;
sema_init (&idle_started, 0);
thread_create ("idle", PRI_MIN, idle, &idle_started);
/** project1-Advanced Scheduler */
load_avg = LOAD_AVG_DEFAULT;
/* Start preemptive thread scheduling. */
intr_enable ();
recent_cpu์ nice๊ฐ์ ์ด์ฉํ์ฌ priority๋ฅผ ๊ณ์ฐ
/** project1-Advanced Scheduler */
void
mlfqs_priority (struct thread *t)
{
if (t == idle_thread)
return;
t->priority = fp_to_int(add_mixed(div_mixed(t->recent_cpu, -4), PRI_MAX - t->niceness * 2));
}
recent_cpu ๊ฐ ๊ณ์ฐ
/** project1-Advanced Scheduler */
void
mlfqs_recent_cpu (struct thread *t)
{
if (t == idle_thread)
return;
t->recent_cpu = add_mixed(mult_fp(div_fp(mult_mixed(load_avg, 2), add_mixed(mult_mixed(load_avg, 2), 1)), t->recent_cpu), t->niceness);
}
load_avg ๊ฐ ๊ณ์ฐ
/** project1-Advanced Scheduler */
void
mlfqs_load_avg (void)
{
int ready_threads;
ready_threads = list_size(&ready_list);
if (thread_current() != idle_thread)
ready_threads++;
load_avg = add_fp(mult_fp(div_fp(int_to_fp(59), int_to_fp(60)), load_avg), mult_mixed(div_fp(int_to_fp(1), int_to_fp(60)), ready_threads));
}
recent_cpu ๊ฐ 1์ฆ๊ฐ
/** project1-Advanced Scheduler */
void
mlfqs_increment (void)
{
if (thread_current() == idle_thread)
return;
thread_current()->recent_cpu = add_mixed(thread_current()->recent_cpu, 1);
}
๋ชจ๋ thread์ recent_cpu์ priority๊ฐ ์ฌ๊ณ์ฐ
/** project1-Advanced Scheduler */
void
mlfqs_recalc_recent_cpu (void)
{
struct list_elem *e = list_begin(&all_list);
struct thread *t = NULL;
while (e != list_end(&all_list)) {
t = list_entry(e, struct thread, all_elem);
mlfqs_recent_cpu(t);
e = list_next(e);
}
}
/** project1-Advanced Scheduler */
void mlfqs_recalc_priority (void)
{
struct list_elem *e = list_begin(&all_list);
struct thread *t = NULL;
while (e != list_end(&all_list)) {
t = list_entry(e, struct thread, all_elem);
mlfqs_priority(t);
e = list_next(e);
}
}
- mlfqs ์ค์ผ์ค๋ฌ๋ฅผ ํ์ฑ ํ๋ฉด thread_mlfqs ๋ณ์๋ ture๋ก ์ค์ ๋๋ค.
- Advanced scheduler์์๋ ์ฐ์ ์์๋ฅผ ์์๋ก ๋ณ๊ฒฝํ ์ ์๋ค.
void
thread_set_priority (int new_priority) {
/** project1-Advanced Scheduler */
if (thread_mlfqs)
return;
/** project1-Priority Inversion Problem */
thread_current()->original_priority = new_priority;
ํ์ฌ thread์ nice๊ฐ์ nice๋ก ์ค์
void
thread_set_nice (int nice UNUSED) {
/* TODO: Your implementation goes here */
/** project1-Advanced Scheduler */
struct thread *t = thread_current();
enum intr_level old_level = intr_disable();
t->niceness = nice;
mlfqs_priority(t);
test_max_priority();
intr_set_level(old_level);
}
ํ์ฌ thread์ nice ๊ฐ ๋ฐํ
int
thread_get_nice (void) {
/* TODO: Your implementation goes here */
return 0;
/** project1-Advanced Scheduler */
struct thread *t = thread_current();
enum intr_level old_level = intr_disable();
int nice = t->niceness;
intr_set_level(old_level);
return nice;
}
load_avg์ 100์ ๊ณฑํด์ ๋ฐํ
int
thread_get_load_avg (void) {
/* TODO: Your implementation goes here */
return 0;
/** project1-Advanced Scheduler */
enum intr_level old_level = intr_disable();
int load_avg_val = fp_to_int_round(mult_mixed(load_avg, 100));
intr_set_level(old_level);
return load_avg_val;
}
recent_cpu์ 100์ ๊ณฑํด์ ๋ฐํ
int
thread_get_recent_cpu (void) {
/* TODO: Your implementation goes here */
return 0;
/** project1-Advanced Scheduler */
struct thread *t = thread_current();
enum intr_level old_level = intr_disable();
int recent_cpu = fp_to_int_round(mult_mixed(t->recent_cpu, 100));
intr_set_level(old_level);
return recent_cpu;
}
devices/timer.c
- 1์ด ๋ง๋ค load_avg, ๋ชจ๋ ์ค๋ ๋์ recent_cpu, priority ์ฌ๊ณ์ฐ
- 4tick ๋ง๋ค ํ์ฌ ์ค๋ ๋์ priority ์ฌ๊ณ์ฐ
static void
timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick ();
if (thread_mlfqs)
{
mlfqs_increment();
if (!(ticks % 4))
{
mlfqs_recalc_priority();
if (!(ticks % TIMER_FREQ))
{
mlfqs_load_avg();
mlfqs_recalc_recent_cpu();
}
}
}
/** project1-Alarm Clock */
if (get_next_tick_to_awake() <= ticks)
{
thread_awake(ticks);
}
}
threads/synch.c
mlfqs ์ค์ผ์ค๋ฌ ํ์ฑํ์ priority donation ๊ด๋ จ ์ฝ๋ ๋นํ์ฑํ
void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock));
/* project1-Priority Inversion Problem /
struct thread *t = thread_current();
if (lock->holder != NULL) {
t->wait_lock = lock;
list_push_back(&lock->holder->donations, &t->donation_elem);
donate_priority();
}
sema_down (&lock->semaphore);
/* project1-Priority Inversion Problem /
t->wait_lock = NULL;
lock->holder = t;
}
### lock_release() ํจ์ ์์
threads/synch.c
> mlfqs ์ค์ผ์ค๋ฌ ํ์ฑํ์ priority donation ๊ด๋ จ ์ฝ๋ ๋นํ์ฑํ
```c
void
lock_release (struct lock *lock) {
ASSERT (lock != NULL);
ASSERT (lock_held_by_current_thread (lock));
lock->holder = NULL;
/** project1-Priority Inversion Problem */
remove_with_lock(lock);
refresh_priority();
sema_up (&lock->semaphore);
}
threads/thread.c
์ค๋ ๋ ์ข ๋ฃ ์ all_list์์ ์ ๊ฑฐ
void
thread_exit (void) {
ASSERT (!intr_context ());
#ifdef USERPROG
process_exit ();
#endif
/** project1-Advanced Scheduler */
if (thread_mlfqs)
list_remove(&thread_current()->all_elem);
/* Just set our status to dying and schedule another process.
We will be destroyed during the call to schedule_tail(). */
intr_disable ();
do_schedule (THREAD_DYING);
NOT_REACHED ();
}
good ~ ๐ฎ