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_priority랑 set_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