일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 백준 17608번
- 이분 탐색(Binary Search)
- 백준 2812번
- 백준 1948번
- 백준 2504번
- BFS
- 플로이드 워셜 알고리즘(Floyd-Warshall Algorithm)
- 분할 정복(Divide and Conquer)
- 위상 정렬(Topology Sort)
- DFS & BFS
- 알고리즘 개념
- 트리(Tree)
- DFS
- 백준 1707번
- 백준 10000번
- 백준 18352번
- 백준 2261번
- 큐(Queue)
- 이분 그래프(Bipartite Graph)
- 스택(Stack)
- 다익스트라 알고리즘(Dijkstra Algorithm)
- BFS(Breadth First Search)
- DFS(Depth First Search)
- 그리디 알고리즘(Greedy Algorithm)
- 동적 프로그래밍(Dynamic Programming)
- 그래프(Graph)
- 백준 2493번
- 백준 21606번
- 백준 9012번
- 위상 정렬(Topological Sort)
- Today
- Total
Always Be Wise
Project_3 : Virtual Memory - Swap In/Out(2) 본문
스와핑 시 운영체제는 방출할 페이지를 선택한다. 방출을 위해 선택 가능한 페이지는 anonymous page 혹은 file-backed page이다.
각 페이지 타입에 맞추어 스와핑이 이루어져야 한다. 우선, anonymous page 타입의 스와핑을 구현해보자.
Anonymous Page
anonymous page의 경우, 해당 페이지에 대한 backing store가 디스크에 존재하지 않는다.
다시 말해, 디스크로 스왑 아웃되었을 때, 이 페이지를 저장할 공간이 디스크 내에 없다는 의미이다.
따라서 디스크 내에 별도의 swap_disk 공간을 만들고, 해당 공간에 스왑 아웃된 anonymous page를 저장하도록 해야 한다.
또한, swap disk의 사용 가능한 영역과 사용 불가능한 영역을 관리할 자료구조, swap_table이 필요하다.
swap_table은 비트를 저장하는 연속된 메모리 공간 위의 배열 객체이다. 각각의 비트는 스왑 슬롯과 매칭 된다.
비트가 1이라는 말은 스왑 슬롯에 페이지가 저장되었다는 의미이다.
스왑 영역은 PGSIZE(4097 bytes, 4KB) 단위로 관리된다.
PGSIZE를 DISK_SECTOR_SIZE(512 bytes)로 나눈 SECTORS_PER_PAGE를 정의하여, swap_size 연산에 이용한다.
/* vm/anon.c */
/*--------------- PROJECT3: Virtual Memory ----------------*/
struct bitmap *swap_table;
const size_t SECTORS_PER_PAGE = PGSIZE / DISK_SECTOR_SIZE;
/*---------------------------------------------------------*/
이제 준비가 되었으니 anonymous page를 위한 스왑 영역을 생성하기 위해서 vm_anon_init( ) 함수를 수정하자.
함수 내부에서 disk_get( ), disk_size( ) 함수를 통해 swap_size( )를 구하고,
bitmap_create( ) 함수를 통해 해당 크기만큼swap_table을 만들어준다.
/* vm/anon.c */
void vm_anon_init (void) {
/* TODO: Set up the swap_disk. */
/*--------------- PROJECT3: Virtual Memory ----------------*/
swap_disk = disk_get(1, 1);
size_t swap_size = disk_size(swap_disk) / SECTORS_PER_PAGE;
swap_table = bitmap_create(swap_size);
/*---------------------------------------------------------*/
}
anon_initializer( ) 함수에서 anon_page에 대한 정보, swap_index를 -1로 변경한다.
/* vm/anon.c */
bool anon_initializer (struct page *page, enum vm_type type, void *kva) {
/*--------------- PROJECT3: Virtual Memory ----------------*/
struct uninit_page *uninit = &page->uninit;
memset(uninit, 0, sizeof(struct uninit_page));
/* Set up the handler */
page->operations = &anon_ops;
struct anon_page *anon_page = &page->anon;
anon_page->swap_index = -1;
return true;
/*---------------------------------------------------------*/
}
다음으로 메모리의 내용을 디스크로 복사하여 anonymous page를 swap_disk로 스왑하는 anon_swap_out( ) 함수를 구현하자.
우선, swap_table을 이용하여 사용 가능한 스왑 슬롯을 찾는다.
그 후, 해당 스왑 슬롯에 해당하는 디스크 영역에 가상 주소 공간의 데이터를 페이지의 시작 주소부터 디스크 섹터 크기로 잘라서 저장한다. 저장을 마친 다음에는 swap_table의 비트를 true로 변경하고, anon_page의 swap_index를스왑 슬롯 번호로 변경한다.
/* vm/vm.c */
/*--------------- PROJECT3: Virtual Memory ----------------*/
/* 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;
int page_no = bitmap_scan(swap_table, 0, 1, false);
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);
}
bitmap_set(swap_table, page_no, true);
pml4_clear_page(thread_current()->pml4, page->va);
anon_page->swap_index = page_no;
return true;
}
/*---------------------------------------------------------*/
이제 스왑 아웃된 페이지를 swap_disk에서 꺼낼 수 있도록 swap_in( ) 함수를 구현해보자.
우선, anon_page의 swap_index를 이용하여 스왑 슬롯에 해당하는 page_no를 찾는다.
이후, swap_table에서 해당 page_no를 사용하고 있는 지 확인하고, 사용하고 있다면 해당 스왑 영역의 데이터를 읽어서 kva에 써준다.
마지막으로 swap_table에 해당 page_no를 false로 변경한다.
/* vm/anon.c */
/*--------------- PROJECT3: Virtual Memory ----------------*/
static bool anon_swap_in (struct page *page, void *kva) {
struct anon_page *anon_page = &page->anon;
int page_no = anon_page->swap_index;
if (bitmap_test(swap_table, page_no) == false) {
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);
}
bitmap_set(swap_table, page_no, false);
return true;
}
/*---------------------------------------------------------*/
File-Mapped Page
file-backed page의 경우, 디스크에 backed file이 있으므로 스왑 아웃될 때 해당 파일에 저장하면 된다.
스왑 아웃되면 해당 페이지의 PTE의 present bit은 0이 되고, 해당 페이지에 프로세스가 접근 시 페이지 폴트가 발생한다.
페이지 폴트가 발생하면 디스크의 파일 데이터를 다시 물리 메모리에 스왑 인된다.
우선, file_backed_swap_out( ) 함수를 수정해보자. 여기서 중요한 것은 파일이 변경되었을 경우, 즉 더티 비트가 1로 변경되었다면
이를 파일에 옮겨 적어주고, 더티 비트를 다시 0으로 변경하는 과정이 필요하다는 것이다.
/* vm/file.c */
/*--------------- PROJECT3: Virtual Memory ----------------*/
/* Swap out the page by writeback contents to the file. */
static bool file_backed_swap_out (struct page *page) {
struct file_page *file_page UNUSED = &page->file;
if (page == NULL)
return false;
struct container* container = (struct container *)page->uninit.aux;
/* 수정된 페이지(더티 비트 1)는 파일에 업데이트 해 놓는다.
그리고 더티 비트를 0으로 만들어둔다. */
if (pml4_is_dirty(thread_current()->pml4, page->va)){
file_write_at(container->file, page->va,
container->page_read_bytes, container->offset);
pml4_set_dirty(thread_current()->pml4, page->va, 0);
}
/* present bit을 0으로 만든다. */
pml4_clear_page(thread_current()->pml4, page->va);
}
/*---------------------------------------------------------*/
file_backed_swap_in( )을 수정해보자. 우선, page의 정보를 받아와 container 형의 aux에 저장해준다.
aux에 저장된 정보를 바탕으로 file_seek ( ) 함수를 수행하여 파일을 찾고, 해당 파일을 file_read( ) 함수로 읽어 온다.
이때, page_read_bytes가 실제로 읽어오는 것과 다른지 확인한다. 그리고 읽어온 길이가 부족한 경우 0으로 초기화 한다.
/* vm/file.c */
/*--------------- PROJECT3: Virtual Memory ----------------*/
/* Swap in the page by read contents from the file. */
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 page_read_bytes = aux->page_read_bytes;
size_t page_zero_bytes = PGSIZE - page_read_bytes;
file_seek (file, offset);
if(file_read(file, kva, page_read_bytes) != (int)page_read_bytes) {
// palloc_free_page(kva);
return false;
}
memset(kva + page_read_bytes, 0, page_zero_bytes);
return true;
}
/*---------------------------------------------------------*/
'카이스트 정글 - 프로젝트 > Pintos' 카테고리의 다른 글
Project_4 : File System - Introduction (0) | 2022.01.29 |
---|---|
Project_3 : Virtual Memory - Weekly I Learned (0) | 2022.01.25 |
Project_3 : Virtual Memory - Swap In/Out(1) (0) | 2022.01.24 |
Project_3 : Virtual Memory - Memory Mapped Files(2) (0) | 2022.01.24 |
Project_3 : Virtual Memory - Memory Mapped Files(1) (0) | 2022.01.24 |