커널 고치지 않고 힙 페이지를 prefetch하는 방법? file-backed heap?
안녕하세요.
어플리케이션 프로그램에서, 특정 힙 주소에 해당하는 페이지들을 prefetch하고 싶습니다.
예를 들어 적당한 힙의 virtual address 영역을 주면 그 주소 영역에 해당하는 페이지들이
메모리로 prefetch되는 거죠. (기왕이면 asynchronous하게 되면 좋겠네요)
커널을 고치면 어떻게든 방법이 있겠지만, 그렇게 되면 제 방법을 반드시 제가 수정한 커널과
함께밖에 사용할 수 없기 때문에 최대한 커널은 손대지 않으려고 합니다.
어플리케이션 레벨에서 프리패치 할수 있는 방법을 찾던 중 madvise() 시스템 콜에서
advise parameter를 MADV_WILLNEED로 주면 프리패치를 할 수 있다는 것을 알게 되었습니다.
그런데 문제는 file-mapped 페이지들에 대해서만 프리패치가 되더군요.
(anonymous vma들에 대해서는 그냥 바로 리턴해 버립니다)
첫번째 질문입니다.
1. 이런 문제를 보통 어떻게 푸나요? 그러니까, 커널을 고치지 않고 어플리케이션에서
힙 페이지를 프리패치할 수 있는 방법이 있나요?
제가 이 문제를 풀기 위해 시도한 방법은, 힙을 file-backed로 만드는 것이었습니다.
더미 파일 하나를 만들어서 이걸 메모리에 mmap()으로 매핑시키고, 이 매핑된 영역을 힙처럼
쓰는 거죠. 이렇게 하면 madvise()로 프리패치가 될 거 같았습니다.
그런데 이렇게 만든 가짜 힙이 정말로 진짜 힙과 비슷하게 동작할 것인지가 문제였습니다.
왜냐면 메모리가 충분한 상황에서도 파일에 매핑된 메모리 영역이 계속 파일에
write back 되더군요. 실제 힙 페이지라면 메모리가 부족하기 전에는 디스크에 스왑아웃
되지 않는다고 알고 있습니다. (kswapd도 어느 이상 메모리가 찼을 때 동작합니다.)
보통 상황이라면 이 정도의 오버헤드는 별 상관 없겠지만, 임베디드 환경을 가정하고
실험 중이라서 이 write back이 문제가 될 소지가 있을 것 같습니다.
두번째 질문입니다.
2. 이 "file-backed heap"이 가능한 방법일까요? 이런 게 시도된 적이 있나요?
테스트 프로그램은 다음과 같습니다.
> int i;
> int fd = open("filemap", O_RDWR|O_ASYNC);
> char *heap = (char *) mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FILE, fd, 0);
> char str[4096];
> for (i = 0; i < 4096; i++)
> str[i] = 'a';
> memcpy(heap, str, strlen(str));
> sleep(100);
프로그램이 sleep(100) 하는 동안 "filemap" 파일의 내용을 살펴보았지만, 항상 제가
memcpy로 쓴 내용이 write back 되어 있더군요.
이러한 잦은 write-back이 pgflush daemon에 의한 것인지 궁금해서, sysctl로
다음과 같이 몇 가지의 커널 환경 변수를 고쳐 보았습니다.
vm.dirty_writeback_centisecs = 500 -> 50000
vm.dirty_expire_centisecs = 3000 -> 30000
vm.dirty_ratio = 40 -> 100
vm.dirty_background_ratio = 10 -> 100
하지만 저렇게 해도 mmap()으로 파일을 매핑한 메모리에 뭔가를 쓰면 바로 파일에
write back 되더군요. 아, mmap()은 O_ASYNC flag로 호출했습니다.
그리고 만약 이렇게 커널 환경 변수를 고쳐서 원하는 결과를 얻었다고 해도, 이렇게 되면
전체 시스템이 변경된 환경 변수의 영향을 받게 되므로 제가 원하는 결과가 아닙니다.
저는 정확히 저 파일 매핑된 메모리만 보통 힙처럼, 메모리가 부족할 때만 디스크에
스왑아웃 되는 것을 원합니다.
세번째 질문입니다.
3. 어떻게 저 파일 매핑된 메모리 영역을 보통 힙처럼 동작하게 만들 수 있을까요?
좀 더 자세하게는, 저 파일 매핑된 영역만 flush나 writeback daemon의 영향을
받지 않게 만들 수 있을까요?
답변, 혹은 다양한 코멘트 모두 환영합니다.


댓글 달기