[Pintos-KAIST] Project 3 : Swap In / Out

์œ ์„ ยท2024๋…„ 5์›” 22์ผ
0

Pintos - KAIST

๋ชฉ๋ก ๋ณด๊ธฐ
15/16
post-thumbnail

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB ๋ ˆํฌ์ง€ํ† ๋ฆฌ
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB Swap In / Out ์ด์Šˆ

๊ณผ์ œ ์„ค๋ช…

Memory swapping์€ physical memory ์‚ฌ์šฉ์„ ๊ทน๋Œ€ํ™”ํ•˜๊ธฐ ์œ„ํ•œ memory ํšŒ์ˆ˜ ๊ธฐ๋ฒ•์ด๋‹ค. main memory์˜ frame์ด ํ• ๋‹น๋˜๋ฉด system์€ user program์˜ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์š”์ฒญ์„ ๋” ์ด์ƒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. ํ•œ ๊ฐ€์ง€ ํ•ด๊ฒฐ์ฑ…์€ ์ตœ๊ทผ์— ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” memory frame์„ disk๋กœ ๊ต์ฒดํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ผ๋ถ€ memory resource๊ฐ€ ํ™•๋ณด๋˜์–ด ๋‹ค๋ฅธ ์‘์šฉํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

๊ฐ€์ƒ ์ฃผ์†Œ ์•ˆ์˜ VPN์— Present Bit์„ ๋‘์–ด ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ ๋””์Šคํฌ๋กœ ์Šค์™‘๋˜์—ˆ๋Š”์ง€๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

swapping์€ OS ์— ์˜ํ•ด ์‹คํ–‰๋œ๋‹ค. system์—์„œ memory๊ฐ€ ๋ถ€์กฑํ•œ๋ฐ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉด ๊ตํ™˜ํ• (evict) page๋ฅผ ๊ณ ๋ฅธ๋‹ค. ๊ทธ ๋‹ค์Œ ๋ฉ”๋ชจ๋ฆฌ frame์˜ ์ •ํ™•ํ•œ ์ƒํƒœ๊ฐ€ disk์— ๋ณต์‚ฌ๋œ๋‹ค. ํ”„๋กœ์„ธ์Šค๊ฐ€ swap out๋œ page์— ์•ก์„ธ์Šคํ•˜๋ ค๊ณ  ํ•˜๋ฉด OS๋Š” ์ •ํ™•ํ•œ ๋‚ด์šฉ์„ memory์— ๋‹ค์‹œ ๊ฐ€์ ธ์™€์„œ page๋ฅผ ๋ณต๊ตฌํ•œ๋‹ค.


๊ตฌํ˜„

1. ์‚ฌ์ „ ์„ค์ • ~~

โœ”๏ธ ์ž๋ฃŒ๊ตฌ์กฐ, lock, ํ—ค๋”ํŒŒ์ผ ์„ ์–ธํ•˜๊ธฐ!

  • vm/anon.c
  • ๋””์Šคํฌ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ swap slot๊ณผ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ swap slot์„ ๊ด€๋ฆฌํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ธ Swap Table(=swap_bitmap)์„ ์„ ์–ธํ•ด์ค€๋‹ค.
  • ์ด ๋•Œ ์Šค์™‘ ํ…Œ์ด๋ธ”์€ ๋น„ํŠธ๋งต ๊ฐ์ฒด๋กœ ์„ ์–ธ๋œ๋‹ค.
  • ์Šค์™‘ ํ…Œ์ด๋ธ”์€ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ์— ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.
/** Project 3-Swap In/Out */
#include <bitmap.h>
#include "threads/vaddr.h"
#define SECTOR_PER_PAGE (PGSIZE / DISK_SECTOR_SIZE)
static struct bitmap *swap_bitmap;
static struct lock swap_lock;

๐Ÿ’ก SECTORS_PER_PAGE
ํ•œ ํŽ˜์ด์ง€์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๋””์Šคํฌ ์„นํ„ฐ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค. PGSIZE == 1<<12 == 4kb์ด๊ณ  DISK_SECTOR_SIZE == 512byte์ด๋‹ค.

