PINTOS - Project 3 : Memory Swapping

JinJinJara·2023년 10월 21일
0

PINTOS

목록 보기
10/10

Swapping

메모리 스와핑 : 메모리 회수기법

  • 누가 ? : 운영체제 의해 이루어짐

  • 언제 ? : 유저 프로그램이 메모리 할당을 요청했을 때

  • 무엇을 ? : 사용되지 않는 메모리 프레임들을 디스크로 스왑 아웃!

  • 어떻게 ? : 운영체제가 감지하면 swap 디스크로 퇴거(evict)시킬 페이지를 골라서 디스크에 복사

    • 프로세스가 스왑 아웃된 페이지에 접근하려고 할때, 운영체제는 디스크에 복사해둔 내용을 그대로 다시 메모리에 가져옴으로서 페이지를 다시 복원
  • 왜 ? : 메인 메모리의 프레임들이 모두 할당되어, 시스템이 유저 프로그램의 메모리 할당 요청을 처리할 수 없기 때문에


Swap Disk

PINTOS 에서 Disk는 sector라는 최소단위로 data를 관리하며 sector의 크기는 512bytes 이다.
따라서 한개의 page를 저장하기 위해 한개의 swap slot은 8개의 sector를 사용한다.

Swap disk : swap out시 data를 임시 저장하기 위한 공간

* swap in 전까지 해당 data는 안전하게 유지

  • Sector : disk에서 data 를 관리하는 최소단위로, Pintos 에서는 512 bytes 이다.

  • Swap Slot : page를 저장하기 위해 4096 bytes 씩 나누어 관리할 수 있다.
    한개의 Page 를 위해, 8개의 Sector 필요

  • Swap Table : Swap slot의 할당여부를 관리 (1=할당됨 / 0=할당가능)


Anonymous page

파일로부터 매핑되지 않은 페이지로서 커널 로부터 할당 된 페이지이다.
디스크에 있던 프로그램이 실행될 때 스택 섹션은 익명 페이지로 메모리에 할당 된다.

  • 익명 페이지는 백업 저장소 가 없기 때문에, 스왑 디스크라는 임시 백업 저장소가 필요

vm_anon_init

스왑 디스크 설정 ( 사용가능/불가능 영역 관리 , 영역=PGSIZE 단위)

void
vm_anon_init (void) {
	// 1:1 - 스왑(교환) 영역
	swap_disk = disk_get(1,1);

	/* sectors / 8 = slot index */
	size_t bitcnt = disk_size(swap_disk)/SECTORS_IN_PAGE;
	swap_table = bitmap_create(bitcnt);
}

anon_initializer

스와핑을 지원

bool
anon_initializer (struct page *page, enum vm_type type, void *kva) {
	/* Set up the handler */
	page->operations = &anon_ops;

	struct anon_page *anon_page = &page->anon;
	anon_page->swap_index = -1;
	return true;
}

anon_swap_in

스왑 디스크 데이터 내용을 읽어서 익명 페이지를(디스크에서 메모리로) swap in

static bool
anon_swap_in (struct page *page, void *kva) {
	struct anon_page *anon_page = &page->anon;
		size_t sec_no = anon_page->swap_index;

	//  sec_no 그룹에 비트가 할당되어 있지 않다면 return (디스크에 write 되지 않았음)
    if (bitmap_test(swap_table, sec_no) == false) 
        return false;

	// swap disk 에 있는 ( 8배수 SECTOR 인덱스 + i ) 안의 정보를 (커널가상주소 + 512 * i) 로 읽기
    for (int i = 0; i < SECTORS_IN_PAGE; ++i) {
        disk_read(swap_disk, sec_no * SECTORS_IN_PAGE + i, kva + DISK_SECTOR_SIZE * i);
    }

    bitmap_set(swap_table, sec_no, false);
    
    return true;
}

anon_swap_out

Evit 될 페이지를 찾아 swap out!
1. 메모리에서 디스크로 내용을 복사
2. 익명 페이지를 스왑 디스크로 교체
3. backing store 할 공간이 없기 때문에 Swap disk 사용

  • 스왑 테이블 을 사용하여 디스크에서 사용 가능한 스왑 슬롯 찾기
    • 다음 데이터 페이지를 슬롯에 복사
    • 데이터의 위치는 페이지 구조체에 저장
    • 디스크에 사용 가능한 슬롯이 더 이상 없으면 커널 패닉이 발생할 수 있음
