nice
,recent_cpu
thread 구조에 추가하기
struct thread {
...
//mlfqs
int nice;
int recent_cpu;
...
};
nice
,recent_cpu
초기화하기
static void init_thread (struct thread *t, const char *name, int priority) {
...
t->nice = 0;
t->recent_cpu = 0;
...
}
load_average
시스템이 얼마나 바쁜지 나타낸다.
load_avg = (59/60) load_avg + (1/60) ready_threads
load_avg선언
int load_avg;
전역 변수로 thread.c 상단에 선언한다.load_avg = 0;
`thread_init(void)에서 초기화 해준다.calculate_load_avg(void)
void calculate_load_avg(void)
{
int ready_threads = list_size(&ready_list);
if (thread_current() != idle_thread)
ready_threads++;
load_avg =add_fixed_point( multiply_fixed_point (divide_fixed_point_integer(convert_to_fixed_point(59), 60), load_avg),
multiply_fixed_point_integer (divide_fixed_point_integer(convert_to_fixed_point(1) , 60), ready_threads));
}
pintOS는 성능 향상을 위해 부동소수점연산을 지원하지 않기 때문에 직접 고정 소수점 연산을 해야한다.
매크로를 사용하기 위해서
#include "threads/fixed-point.h"를 추가해준다.
#define F (1 << 14) // 2^14 = 16384
#define convert_to_fixed_point(n) (n * F)
#define convert_to_integer_towards_zero(x) (x / F)
#define convert_to_integer_towards_nearest(x) (x >= 0 ? ((x + F / 2) / F) : ((x - F / 2) / F))
#define add_fixed_point(x, y) (x + y)
#define add_fixed_point_integer(x, n) (x + n * F)
#define subtract_fixed_point(x, y) (x - y)
#define subtract_fixed_point_integer(x, n) (x - n * F)
#define multiply_fixed_point(x, y) (((int64_t) x) * y / F)
#define multiply_fixed_point_integer(x, n) (x * n)
#define divide_fixed_point(x, y) (((int64_t) x) * F / y)
#define divide_fixed_point_integer(x, n) (x / n)
int thread_get_load_avg(void)
{
return convert_to_integer_towards_nearest(multiply_fixed_point_integer(load_avg, 100));
}
static void timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick ();
thread_wake_up (ticks);
if(thread_mlfqs){
// timer_ticks 는 10ms 마다 호출되므로 10ms 마다 load_avg를 업데이트
// 1초 마다 계산
if(timer_ticks()%TIMER_FREQ==0){
calculate_load_avg();
}
}
}
이렇게 하면
pass tests/threads/mlfqs/mlfqs-load-1
통과!!
recent_cpu계산하기
static struct list sleep_list;
추가list_init (&all_list);
struct list_elem allelem;
static void init_thread (struct thread *t, const char *name, int priority) {
...
t->nice = 0;
t->recent_cpu = 0;
if (strcmp(name, "idle"))
list_push_back(&all_list, &t->allelem);
...
}
DYING 예정인 스레드 all_list에서도 제거
static void schedule(void)
{
...
if (curr && curr->status == THREAD_DYING && curr != initial_thread)
{
ASSERT(curr != next);
list_push_back(&destruction_req, &curr->elem);
list_remove(&curr->a_elem);
}
...
}
static void timer_interrupt (struct intr_frame *args UNUSED)
에 코드 추가
static void timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick ();
thread_wake_up (ticks);
if(thread_mlfqs){
// timer_ticks 는 10ms 마다 호출되므로 10ms 마다 load_avg를 업데이트
// 1초 마다 계산
if(timer_ticks()%TIMER_FREQ==0){
calculate_load_avg();
calculate_recent_cpu();
}
recent_cpu_plus();
}
}
recent_cpu_plus();
, calculate_recent_cpu();
함수 구현
void calculate_recent_cpu(void)
{
//recent_cpu = (2*load_avg)/(2*load_avg + 1) * recent_cpu + nice;
struct list_elem *e;
struct thread *t;
for (e = list_begin(&all_list); e != list_end(&all_list); e = list_next(e))
{
t = list_entry(e, struct thread, allelem);
t->recent_cpu = multiply_fixed_point (divide_fixed_point (multiply_fixed_point_integer (load_avg, 2),
add_fixed_point_integer (multiply_fixed_point_integer (load_avg, 2), 1)), t->recent_cpu) + convert_to_fixed_point(t->nice);
t->priority = calculate_priority(t);
}
}
void recent_cpu_plus(void){
struct thread *t = thread_current();
if (t == idle_thread)
return;
t->recent_cpu = add_fixed_point_integer(t->recent_cpu, 1);
}
int thread_get_recent_cpu(void)
{
return convert_to_integer_towards_zero(multiply_fixed_point_integer(thread_current()->recent_cpu, 100));
}
현재 cpu사용량을 구하기 위해 nice 설정함수 구현
void thread_set_nice(int nice)
{
struct thread *t = thread_current();
t->nice = nice;
thread_set_priority(calculate_priority(t));
}
nice 변경시 우선순위 바뀔 수 있으니 바뀐 우선순위 설정해주기
구한 nice get
int thread_get_nice(void)
{
return thread_current()->nice;
}
바뀐 우선순위 계산하기
static void
timer_interrupt (struct intr_frame *args UNUSED) {
ticks++;
thread_tick (); // 실행 중인 프로세스의 CPU 사용량을 업데이트
thread_wakeup(ticks);
if(thread_mlfqs){
// timer_ticks 는 10ms 마다 호출되므로 10ms 마다 load_avg를 업데이트
// 1초 마다 계산
if(timer_ticks()%4 == 0){
recalculate_all_priority();
if(timer_ticks()%TIMER_FREQ==0){
calculate_load_avg();
calculate_recent_cpu();
}
}
recent_cpu_plus();
}
}
void recalculate_all_priority(void)
{
if(list_empty(&all_list))
return;
struct list_elem *e;
struct thread *t;
for (e = list_begin(&all_list); e != list_end(&all_list); e = list_next(e))
{
t = list_entry(e, struct thread, allelem);
t->priority = calculate_priority(t);
}
}
int calculate_priority(struct thread *t){
int temp = PRI_MAX - convert_to_integer_towards_nearest(divide_fixed_point(t->recent_cpu, convert_to_fixed_point(4))) - t->nice * 2;
if (temp > PRI_MAX)
temp = PRI_MAX;
else if (temp < PRI_MIN)
temp = PRI_MIN;
return temp;
}
void calculate_load_avg(void);
void calculate_recent_cpu(void);
void recalculate_all_priority(void);
int calculate_priority(struct thread *t);
header에 선언
void thread_wake_up(int64_t os_ticks)
{
if (list_empty(&sleep_list))
return;
struct thread *t, *curr;
enum intr_level old_level;
old_level = intr_disable();
while (!list_empty(&sleep_list))
{
t = list_entry(list_front(&sleep_list), struct thread, elem);
if (t->wake_up_tick > os_ticks)
break;
list_pop_front(&sleep_list);
list_insert_ordered(&ready_list, &t->elem, cmp_priority, NULL);
t->status = THREAD_READY;
}
// curr = thread_current();
// if (curr != idle_thread)
// {
// if (curr->priority < list_entry(list_front(&ready_list), struct thread, elem)->priority)
// {
// thread_yield();
// }
// }
intr_set_level(old_level);
} 로 주석처리
이렇게 하면 ALLPASS
새벽 4:30 정리 완료 ,,,,