2. vm_anon_init() ๊ตฌํ˜„

  • vm/anon.c
  • anon ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ ๋””์Šคํฌ ๋‚ด ์Šค์™‘ ์˜์—ญ์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • ๋””์Šคํฌ ๋‚ด์— ์Šค์™‘ ์˜์—ญ์„ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ์ด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์Šค์™‘ ํ…Œ์ด๋ธ”๋„ ๋งŒ๋“ค์–ด์ค€๋‹ค.
  • swap_size๋Š” ์Šค์™‘ ๋””์Šคํฌ ์•ˆ์—์„œ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ์Šค์™‘ ์Šฌ๋กฏ์˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
void
vm_anon_init (void) {
	/** Project 3-Swap In/Out */
	swap_disk = disk_get(1, 1);
	swap_bitmap = bitmap_create(disk_size(swap_disk) / SECTOR_PER_PAGE);
	lock_init(&swap_lock);
}

3. anon_page ์ž๋ฃŒ๊ตฌ์กฐ ์ˆ˜์ •

  • include/vm/anon.h
struct anon_page {
    /** Project 3-Swap In/Out */
    size_t page_no;
};

4. anon_initializer() ๊ตฌํ˜„

  • vm/anon.c
  • page struct ์•ˆ์˜ Union ์˜์—ญ์€ ํ˜„์žฌ uninit page์ด๋‹ค.
  • anon page๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‘ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด์ค€๋‹ค.
  • ์ด์ œ ํ•ด๋‹น ํŽ˜์ด์ง€๋Š” anon์ด๋ฏ€๋กœ operations๋„ anon์œผ๋กœ ์ง€์ •ํ•œ๋‹ค.
bool
anon_initializer (struct page *page, enum vm_type type, void *kva) {
	/** Project 3-Swap In/Out */
	struct uninit_page *uninit = &page->uninit;
	memset(uninit, 0, sizeof(struct uninit_page));
	page->operations = &anon_ops;
	
	struct anon_page *anon_page = &page->anon;
	anon_page->page_no = BITMAP_ERROR;
	return true;
}

5. anon_swap_out() ๊ตฌํ˜„

  • vm/anon.c
  • ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ์˜ ์Šค์™‘ ํ…Œ์ด๋ธ”์—์„œ ๋น„ํŠธ๊ฐ€ false์ธ ์Šค์™‘ ์Šฌ๋กฏ์„ ์ฐพ๋Š”๋‹ค. ๋น„ํŠธ๊ฐ€ false๋ผ๋Š” ๋ง์€ ํ•ด๋‹น ์Šค์™‘ ์Šฌ๋กฏ์— swap out๋œ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.
  • ํ•ด๋‹น ์Šค์™‘ ์Šฌ๋กฏ์— ํ•ด๋‹นํ•˜๋Š” ๋””์Šคํฌ์˜ ์˜์—ญ์— ๊ฐ€์ƒ ์ฃผ์†Œ ๊ณต๊ฐ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์ฃผ์†Œ๋ถ€ํ„ฐ ๋””์Šคํฌ ์„นํ„ฐ ํฌ๊ธฐ๋กœ ์ž˜๋ผ์„œ ์ €์žฅํ•œ๋‹ค.
  • ํ•ด๋‹น ์Šค์™‘ ์Šฌ๋กฏ์— ๋Œ€์‘๋˜๋Š” ์Šค์™‘ ํ…Œ์ด๋ธ”์˜ ๋น„ํŠธ๋ฅผ TRUE๋กœ ๋ฐ”๊ฟ”์ฃผ๊ณ , anon ํŽ˜์ด์ง€์˜ page_no์— ์Šค์™‘ ์Šฌ๋กฏ ๋ฒˆํ˜ธ๋ฅผ ์ €์žฅํ•ด์„œ ์ด ํŽ˜์ด์ง€๊ฐ€ ๋””์Šคํฌ์˜ ์Šค์™‘ ์˜์—ญ ์ค‘ ์–ด๋””์— swap ๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
