09_pintos_VM_Swap_In/Out

신치우·2022년 12월 12일

data_structure_and_Pintos

목록 보기
33/36

메모리 스와핑은 물리 메모리의 활용을 극대화하기 위한 메모리 회수기법입니다.
메인 메모리의 프레임들이 모두 할당된다면, 시스템은 유저프로그램이 요청하는 메모리 할당 요청을 더 이상 처리할 수 없습니다.
이에 대한 한 가지 해결 방법은 현재 사용되지 않고 있는 메모리 프레임들을 디스크로 스왑 아웃 하는 것입니다.
이는 일부 메모리 자원들을 해제 시켜서 다른 어플리케이션들이 이 자원들을 사용할 수 있게 해 줍니다.
모든 스와핑 연산은 명시적으로 호출되는 것이 아니라 함수 포인터로 호출됩니다.
이 연산들은 struct page_operations file_ops의 멤버변수로서 각 페이지의 initializer에 대한 operation으로 등록되어있습니다.

swap out

  • 스와핑은 운영체제 의해서 이루어집니다. 메모리는 고갈되었는데 메모리 할당 요청을 받았다는 것을 운영체제가 감지하면 swap 디스크로 퇴거(evict)시킬 페이지를 골라냅니다. 그리고 메모리 프레임의 상태를 동일하게 디스크에 복사해둠
    --> 즉, RAM에 공간은 없는데 더 쓰기 요청이 들어오면 RAM에서 공간은 차지하지만 필요 없는 부분을 disk에 복사하고 RAM에서는 빼버림

swap in

  • 프로세스가 스왑 아웃된 페이지에 접근하려고 할때, 운영체제는 디스크에 복사해둔 내용을 그대로 다시 메모리에 가져옴으로서 페이지를 다시 복원
    --> 운영체제가 disk에 복사해놓은 data에 다시 접근하여 RAM에 올려 사용하려고 할때 swap in 을 함

이를 위해서 우리는 anon.c file을 수정할 것

vm_anon_init

이 기능에서는 스왑 디스크를 설정. 또한 스왑 디스크에서 사용 가능한 영역과 사용된 영역을 관리하기 위한 데이터 구조가 필요. 스왑 영역도 PGSIZE(4096바이트) 단위로 관리

const size_t SECTORS_PER_PAGE = PGSIZE / DISK_SECTOR_SIZE; // 256KB/512B -> 512
/* Initialize the data for anonymous pages */
// anonymous page를 위한 data를 초기화함
void
vm_anon_init (void) {
	/* TODO: Set up the swap_disk. */
	swap_disk = disk_get(1,1); // swap disk를 받아줌

	size_t swap_size = disk_size(swap_disk) / SECTORS_PER_PAGE; // 할당된 swap_disk의 사이즈를 512로 나눔
	swap_table = bitmap_create(swap_size); // swap_size에 맞는 bitmap을 만들어서 swap_table로 반환함
}

anon_initializer

swap을 지원하기 위해서 anon_page에 정보를 추가해줘야함

/* Initialize the file mapping */
bool
anon_initializer (struct page *page, enum vm_type type, void *kva) {
	/* Set up the handler */
	page->operations = &anon_ops; // page->operation 에 anonymous type을 넣어줌

	struct anon_page *anon_page = &page->anon; // page->anon 의 주소를 anon_page로 연결
}

anon_swap_in

disk 에서 memory로 anonymous_page를 swap해줌

/* Swap in the page by read contents from the swap disk. */
static bool
anon_swap_in (struct page *page, void *kva) {
	struct anon_page *anon_page = &page->anon; // anon_page에 page->anon 주소를 연결하고

	int page_no = anon_page->swap_index; // swap_index - 몇번째 swap data랑 바꿀것인지
	if(bitmap_test(swap_table, page_no) == false) // swap_talbe(전역변수) 에서 page_no를 bit로 찾을건데 없으면 false 있으면 해당 index를 return함
		return false;
	
	for ( int i = 0; i < SECTORS_PER_PAGE; i++){
		disk_read(swap_disk, page_no*SECTORS_PER_PAGE+ i, kva + DISK_SECTOR_SIZE* i);
		//swap dist에서 page_no*SECOTRS_PER_PAGE+ i sec를 kva+DISK_SECTOR_SIZE* i 만큼 읽음
	}

	bitmap_set(swap_table, page_no, false);
	// page_no을 index로 swap_table 안에 설정함


	return true;
}

anon_swap_out

content를 swap disk에 기록 후 page를 swap out 함

  • 먼저 스왑 테이블을 사용하여 디스크에서 사용 가능한 스왑 슬롯을 찾은 다음 데이터 페이지를 슬롯에 복사
  • 데이터의 위치는 페이지 구조체에 저장
  • 디스크에 사용 가능한 슬롯이 더 이상 없으면 커널 패닉이 발생할 수 있음
/* Swap out the page by writing contents to the swap disk. */
static bool
anon_swap_out (struct page *page) {
	struct anon_page *anon_page = &page->anon;

	/* for project 3 - start */
	int page_no = bitmap_scan(swap_table, 0, 1, false); // swap_table에 value로 설정된 애들중 첫번째 index를 반환
	if(page_no == BITMAP_ERROR)
		return false;

	for (int i = 0; i < SECTORS_PER_PAGE; i++){
		disk_write(swap_disk, page_no*SECTORS_PER_PAGE+ i, page->va + DISK_SECTOR_SIZE* i);
		//swap disk로 page_no*SECOTRS_PER_PAGE+ i sec를 kva+DISK_SECTOR_SIZE* i 만큼 씀
	}

	bitmap_set (swap_table, page_no, true);
	pml4_clear_page(thread_current() -> pml4, page->va);
	anon_page->swap_index = page_no;

	return true;
	/* for project 3 - end */
}

File-mapped page

file-backed 페이지의 내용은 파일에서 가져오므로 mmap된 파일을 백업 저장소로 사용해야 합니다. 즉, file-backed 페이지를 evict하면 해당 페이지가 매핑된 파일에 다시 기록됩니다.

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;

	if (page == NULL)
		return false;
	
	struct container *aux = (struct container *)page->uninit.aux;

	struct file *file = aux->file;
	off_t offset = aux->offset;
	size_t read_byte = aux->read_byte;

	file_seek(file, offset);

	if(file_read(file, kva, read_byte) != (int)read_byte)
		return false;
	
	memset(kva + read_byte, 0, PGSIZE - read_byte);

	return true;
}

file_backe_swap_out

  • content를 file에 다시 기록하여 swap out
  • 먼저 페이지가 dirty bit가 true인지 확인
  • dirty bit가 true가 아니라면 수정을 할 필요가 없음
  • 페이지를 교체한 후에는 페이지의 더티 비트를 0 으로 처리해야함
static bool
file_backed_swap_out (struct page *page) {
	struct file_page *file_page UNUSED = &page->file;

	if (page == NULL)
		return false;
	
	struct container *aux = (struct container *)page->uninit.aux;

	if(pml4_is_dirty(thread_current()->pml4, page->va)){
		file_write_at(aux->file, page->va, aux->read_byte, aux->offset);
		pml4_set_dirty(thread_current()->pml4, page->va, 0);
	}
	pml4_clear_page(thread_current()->pml4, page->va);
}
profile
https://shin8037.tistory.com/

0개의 댓글