static bool
anon_swap_out (struct page *page) {
	struct anon_page *anon_page = &page->anon;
	// page = evict page 에 대한 정보를 swap disk 에 저장
	// Swap out : 유저 프로그램이 메모리 요청했지만, 다 차 있기 때문에 일부 페이지를 퇴출한다. 퇴출된 페이지는 메모리에서 삭제되고 디스크에 복사된다.

	/* 1. 페이지를 할당받을 수 있는 swap slot 하나를 찾기 */
	//	  Swap table 에서 0번째부터 false값을 갖는 비트를 1개 찾기 (false=할당가능)
	size_t sec_no = bitmap_scan(swap_table, 0, 1, false);

	if(sec_no == BITMAP_ERROR)
		return false;

	/* 2. 디스크에 페이지를 복사하기 */
	//    sector(512 bytes) * 8 = slot = 1 page
	// SEC_NO를 버퍼로 디스크에 기록 - 버퍼는 512 바이트를 포함해야 합니다
	for(int i = 0; i < SECTORS_IN_PAGE; i++){
		disk_write(swap_disk, sec_no * SECTORS_IN_PAGE + i
							, page->va + DISK_SECTOR_SIZE * i);
	}

	/* 3. swap slot의 비트를 true(할당됨)로 바꿔주기 */
    //    해당 페이지의 PTE에서 present bit을 0으로 바꿔준다.
    //    이제 프로세스가 이 페이지에 접근하면 page fault가 뜬다.    
    bitmap_set(swap_table, sec_no, true);
    pml4_clear_page(thread_current()->pml4, page->va);

    /* 페이지의 swap_index 값을 이 페이지가 저장된 swap slot의 번호로 써준다.*/
    anon_page->swap_index = sec_no;
    return true;
	
}

swap out : 메인 메모리 꽉 참 -> 퇴출할 페이지 고름 -> 디스크에 복사하기 -> 메모리에 삭제
swap in : 디스크에 복사해둔 내용으로 페이지 생성 -> 스왑테이블 업데이트 -> 메모리에 다시 로드


File-Mapped Page

파일 로부터 맵핑 된 페이지이다.
디스크에 있던 프로그램이 실행될 때 코드 섹션데이터 섹션 섹션은 파일기반 페이지로 load 된다.

  • file-backed 페이지의 내용은 파일에서 가져오므로 mmap된 파일을 백업 저장소로 사용

  • file-backed 페이지를 evict하면 해당 페이지가 매핑된 파일에 다시 기록

  • vm/anon.c에서 file_backed_init 및 file_initializer 수정

file_backed_initializer

bool
file_backed_initializer (struct page *page, enum vm_type type, void *kva) {
	/* Set up the handler */
	page->operations = &file_ops;
	
	struct uninit_page *uninit = &page->uninit;
	
	struct aux_file_info *f_info = (struct aux_file_info*)uninit->aux;
	page->file.file = f_info->file;
	page->file.read_bytes = f_info->read_bytes;
	page->file.pg_cnt = f_info->pg_cnt;
	page->file.ofs = f_info->ofs;


	return true;
}

file_backed_swap_in

파일에서 콘텐츠를 읽어 kva 페이지에서 swap in
파일 시스템과 동기화

static bool
file_backed_swap_in (struct page *page, void *kva) {
	struct file_page *file_page UNUSED = &page->file;
	/*파일에서 콘텐츠를 읽어 kva 페이지에서 swap in
	  파일 시스템과 동기화하기*/
	struct file *file = file_page->file;
	size_t read_bytes = file_page->read_bytes;
	off_t ofs = file_page->ofs;
	int pg_cnt = file_page->pg_cnt;
	

	file_read_at(file, kva, read_bytes, ofs);
	return true;
}

file_backed_swap_out

내용을 다시 파일에 기록하여 swap out

  1. 먼저 페이지가 dirty 인지 확인
    • 더럽지 않으면 파일의 내용을 수정할 필요가 없음
  1. 페이지를 교체한 후에는 페이지의 더티 비트 끄기
    • 이상 없으면 커널 패닉이 발생할 수 있음
static bool
file_backed_swap_out (struct page *page) {
	struct file_page *file_page UNUSED = &page->file;
	uint64_t curr_pml4 = thread_current()->pml4;
	
	struct file *file = file_page->file;
	size_t read_bytes = file_page->read_bytes;
	off_t ofs = file_page->ofs;
	
	// dirty 한지 확인
	if(pml4_is_dirty(curr_pml4, page->va)){

		file_write_at(file, page->frame->kva, read_bytes, ofs);
		pml4_set_dirty(curr_pml4, page->va, 0);
	}

	// page-frame 연결 끊기
	page->frame->page = NULL;
	page->frame = NULL;
	pml4_clear_page(curr_pml4, page->va);
	return true;

}
  • Evict : 퇴거의 대상 : 익명 페이지, 파일기반 페이지

0개의 댓글