static bool
anon_swap_out (struct page *page) {
	struct anon_page *anon_page = &page->anon;
	/** Project 3-Swap In/Out */
	lock_acquire(&swap_lock);
	size_t page_no = bitmap_scan_and_flip(swap_bitmap, 0, 1, false);

	if (page_no == BITMAP_ERROR){
		lock_release(&swap_lock);
		return false;
	}

	for (size_t i = 0; i < SECTOR_PER_PAGE; i++)
		disk_write(swap_disk, (page_no * SECTOR_PER_PAGE) + i, page->va + (i * DISK_SECTOR_SIZE));
	anon_page->page_no = page_no;
	page->frame->page = NULL;
	page->frame = NULL;
	pml4_clear_page(thread_current()->pml4, page->va);
	lock_release(&swap_lock);
}

6. anon_swap_in() ๊ตฌํ˜„

  • vm/anon.c
  • SWAP OUT๋œ ํŽ˜์ด์ง€์— ์ €์žฅ๋œ swap_index ๊ฐ’์œผ๋กœ ์Šค์™‘ ์Šฌ๋กฏ์„ ์ฐพ์•„ ํ•ด๋‹น ์Šฌ๋กฏ์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ํŽ˜์ด์ง€๋กœ ์›๋ณต์‹œํ‚จ๋‹ค.
static bool
anon_swap_in (struct page *page, void *kva) {
	struct anon_page *anon_page = &page->anon;
	/** Project 3-Swap In/Out */
	lock_acquire(&swap_lock);
	if (anon_page->page_no == BITMAP_ERROR){
		lock_release(&swap_lock);	
		return false;
	}


	if (!bitmap_test(swap_bitmap, anon_page->page_no)){
		lock_release(&swap_lock);	
		return false;
	}

	for (size_t i = 0; i < SECTOR_PER_PAGE; i++)
		disk_read(swap_disk, (anon_page->page_no * SECTOR_PER_PAGE) + i, kva + (i * DISK_SECTOR_SIZE));

	bitmap_set(swap_bitmap, anon_page->page_no, false);

	lock_release(&swap_lock);
	anon_page->page_no = BITMAP_ERROR;

	return true;
}

7. anon_destroy() ๊ตฌํ˜„

  • vm/anon.c
static void
anon_destroy (struct page *page) {
	struct anon_page *anon_page = &page->anon;
	/** Project 3-Swap In/Out */
    if (anon_page->page_no != BITMAP_ERROR)
        bitmap_reset(swap_bitmap, anon_page->page_no);

    if (page->frame) {
		lock_acquire(&swap_lock);
        list_remove(&page->frame->frame_elem);
		lock_release(&swap_lock);
        page->frame->page = NULL;
        free(page->frame);
        page->frame = NULL;
    }
}

8. file_backed_swap_out() ๊ตฌํ˜„

  • vm/file.c
  • swap out ์‹œํ‚ค๋ ค๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฉด ์•ˆ๋˜๋ฏ€๋กœ ๊ฒ€์‚ฌํ•ด์ค€๋‹ค.
  • aux์— ์ปจํ…Œ์ด๋„ˆ ๊ตฌ์กฐ์ฒด๋ฅผ ์ž…๋ ฅํ•˜๊ณ  dirty bit๋ฅผ ํ†ตํ•ด ์ˆ˜์ •์ด ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์ˆ˜์ •๋˜์—ˆ๋‹ค๋ฉด ํŒŒ์ผ์— ์ˆ˜์ •๋œ ๋‚ด์šฉ์„ ๊ธฐ์ž…ํ•˜๊ณ  dirty bit๋ฅผ 0์œผ๋กœ ๊ฐฑ์‹ ์‹œ์ผœ์ค€๋‹ค.
  • ๊ทธ ํ›„ pml4์˜ present bit๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ page fault๊ฐ€ ๋ฐœ์ƒํ•˜๋„๋ก ํ•œ๋‹ค.
static bool
file_backed_swap_out (struct page *page) {
	struct file_page *file_page UNUSED = &page->file;
	/** Project 3-Swap In/Out */
	struct frame *frame = page->frame;

	if (pml4_is_dirty(thread_current()->pml4, page->va))
	{
		file_write_at(file_page->file, page->frame->kva, file_page->page_read_bytes, file_page->offset);
		pml4_set_dirty(thread_current()->pml4, page->va, false);
	}
	page->frame->page = NULL;
	page->frame = NULL;
	pml4_clear_page(thread_current()->pml4, page->va);
	return true;
}

