RT task and mlock race Sep 10, 2009

Linux에서의 Real Time?
시작부터 거창하다. 오늘 이 거창한 주제에 대해서 얘기하자는 것은 아니다.
이 주제는 거의 반나절 이상 얘기가 되야하는 주제이고..

오늘 얘기하고 싶은 것은 RT task와 Mlock system call과의 문제이다.
사실, Linux RT에 가장 큰 걸림돌은 Memory Subsystem이라고 생각한다.
Ingo나 Robert과 같은 많은 개발자들이 Linux의 RT feature를 향상시키기
위해 다각도로 노력을 해왔지만 아직까지 개척되지 못한 부분이 Memory 부분이다.

현재 Linux kernel의 memory allocation/reclaim routine은 절대 deterministic
하지 못하기 때문이다. 오늘 이 얘기를 하려고 하는 것이 아니니 여기서 각설하고.

RT task를 사용하는 환경에서 page fault overhead를 줄이기 위해서
mlock system call을 흔히 사용한다. 또는 Montavista의 RT programming guide를 봐도,
또는 세미나를 들어도 mlock을 사용하라고 권한다.
하지만 다음과 같은 경우 큰 문제를 발생시킬 수 있다.

1. taskset 0x2 ./test
A. => Top과 Top 환경에서 숫자 1번 키를 통해 CPU1이 100% 소모되고 있는 것을 확인
2. sudo chrt –fp 55 `pidof test`
A. RT task로 변환
3. dd if=/dev/zero of=test.dat bs=4K count=1000000
A. 4G의 파일을 생성하는 명령하나 수행
4. .taskset 0x4 /test_mlock
A. 3번째 CPU에서 Memory lock을 수행하는 application 수행
3번째 CPU에서 실행되는 test_mlock 응용이 mlockall system call에서
멈추어 더 이상 실행되지 않는 것을 확인할 수 있다. 만일 시스템에 top을 수행시킬
수 있다면 해당 프로세스의 state를 봐라. 'D' state일 것이다.
그리고 시간이 좀 지나게 되면 운이 좋지 못하면 시스템 전체가 먹통이 되는 현상을
볼 수 있을 것이다.

./test

#include

int main()
{
int i = 0;
while(1) {
i+=1;
}
}

./test_mlock
#include
#include

int main()
{

printf("mlock test\n");

printf("before mlock\n");
mlockall(MCL_CURRENT|MCL_FUTURE);
printf("after mlock\n");
return 0;
}


자. 도대체 시스템에서 무슨 일이 일어났을까?
CPU2에서 RT task가 user space에서 CPU를 100% 소모하며 실행되고 있다.
이때 CPU3에서의 응용 프로그램이 mlockall system call을 수행한다.
mlock system call은 kernel 내부에서 동작할 때, 먼저 per CPU page_vec
에 저장되어 있는 lru pages들을 lru list로 drain하게 되어 있다.
이때 문제가 발생한다. 모든 CPU들의 page_vec에 pages들을 drain하기 위해서
커널은 workqueue를 사용하며 lru drain이 모두 완료될 때 까지 기다린다.
즉 해당 work들을 flush한다는 말이다. 이때 CPU[1,3,4]는 문제가 안된다.
문제가 되는 녀석은 RT task를 수행하고 있는 CPU2이다.
CPU2의 RT task는 자발적으로 제어권을 놓지 않는 한 kenrel은 CPU2를 위한 제어권을
받을 수 없다(timer tick을 제외하고. 하지만 timer tick이 우리의 상황을 해결해
줄 수는 없다.). 그렇게 되면 CPU2의 eventd가 수행될 수 없고, 그 결과 CPU3에서 실행한
lru_add_drain_all(모든 CPU의 page_vec을 flush하는)은 완결될 수 없다.
즉 CPU3의 응용 프로그램은 CPU2에서 수행되고 있는 RT task의 execution time에
dependency를 갖게 된다.

문제는 더욱 커질 수 있다. CPU2의 eventd에 pending되어 있던 work들이 수행되지 못할 경우,
그 work의 event 완료를 기다리는 모든 task들은 모두 freeze되는 효과를 볼 것이다.

이는 결국, 시스템 전체의 hang으로 이어질 수 있다는 것이다. RT task를 무한루프로 생성하는
테스트가 다소 비약일 수 있다고 생각할 수도 있다. 하지만 문제의 요지는 RT task의 무한루프가
아니다. 문제는 CPU3에서 실행된 task가 CPU1에서 실행되고 있는 task보다 더 높은 RT prio를
가질수도 있으며 이와 같은 상황에서의 mlock system call은 priority inversion problem을
만든다는 것이다. 물론 kernel에 많은 priority inversion problem 중의 하나일 뿐이지만,
문제는 mlock system call이 RT task들이 흔히 사용할 수 있다는 데서 있다고 본다.

barrios는 사실, mlock system call의 경우 굳이 page_vec을 drain할 필요가 없다고 생각한다.
그 이유는 해당 page들은 결국에는 PG_mlocked될 것이며, unevictable list로 옮겨갈 것이기 때문이다.

다른 개발자들의 의견을 기다려 보자.

0 개의 덧글: