[Pintos-KAIST] Project 3 : Memory Management

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

Pintos - KAIST

๋ชฉ๋ก ๋ณด๊ธฐ
11/16

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB ๋ ˆํฌ์ง€ํ† ๋ฆฌ
๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป GITHUB Extend File Descriptor ์ด์Šˆ

ํ”„๋กœ์ ํŠธ3 ์ง„์ž… ์ „ ์ฃผ์˜์‚ฌํ•ญ ๋ฐ ์‚ฌ์ „ ์„ค์ •

1๏ธโƒฃ ๋‘๋ฒˆ์งธ ๊ณผ์ œ์ธ Anonymous Page๋ฅผ ์™„์„ฑํ•˜๊ธฐ ์ „๊นŒ์ง€ VM ํ…Œ์ŠคํŠธ ์ง„ํ–‰์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค. (threads๋Š” ๋˜์–ด์•ผํ•จ)
2๏ธโƒฃ .vscode/c_cpp_properties.json defindes์— VM ์ถ”๊ฐ€

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "USERPROG",
                "VM"
            ],
            "cStandard": "c17",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "linux-gcc-x64"
        }
    ],
    "version": 4
}

์ฝ”๋ฐ”์ฝ” (์ฝ”๋“œ ๋ฐ”์ด ์ฝ”๋“œ... ๋ณธ์ธ ์ฝ”๋“œ์— ํ•ด๋‹น ์•ˆ๋˜๋Š”๊ฑธ์ˆ˜๋„ ์žˆ์Œ)
3๏ธโƒฃ include/threads/thread.h #define USERPROG ์‚ญ์ œ

4๏ธโƒฃ threads/thread.c #ifdef USERPROG ์ถ”๊ฐ€


๊ณผ์ œ ์„ค๋ช…

ํ˜„์žฌ ํ•€ํ† ์Šค์—์„œ๋Š” ๋ ˆ๋ฒจ 4 ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”(pml4)์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ์™€ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ ๊ฐ„์˜ ๋งคํ•‘ ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ์ถฉ๋ถ„ํ•˜์ง€ ์•Š๋‹ค. Supplemental Page Table์„ ๊ตฌํ˜„ํ•ด ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ ์ธ ์ •๋ณด๋“ค์„ ์ €์žฅํ•˜๊ฒŒ ๋˜๋ฉด Page Fault์™€ Resource Management๋ฅผ ์ˆ˜์›”ํ•˜๊ฒŒ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ก Supplemental Page Table

supplemental page table์€ ๊ธฐ์กด์˜ page table์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ๊ฒƒ์ด๋‹ค.

์—ญํ• 

ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

  • ํŽ˜์ด์ง€ ํดํŠธ ์‹œ ์ปค๋„์ด ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฐ€์ƒ ํŽ˜์ด์ง€๋ฅผ ์กฐํšŒํ•˜์—ฌ ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š”์ง€ ํ™•์ธ
  • ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ์ปค๋„์ด ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•˜์—ฌ ์–ด๋–ค ๋ฆฌ์†Œ์Šค๋ฅผ free์‹œํ‚ฌ ๊ฒƒ์ธ์ง€ ๊ฒฐ์ •

struct supplemental_page_table ๊ตฌํ˜„

๋จผ์ € ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์˜ ๊ตฌ์กฐ์ฒด struct supplemental_page_table์„ ๊ตฌํ˜„ํ•œ๋‹ค. ๊ทธ ํ›„์— ์ถ”๊ฐ€ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์ฒด์— ๊ด€๊ณ„๋œ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

Supplemental page table์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ์‹์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ฐฐ์—ด์ด๋‚˜, ๋น„ํŠธ๋งต, ํ•ด์‹œ ํ…Œ์ด๋ธ”๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. hash table๋กœ ๊ตฌํ˜„ํ•˜์ž.

๐Ÿ’ก frame table

frame table์€ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์˜ ๊ฐ ํ”„๋ ˆ์ž„์˜ ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.

์—ญํ• 

Frame table์€ frame entry์˜ ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌ์„ฑ๋˜๋Š”๋ฐ,
๊ฐ ์—”ํŠธ๋ฆฌ๋Š” ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ํ”„๋ ˆ์ž„ ํ…Œ์ด๋ธ”๋กœ ์ธํ•ด eviction ์ •์ฑ…, ์ฆ‰ SWAP OUT/IN์„ ์œ„ํ•œ ํ”„๋ ˆ์ž„ ๊ต์ฒด ์ •์ฑ…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

struct frame_table ๊ตฌํ˜„

  • ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋นˆ ํ”„๋ ˆ์ž„๋“ค์˜ ์ง‘ํ•ฉ
  • frame_table์€ ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.
  • frame_table์€ ์ „์—ญ์ ์œผ๋กœ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

๊ตฌํ˜„

Supplemental Page Table

1. hash, hash_elem ๊ตฌ์กฐ์ฒด ์ถ”๊ฐ€

  • include/vm/vm.h
1-1. hash.h include
#define VM_VM_H
#include <stdbool.h>
#include "threads/palloc.h"
#include <hash.h> /** Project 3-Memory Management */
...
1-2. spt_hash ์ถ”๊ฐ€
  • supplemental_page_table์— hash ๊ตฌ์กฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
struct supplemental_page_table {
	 struct hash spt_hash; /** Project 3-Memory Management */
};
1-3. hash_elem ์ถ”๊ฐ€
  • page ๊ตฌ์กฐ์ฒด์— hash_elem์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
struct page {
	const struct page_operations *operations;
	void *va;              /* Address in terms of user space */
	struct frame *frame;   /* Back reference for frame */

	/* Your implementation */

	/* Per-type data are binded into the union.
	 * Each function automatically detects the current union */
	union {
		struct uninit_page uninit;
		struct anon_page anon;
		struct file_page file;
#ifdef EFILESYS
		struct page_cache page_cache;
#endif
	};
	/** Project 3-Memory Management */
	struct hash_elem hash_elem;
};

2. supplemental_page_table_init() ๊ตฌํ˜„

  • vm/vm.c
  • supplementary page table์„ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  • hash table์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ์œผ๋ฏ€๋กœ hash_init์„ ์‚ฌ์šฉํ•˜์—ฌ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.
  • hash_init์—์„œ ํ•„์š”ํ•œ page_hash์™€ page_less๋Š” 3๋ฒˆ๊ณผ 4๋ฒˆ์— ์„ค๋ช…๋˜์–ด ์žˆ๋‹ค.
void
supplemental_page_table_init (struct supplemental_page_table *spt UNUSED) {
	/** Project 3-Memory Management */
	hash_init(spt, page_hash, page_less, NULL);
}

3. page_hash() ๊ตฌํ˜„

  • spt์— ๋„ฃ์„ ์ธ๋ฑ์Šค๋ฅผ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ๋Œ๋ ค์„œ ๋„์ถœํ•œ๋‹ค.
  • hash table์ด hash elem์„ ์›์†Œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ํŽ˜์ด์ง€ ์ž์ฒด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  • ์ธ๋ฑ์Šค๋ฅผ ๋ฆฌํ„ดํ•ด์•ผํ•˜๋ฏ€๋กœ hash_bytes๋กœ ๋ฆฌํ„ดํ•œ๋‹ค.
3-1. ์„ ์–ธ
  • include/vm/vm.h
/** Project 3-Memory Management */
uint64_t page_hash(const struct hash_elem *e, void *aux);
3-2. ๊ตฌํ˜„
  • vm/vm.c
/** Project 3-Memory Management */
uint64_t 
page_hash(const struct hash_elem *e, void *aux)
{
	struct page *page = hash_entry(e, struct page, hash_elem);
	return hash_bytes(page->va, sizeof *page->va);
}

4. page_less() ๊ตฌํ˜„

  • ์ฒด์ด๋‹ ๋ฐฉ์‹์˜ spt๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜์ด๋‹ค.
  • ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋ฒ„ํ‚ท ๋‚ด์˜ ๋‘ ํŽ˜์ด์ง€์˜ ์ฃผ์†Œ๊ฐ’์„ ๋น„๊ตํ•œ๋‹ค.
4-1. ์„ ์–ธ
  • include/vm/vm.h
/** Project 3-Memory Management */
uint64_t page_hash(const struct hash_elem *e, void *aux);
bool page_less(const struct hash_elem *a, const struct hash_elem *b, void *aux);
4-2. ๊ตฌํ˜„
  • vm/vm.c
/** Project 3-Memory Management */
bool 
page_less(const struct hash_elem *a, const struct hash_elem *b, void *aux)
{
	struct page *page_a = hash_entry(a, struct page, hash_elem);
	struct page *page_b = hash_entry(b, struct page, hash_elem);

	return page_a->va < page_b->va;
}

5. spt_find_page() ๊ตฌํ˜„

  • vm/vm.c
  • supplementary page table์—์„œ va์— ํ•ด๋‹นํ•˜๋Š” ๊ตฌ์กฐ์ฒด ํŽ˜์ด์ง€๋ฅผ ์ฐพ์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
struct page *
spt_find_page (struct supplemental_page_table *spt UNUSED, void *va UNUSED) {

	/** Project 3-Memory Management */
	struct page *page = (struct page *)malloc(sizeof(struct page));     
    page->va = pg_round_down(va);                                       
    struct hash_elem *e = hash_find(&spt->spt_hash, &page->hash_elem);  
    free(page);                                                         

    return e != NULL ? hash_entry(e, struct page, hash_elem) : NULL;
}

6. spt_insert_page() ๊ตฌํ˜„

  • vm/vm.c
  • supplementary page table์— struct page๋ฅผ ์‚ฝ์ž…ํ•œ๋‹ค.
  • ๊ฐ€์ƒ ์ฃผ์†Œ๊ฐ€ ์ด๋ฏธ supplementary page table์— ์กด์žฌํ•˜๋ฉด ์‚ฝ์ž…ํ•˜์ง€ ์•Š๊ณ , ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์‚ฝ์ž…ํ•œ๋‹ค.