9. file_backed_swap_in() ๊ตฌํ˜„

  • vm/file.c
  • ํŒŒ์ผ๋กœ ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด ๋ฉ”๋ชจ๋ฆฌ๋กœ ์˜ฌ๋ฆฐ๋‹ค.
  • lazy_load_segment()์™€ ์œ ์‚ฌํ•˜๋‹ค.
static bool
file_backed_swap_in (struct page *page, void *kva) {
	struct file_page *file_page UNUSED = &page->file;
	/** Project 3-Swap In/Out */
	int read = file_read_at(file_page->file, page->frame->kva, file_page->page_read_bytes, file_page->offset);
	memset(page->frame->kva + read, 0, PGSIZE - read);
	return true;
}

10. vm_get_victim() ๊ตฌํ˜„

10-1. vm.c lock ์ถ”๊ฐ€ ๋ฐ ์ดˆ๊ธฐํ™”

  • vm/vm.c
/** Project 3-Swap In/Out */
struct lock frame_lock;
void
vm_init (void) {
	vm_anon_init ();
	vm_file_init ();
#ifdef EFILESYS  /* For project 4 */
	pagecache_init ();
#endif
	register_inspect_intr ();
	/* DO NOT MODIFY UPPER LINES. */

	/** Project 3-Memory Management */
	list_init(&frame_table);
	
	/** Project 3-Swap In/Out */
	lock_init(&frame_lock);
}

10-2. next list_elem ์„ ์–ธ

  • vm/vm.c
/** Project 3-Swap In/Out */
struct lock frame_lock;
struct list_elem *next = NULL;

10-3. vm_get_victim() ๊ตฌํ˜„

  • vm/vm.c
static struct frame *
vm_get_victim (void) {
	struct frame *victim = NULL;
	/** Project 3-Swap In/Out */
	lock_acquire(&frame_lock);
	for (next = list_begin(&frame_table); next != list_end(&frame_table); next = list_next(next))
	{
		victim = list_entry(next, struct frame, frame_elem);
		if (pml4_is_accessed(thread_current()->pml4, victim->page->va))
			pml4_set_accessed(thread_current()->pml4, victim->page->va, false);
		else{
			lock_release(&frame_lock);
			return victim;
		}
	}
	lock_release(&frame_lock);
	return victim;
}

11. vm_evict_frame() ๊ตฌํ˜„

  • vm/vm.c
static struct frame *
vm_evict_frame (void) {
	/** Project 3-Swap In/Out */
	struct frame *victim = vm_get_victim ();
	if (victim->page)
		swap_out(victim->page);
	return victim;
}

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

