jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 구현 요구사항 간단 정리
  2. 구현 계획
  3. 구현 시작

구현 요구사항 간단 정리

thread_mlfqs
parse_options

이 true 일때 고급 스케줄러

thread_create 우선순위 인자 무시
thread_set_priority 역시 무시

thread_get_priority는 현재 우선순위 반환

4.4BSD 스케줄러 구현시
데이터 갱신은 일반 커널 스레드 실행 전에

우선순위 기부 없음

나이스 값
thread_get_nice nice값 반환
thread_set_nice nice값 재설정 후 우선순위 재계산 하고 최고 우선순위 아닐시 즉시 양보

우선순위 계산
-20 ~ 20 nice값 4틱마다 재계산

priority = PRI_MAX - (recent_cpu / 4) - (nice * 2)


recent_cpu
최근에 받은 cpu시간 측정 1틱마다 1증가하고
1초마다 다음 공식 계산

recent_cpu = (2 * load_avg) / (2 * load_avg + 1) * recent_cpu + nice


load_avg는 지난 1분간 실행 준비 스레드 평균개수
0에서 시작해 초당 1회 다음 공식으로 갱신

load_avg = (59/60) * load_avg + (1/60) * ready_threads

ready_threads는 실행 또는 준비 상태인 스레드 수 (idle 제외)



구현 계획

기존 코드와 고급 스케줄러 고를수 있게 설계

nice값을 비롯한 필요 숫자들을 위한 공식 함수 설계

구현 시작

일단 get_priorityset_priority를 손 볼 생각이다

if (thread_mlfqs)로 관리하려 한다

get은 솔직히 건드릴 게 없어 보여 스킵하겠다

생각해보니 그 이전에 준비 큐 만들어야 겠다
64개 준비 큐 있어야 한다는데

이걸 어캐 만드냐…

잘 모르겠으니 지금은 스킵하겠다

priority 관련 먼저 구현하면 되지 않을까 싶다

초단위 계산부터 넣어야한다

ticks % 100 이 0이어야 한다

pintos 기본값으로 초당 100틱 발생시키니 말이다
TIMER_FREQ 쓰란다 초당 몇틱인지 나타내는 매크로가 존재하니 하드코딩 괜히 하지 말고 말이다

thread_tick이 매 틱마다 호출되니 여기서 하면 된다

void
thread_tick (void) {
	struct thread *t = thread_current ();

	/* Update statistics. */
	if (t == idle_thread)
		idle_ticks++;
#ifdef USERPROG
	else if (t->pml4 != NULL)
		user_ticks++;
#endif
	else
		kernel_ticks++;

	/* Enforce preemption. */
	if (++thread_ticks >= TIME_SLICE)
		intr_yield_on_return ();
}

기본은 이렇게 생겼다

어떻게 코딩했고 뭘 넣었는지는 비밀로 하겠다

알아서 하도록


공식 구현하려면 일단

priority 구하는거 만들어야 하고

이거 만들려면 nice랑 recent_cpu 필요하다

recent_cpu 만드려면 load_avg가 필요하다

load_avg 만드려면 ready_threads가 필요하다

ready_threads 얻으려면…

1초마다 스레드 돌아 확인하면 된다! emoji2

그치만 그전에 recent_cpu 만져야 한다

공식 말고 기본적으로 매 틱마다 1 늘려줘야함 ㅇㅇ

idele_thread일 떄 뺴고는 현재 스레드 1씩 늘려주면 되니 간단하다

/* 틱 계산 */
if (t != idle_thread) {
    t->recent_cpu += 1;
}

이게 끝이다

이제 다음으로 가자

timer_ticks() 함수로 현재 틱 불러 올 수 있다

그리고 1초는 100틱이다

그렇다,
if ((timer_ticks() % 100) == 0)으로 1초마다 함수 돌릴 수 있다

그리고 100대신 4넣으면 4틱마다 하는 것도 해결 가능하다

이제 여기 안에 load_avg를 구하는 공식을 넣어주자

load_avg = (59/60) * load_avg + (1/60) * ready_threads

참고로 thread.h에 전역변수 int load_avg;로 선언하고
thread_init에 0으로 초기화하것도 넣어주고 오는 길이다

/* load avg */
int cur;
if (t != idle_thread) cur = 1; else cur = 0;
load_avg = FP_ADD(FP_MUL(FP_59_60, load_avg), FP_MUL(FP_1_60, (len(ready_list) + cur)));

t는 현재 스레드다 그리고 load_avg에 1더해주는 건 idle_thread가 아닐때만이라 저렇게 한거다

ready_list에는 현재 스레드 없으니까 실행중인 현제 스레드 포함해서 + 1
idle_thread는 늘 제외니까 idle_thread 돌아갈땐 + 0

그리고 나서는 recent_cpu에 대한 공식 재계산 해야한다
이번에는 현재 스레드 말고 idle_thread제외 전부 돌아야 하는데
이는 불가능하다

그러니까 구조체에 새로 리스트 하나 추가해줘야한다
이름 적당히 지어 원소 하나 추가해주고

관련해서 선언해주면 끝이다



할게 너무 많아 잠시 TIL 스탑하다가 왔다

이번에는 전역함수 안만들고 조금씩 추가하면서 했더니…

좀 코드가 많이 더럽고 길어져 어떻게 정리해야 될지 모르겠다;;

전부 통과하고 난 뒤 따로

코드 정리하거나 전역 함수등으로 간결하게 정리한 뒤에

새로 정리해보겠다

일단 흐름만 정리한 글 올리고 코드와 함께 정리 다시해보겠다

흐름은 간단한데 코드 개판으로 짜서 힘듬;; emoji