bool
spt_insert_page (struct supplemental_page_table *spt UNUSED,
		struct page *page UNUSED) {
	/** Project 3-Memory Management */
	return hash_insert(&spt->spt_hash, &page->hash_elem) ? false : true;
}

Frame Management

7. frame_table ๊ตฌ์กฐ์ฒด ์ถ”๊ฐ€

7-1. frame_table ์ถ”๊ฐ€ ๋ฐ ์ดˆ๊ธฐํ™”
  • vm/vm.c
/* vm.c: Generic interface for virtual memory objects. */

#include "threads/malloc.h"
#include "vm/vm.h"
#include "vm/inspect.h"

/** Project 3-Memory Management */
static struct list frame_table; 

/* Initializes the virtual memory subsystem by invoking each subsystem's
 * intialize codes. */
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);
}
7-2. frame_elem ์ถ”๊ฐ€
  • include/vm/vm.h
struct frame {
	void *kva;
	struct page *page;
	/** Project 3-Memory Management */
	struct list_elem frame_elem; 
};

8. vm_get_frame() ๊ตฌํ˜„

  • vm/vm.c
  • palloc_get_page ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉ์ž ํ’€์—์„œ ์ƒˆ๋กœ์šด physical page(frame)๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.
  • ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ page๊ฐ€ ์—†๋‹ค๋ฉด swap out์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
static struct frame *
vm_get_frame (void) {
	struct frame *frame = NULL;
	/* TODO: Fill this function. */

	/** Project 3-Memory Management */
	struct frame *frame = (struct frame *)malloc(sizeof(struct frame));
	ASSERT (frame != NULL);

	frame->kva = palloc_get_page(PAL_USER | PAL_ZERO);  

    if (frame->kva == NULL)
        frame = vm_evict_frame();  
    else
        list_push_back(&frame_table, &frame->frame_elem);

    frame->page = NULL;

	ASSERT (frame->page == NULL);
	return frame;
}

9. vm_claim_page() ๊ตฌํ˜„

  • vm/vm.c
  • ์ธ์ž๋กœ ์ฃผ์–ด์ง„ va์— ํŽ˜์ด์ง€๋ฅผ ํ•˜๋‚˜ ํ• ๋‹นํ•œ๋‹ค.
  • ํ•ด๋‹น ํŽ˜์ด์ง€๋กœ vm_do_claim_page๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
bool
vm_claim_page (void *va UNUSED) {
	struct page *page = NULL;
	/** Project 3-Memory Management */
	struct page *page = spt_find_page(&thread_current()->spt, va);

    if (page == NULL)
        return false;

	return vm_do_claim_page (page);
}

10. vm_do_claim_page() ๊ตฌํ˜„

  • vm_get_frame() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํ”„๋ ˆ์ž„ ํ•˜๋‚˜๋ฅผ ์–ป๋Š”๋‹ค.
  • ํ”„๋ ˆ์ž„์˜ ํŽ˜์ด์ง€๋กœ ์–ป์€ ํŽ˜์ด์ง€๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.
  • ํ”„๋ ˆ์ž„์˜ ๋ฌผ๋ฆฌ์  ์ฃผ์†Œ๋กœ ์–ป์€ ํ”„๋ ˆ์ž„์„ ์—ฐ๊ฒฐํ•œ๋‹ค.
  • ํ˜„์žฌ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์— ๊ฐ€์ƒ ์ฃผ์†Œ์— ๋”ฐ๋ฅธ frame์„ ๋งคํ•‘ํ•œ๋‹ค.
10-1. writable ๊ตฌ์กฐ์ฒด ์ถ”๊ฐ€
struct page {
	const struct page_operations *operations;
	void *va;              /* Address in terms of user space */
	struct frame *frame;   /* Back reference for frame */

	/* Your implementation */

	/* Per-type data are binded into the union.
	 * Each function automatically detects the current union */
	union {
		struct uninit_page uninit;
		struct anon_page anon;
		struct file_page file;
#ifdef EFILESYS
		struct page_cache page_cache;
#endif
	};
	/** Project 3-Memory Management */
	struct hash_elem hash_elem;
	bool writable;
};
10-2. mmu.h include
  • vm/vm.c
/** Project 3-Memory Management */
#include "threads/mmu.h"
static struct list frame_table; 
10-3. vm_do_claim_page() ๊ตฌํ˜„
  • vm/vm.c
static bool
vm_do_claim_page (struct page *page) {
	struct frame *frame = vm_get_frame ();

	/* Set links */
	frame->page = page;
	page->frame = frame;

    if (!pml4_set_page(thread_current()->pml4, page->va, frame->kva, page->writable))
        return false;

	return swap_in (page, frame->kva);
}
profile
Sunny Day!

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