pass tests/userprog/args-none
pass tests/userprog/args-single
pass tests/userprog/args-multiple
pass tests/userprog/args-many
pass tests/userprog/args-dbl-space
pass tests/userprog/halt
pass tests/userprog/exit
pass tests/userprog/create-normal
pass tests/userprog/create-empty
pass tests/userprog/create-null
pass tests/userprog/create-bad-ptr
pass tests/userprog/create-long
pass tests/userprog/create-exists
pass tests/userprog/create-bound
pass tests/userprog/open-normal
pass tests/userprog/open-missing
pass tests/userprog/open-boundary
pass tests/userprog/open-empty
pass tests/userprog/open-null
pass tests/userprog/open-bad-ptr
pass tests/userprog/open-twice
pass tests/userprog/close-normal
pass tests/userprog/close-twice
pass tests/userprog/close-bad-fd
pass tests/userprog/read-normal
pass tests/userprog/read-bad-ptr
pass tests/userprog/read-boundary
pass tests/userprog/read-zero
pass tests/userprog/read-stdout
pass tests/userprog/read-bad-fd
pass tests/userprog/write-normal
pass tests/userprog/write-bad-ptr
pass tests/userprog/write-boundary
pass tests/userprog/write-zero
pass tests/userprog/write-stdin
pass tests/userprog/write-bad-fd
pass tests/userprog/fork-once
pass tests/userprog/fork-multiple
pass tests/userprog/fork-recursive
pass tests/userprog/fork-read
pass tests/userprog/fork-close
pass tests/userprog/fork-boundary
pass tests/userprog/exec-once
pass tests/userprog/exec-arg
pass tests/userprog/exec-boundary
pass tests/userprog/exec-missing
pass tests/userprog/exec-bad-ptr
pass tests/userprog/exec-read
pass tests/userprog/wait-simple
pass tests/userprog/wait-twice
pass tests/userprog/wait-killed
pass tests/userprog/wait-bad-pid
pass tests/userprog/multi-recurse
pass tests/userprog/multi-child-fd
pass tests/userprog/rox-simple
pass tests/userprog/rox-child
pass tests/userprog/rox-multichild
pass tests/userprog/bad-read
pass tests/userprog/bad-write
pass tests/userprog/bad-read2
pass tests/userprog/bad-write2
pass tests/userprog/bad-jump
pass tests/userprog/bad-jump2
pass tests/vm/pt-grow-stack
pass tests/vm/pt-grow-bad
pass tests/vm/pt-big-stk-obj
pass tests/vm/pt-bad-addr
pass tests/vm/pt-bad-read
pass tests/vm/pt-write-code
pass tests/vm/pt-write-code2
pass tests/vm/pt-grow-stk-sc
pass tests/vm/page-linear
pass tests/vm/page-parallel
pass tests/vm/page-merge-seq
pass tests/vm/page-merge-par
pass tests/vm/page-merge-stk
pass tests/vm/page-merge-mm
pass tests/vm/page-shuffle
pass tests/vm/mmap-read
pass tests/vm/mmap-close
pass tests/vm/mmap-unmap
pass tests/vm/mmap-overlap
pass tests/vm/mmap-twice
pass tests/vm/mmap-write
pass tests/vm/mmap-ro
pass tests/vm/mmap-exit
pass tests/vm/mmap-shuffle
pass tests/vm/mmap-bad-fd
pass tests/vm/mmap-clean
pass tests/vm/mmap-inherit
pass tests/vm/mmap-misalign
pass tests/vm/mmap-null
pass tests/vm/mmap-over-code
pass tests/vm/mmap-over-data
pass tests/vm/mmap-over-stk
pass tests/vm/mmap-remove
pass tests/vm/mmap-zero
pass tests/vm/mmap-bad-fd2
pass tests/vm/mmap-bad-fd3
pass tests/vm/mmap-zero-len
pass tests/vm/mmap-off
pass tests/vm/mmap-bad-off
pass tests/vm/mmap-kernel
pass tests/vm/lazy-file
pass tests/vm/lazy-anon
pass tests/vm/swap-file
pass tests/vm/swap-anon
pass tests/vm/swap-iter
pass tests/vm/swap-fork
pass tests/filesys/base/lg-create
pass tests/filesys/base/lg-full
pass tests/filesys/base/lg-random
pass tests/filesys/base/lg-seq-block
pass tests/filesys/base/lg-seq-random
pass tests/filesys/base/sm-create
pass tests/filesys/base/sm-full
pass tests/filesys/base/sm-random
pass tests/filesys/base/sm-seq-block
pass tests/filesys/base/sm-seq-random
pass tests/filesys/base/syn-read
pass tests/filesys/base/syn-remove
pass tests/filesys/base/syn-write
pass tests/threads/alarm-single
pass tests/threads/alarm-multiple
pass tests/threads/alarm-simultaneous
pass tests/threads/alarm-priority
pass tests/threads/alarm-zero
pass tests/threads/alarm-negative
pass tests/threads/priority-change
pass tests/threads/priority-donate-one
pass tests/threads/priority-donate-multiple
pass tests/threads/priority-donate-multiple2
pass tests/threads/priority-donate-nest
pass tests/threads/priority-donate-sema
pass tests/threads/priority-donate-lower
pass tests/threads/priority-fifo
pass tests/threads/priority-preempt
pass tests/threads/priority-sema
pass tests/threads/priority-condvar
pass tests/threads/priority-donate-chain
FAIL tests/vm/cow/cow-simple
1 of 141 tests failed.

ec2 ํ™˜๊ฒฝ์—์„œ swap-fork๊ฐ€ FAILํ•˜์˜€์ง€๋งŒ, WSL ํ™˜๊ฒฝ์—์„œ passํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•จ.

profile
Sunny Day!

0๊ฐœ์˜ ๋Œ“๊ธ€