[sw정글 10주차] 쌓여왔던 기술부채들과 그 해결책들
카테고리: swjungle survive
🚀시작
- 몰랐던 사실:
- 한 버킷당 평균 2개를 맞춰주려고 함. rehash를 통해서 버킷cnt계속 늘어남
- file-backed에 해당하는 내용을 anon으로 초기화된곳 위에 올려도 될까?
vm_alloc_page_with_initializer
을 왜VM_ANON
으로 해주는 걸까?- 해결내용
- 정확한 단어의 뜻을 먼저 알아야 한다
- VM_FILE ⇒
memory mapped *files*
- VM_ANON ⇒
anonymous mappings
- VM_FILE ⇒
- 즉 핀토스에서의 file_backed는 메모리에 맵핑된 파일이라는 뜻이다.
- code, data와 같은 녀석들은 파일로써 디스크에 존재하니까(우리시몬스조는) VM_FILE이라고 생각을 했었다. 하지만 모두 ANON으로 분류된다. code, data, bss 들도 사실상 (anon의 일부분인)힙영역의 일부분으로 생각하면 되는 것이다.
- 거대한 anon_page를 만들어두고, (anon의 일부분인)힙영역에 코드, 데이터들을 채워나간다.
- (그리고 맨 윗부분을 setup_stack으로 초기화시켜주고 바로 claim해주었던 것)
- 메모리에 맵핑되었다(mmap당했다)는것은 힙도, 스택도 아닌 영역에 할당받았다는 뜻 (그리고 이녀석을이 결국 VM_FILE임)
-
적당히 관련있는 이미지
- 정확한 단어의 뜻을 먼저 알아야 한다
- 해결내용
- ELF의 헤더와, 프로그램 헤더의 차이점은?
- (pintos 기준)커널영역에는 페이지테이블 말고 각 프로세스별 스택 정보도 쌓이는 것일까?
- 해결내용
- 해결내용
- Malloc과 mmap은 어떤 차이가 있을까?
- 해결내용
Malloc
은 힙영역에 동적으로mmap
은 힙도스택도 아닌 영역에 정적으로- 힙도 스택도 아닌 영역 ⇒ memory mapped region
- 설마 진짜 정적할당인가 싶어서 mmap함수 쓰인곳들을 살펴보면 전부 정적으로 할당되어 있음(이미 크기가 결정나 있음, 변수로 할당크기 선언 X)
- 리눅스에서는 malloc호출되었을 때, 너무 사이즈가 크면 mmap으로 분기됨
- 핀토스에서는 동등한 개념, 실 linux 시스템에서는 하위개념에 속함
-
관련있는 이미지
- 해결내용
- 핀토스에서의 커널영역 메모리맵핑은 어떻게 되는걸까?(성훈&중선 주말 피자먹다가 했던 이야기)
- 해결내용
- 핀토스의 크기는 수 MiB크기정도로 상당히 작음
- 핀토스에서는 물리와 kva는 모든 영역이 1:1 맵핑됨
- 대부분의 영역은 공영역임
- 해결내용
- swap-fork는 왜 make check 돌리면 무조건 터져버리는가?(개별테스트시 정상작동)
- 해결내용(아직 미완료)
- (추측) 한번에 돌릴시, 여러 프로그램들의 메모리누수로 인한 공간부족으로 인하여 터지는 것 같다.
- 해결내용(아직 미완료)
- page-merge는 왜 간헐적으로 터져버리는가?
- 해결내요(아직 미완료)
- (현진형피셜) donate-multiple에서 터지는 것 같다
- filesys들에 lock걸어 주면 조금 더 안정적이게 됨
- 0x18, 0x40등 이상한 주소값들에 대해 방어코드 심으면 조금 더 안정적이게 됨
- 해결내요(아직 미완료)
- vm_try_handle_fault에서 user ? f→rsp : thread_current()→user_rsp; 의 3항 연산자가 있는데 둘 다 똑같은 말이 아닌가?
-
코드 참고
-
깃북 내용
-
해결내용 (아직 미완료)
- 직접 찍어본 결과
thread_current()→user_rsp
와f→rsp
는 다른 값을 가지고 있는데 그 이유에 대해서는 정확하게 어디서 온지 아직 모르겠음 - 좀 더 확인 필요!
- 직접 찍어본 결과
-
- FIFO, LRU, Clock 알고리즘? 왜 쓰는가?
- 해결내용(OSTEP p.257 ~ 272)
- 물리메모리 크기의 제한을 극복하기 위해 나온 다양한 정책들이 있고 그 정책은 아래와 같이 정리
- FIFO (First in - First out) : 간단하게 구현하지만 성능이 안좋음
- 랜덤 방식 : 운에 따라 성능이 달라짐
- 최적조건 (Optimal) : 가장 나중에 접근될 페이지를 교체하는 것
- LRU (Least Recently Used) : 지역성의 원칙(최근성)에 따르는 것으로 가장 오래 전에 사용하였던 페이지를 교체
- LFU (Least Frequently Used) : 지역성의 원칙 (빈도수)에 따르는 것으로 가장 적은 빈도로 사용된 페이지를 교체
-
메인메모리가 가상메모리에 페이지를 가져놓기 위한 캐시로 여겨진다면 평균 메모리 접근시간(Average Memory Access Time, AMAT)를 계산할 수 있는데 해당 계산식은 아래와 같음
$AMAT = T_m + (P_m * T_D)$
- Tm = 메모리 접근 비용
- Pm = cache miss 날 확률
- Td = 디스크 접근 비용
⇒ 현대 시스템에서는 디스크 접근 비용이 매우 크기 때문에 아주 작은 미스가 발생하더라도 큰 비용이 발생함 ⇒ 디스크 접근 비용을 줄이는 것이 관건!
- 여러가지 TC를 돌려본 결과 FIFO는 좋지 못한 성능을 보였고 최적조건이나 LRU가 가장 좋은 결과를 보였음 (예외적인 상황으로 Sequential Workload에서는 Rand가 좋은 성능을 보였고, FIFO는 최악의 성능을 보여주었음)
-
그래프 참고 (링크)
-
-
하지만 LRU의 경우 4KB의 페이지를 4GB의 물리메모리에 올릴 때 백만개의 페이지를 조사해야하고, 이 중 가장 오래 전에 사용된 페이지를 찾는 것은 고비용의 연산이 됨
⇒ 여기서 나온 것이 시계알고리즘 (clock algorithm)으로 최근 사용 유무에 따라 Use Bit (1 : 최근 사용 / 0 : 사용 x)를 통해 환형 리스트 등을 통해서 0인 페이지를 찾기 위해 순서대로 탐색함
- Dirty Bit를 사용하는 것은 시계알고리즘을 좀 더 추가 개선하는 것으로 Dirty Bit가 1이 되어있으면 무엇인가 써져있다는 상태이고 디스크에 다시 갔다와야하기 때문에 비용이 많이 들어서 성능적인 측면을 고려하여서는 위의 Use Bit와 Dirty Bit를 동시에 사용함으로써 조금이라도 저비용을 들게 하려고 노력
- 근데 제일 좋은 방법은 그냥 물리 메모리를 늘리는 것! 그게 가장 좋음 🤣
- 물리메모리 크기의 제한을 극복하기 위해 나온 다양한 정책들이 있고 그 정책은 아래와 같이 정리
- 해결내용(OSTEP p.257 ~ 272)
- vaddr.h, mmu.h
- pml4 테이블 기준주소 + 선형주소의 PML4offset = pml4 엔트리 (???)
- 해결내용
- pml4는 디렉토리와 같다
- 임의의 pml4도 n개의 엔트리들로 구성되어있다
-
어떤 임의의 pml4의 시작부분부터 N칸만큼 이동하면, N번째 임의의 pml4에 대해 N번째 엔트리가 나올 것이다
(= 어떤 pml4의 기준주소로부터 offset만큼 이동하면 해당 pml4엔트리를 만날 수 있다 )
- 해결내용
- pml4 테이블 기준주소 + 선형주소의 PML4offset = pml4 엔트리 (???)
- KERN_BASE = 42 하드코딩의 의미
- 해결내용
- multi-oom 테스트에 한해서였다
- 일반적인 경우 (우리가 알고있듯)핀토스에서 kern_base는 0x8004000000
- 세그폴트 = 유저에서 커널, 페이지폴트 = mapping된 페이지가 없음
- 따라서 KERN_BASE = 42면 유저가 쓸 공간이 없으므로…. page fault 자주발생 및 큰 파일 못올리게 됨
- 해결내용
- 유저메모리.. 나는 어디에 저장해(??)
- 해결내용
- (VA기준)커널영역(의 일정 부분)은 1:1로 pysical에 맵핑됨
- (VA기준)유저영역은 페이지테이블에 의해 pysical에 맵핑됨
- 따라서 유저영역의 정보가 직접 변환되는게 아님
- 따라서 mmap과 같은 맵핑함수는 커널영역의 정보에 대해서만 작동한다.
- 해결내용
- PTE(페이지 테이블 엔트리)
- 이거 주인이 누구인지 어떻게 앎?
- PTE는 페이지 테이블의 첫번째 부분인지?
- 해결내용
- 어떤 프로세스가 실행중일 때, 해당 프로세스의 유저스페이스만 pml4_activate함수를 통해 활성화된다
- cr3로도 불리는 이것은, 한 프로세스에 대하여 항상 하나만 활성화되어있다. 따라서 그냥 열려있는 PTE가 해당 프로세스의 주인이다
- PTE는 페이지테이블의 첫번째 부분이 아니라, PT의 요소 하나하나들이다.
- 오늘 야구 “엔트리”가 어떻게 돼?
- 해결내용
- 페이지 테이블, 페이지 디렉토리는 둘다 RAM에있는가?
- 해결내용
- 모두 VA의 커널스페이스에 존재한다. 그리고 이 정보들은 pysical의 어느 부분과 잘 mapping되어있다
- 그리고 이 ‘어느부분’은 kernel base 기준 0부터 pysical에 mapping된다.
- 해결내용
- Linux 커널에서 사용자 공간 메모리에 액세스하는 방법은 무엇입니까?
- 해결내용
- 핀토스의 경우, 쓰레드별로 유저스페이스를 따로 가지고 있다
- 따라서, 어떤 한 포인터의 주소정보만으로는 그 포인터가 속한 pysical의 정보를 얻어올 수 없다
- 왜냐하면!! 유저별로(쓰레드별로) 각기 다른 유저스페이스를 차지하고 있기 때문이다.
- 따라서, 어떤 한 포인터가 속해있는 프로세스를 알아야 한다. (핀토스 경우 쓰레드로 보아도 무방)
- 어떤 쓰레드의 포인터인지 알게되면, pysical의 어디부분에 맵핑되어있는지 알 수 있을테고 해당 VA로 정보를
- 해결내용
- NOT_REACHED() 의 의미??
- 해결내용
-
여기오면 커널이 혼란스러워함(헐… 여기 오면안되는데…. 그냥 패닉 내야겠당ㅎㅎ)
-
- 해결내용
- thread 구조체에 All_elem 언제쓰누???
- 해결내용
- ready_list에도, wait_list 등 여기저기 산재되어 있을 수 있음
- 메모리 누수때문에, 산재된 녀석을 한번에 지우기 쉽게 하기 위해서 all_elem으로 관리
- 해결내용
- 프로세스 디스크립터, 파일 디스크립터 테이블
- 해결내용
- 프로세스 디스크립터 = 쓰레드라는 의미로 쓰임
- 파일디스크립터 = 모니터, 키보드, 우리가 오픈한 파일… 등
**fdt
(File Descriptor Table)
- 해결내용
- PageFault를 이용하여 bad-ptr-attack(string copy)을 방어하려고 할 때, 왜
rax
레지스터를0Xffffffff
로 설정하여 주는지?- 해결내용
- 답변: 스택exchange(링크)
- 0xffffffff = -1임, 어셈블리로 -1 set 쉽게 해주려고
-
그냥 exit(-1)을 빠르게 하기 위한 장치임
- 답변: 스택exchange(링크)
- 해결내용
- 이번 과제에서 HEAP 영역을 쓰면 안 되는 걸까??
- 해결내용
- HEAP은 malloc해주지 않는이상 사용하지 않는다. 사용해도 무방하다
- 추가적으로…
-
Page할당은 힙도 스택도 아닌 영역에 할당된다
-
- 해결내용
- syscall.c의 case문에서
a label can only be part of a statement and a declaration is not a statement
에러가 뜸- 해결내용
- 중괄호로 묶어주어 해결해주긴 했는데… 이유는 아직까지도 잘 모르겠음;;;
- OPEN()에서는 잘 되던데, EXEC()에서는 왜 저런 에러를 보여줄까????
- 해결내용
- exec에서는… fn_copy에 palloc을 하고, 거기에 strlcpy를 해준다. 왜 할당된 페이지에 해주는가? 거기에 프로그램이 올라가지는 않겠지? 단순 이름이 너무 길까봐 palloc을 해주는건가? malloc으로는?해주면 안되나?
- 해결내용
- 이름이 길 수 도 있어서…?
- 해결내용
😵배우면서 깨달은 내용을 정리해 보았습니다. 틀린 것 같은 개념을 아래 댓글에 달아주시면 감사합니다😵
🌜 Thank you for reading it. Please leave your comments below😄
댓글 남기기