2.6.32 merge plan Sep 16, 2009

http://lkml.org/lkml/2009/9/15/471

2.6.32를 위한 merge plan이 발표되었습니다. by Andrew Morton.
것이 의미하는 것은 그 동안 mm tree에서 잘 성숙되어 온 patch들중,
Andrew Morton과 Subsystem maintainer들에 의해 어떤 patch들을
이번에 mainline으로 밀어 넣을 것인지를 결정하는 일입니다.

밀어 넣어진 patch들 또한 rc1~rc8 or rc9이 될 때 까지 약 3개동안 mainline
tree에서 테스트를 거치게 됩니다.

이번 2.6.32를 위한 patch들 중 특이한 점은 memory management patch들이
대거 포함되었다는 겁니다. 즉, 속된 말로 잘 되면 대박, 못되면 쪽박이 될 수도 있습니다.
(제가 개발팀장이라면 2.6.32 커널은 되도록 피하라고 지시할 것 같습니다.)

memory management 쪽의 패치가 많을 수 있었던 것은 “후지쯔 가이”들,
즉 일본인들이 mm 쪽의 개발에 부지런히 참여했었고,
늘상 부지런하던 Hugh, Rik, Mel, 그리고 VFS layer에 주로 놀던 Wu의 mm 참여,
반대로 mm쪽에서 많은 활약을 하던 Nick의 VFS layer로의 이동.
그리고 한국의 hobbyist정도가 정도가 바쁘게 움직인 덕입니다. ^^

그럼 3달동안 어떤 regression들이 생기는 지 두고 보기로 하죠.

꼬랑지)

MM쪽의 패치를 만들어 나가는 과정은 약간 복잡합니다.
물론 다른 쪽도 얼마든지 복잡해 질 수 있지만, MM쪽은 시스템에 critical한
변경을 가하는 것이기 때문에, 하나의 패치에도 여러 사람들이 관계하게 됩니다.
먼저, 최초 문제의 목격자 reporter(Reported-by),
그 문제를 풀기 위한 패치의 저자(signed-off-by),
패치를 review해주는 리뷰어(Reviewed-by)
패치에 대한 승인을 해주는 영향력 있는 인물들의 승락(Acked-by)
패치를 test해주는 테스터(Tested-by),
등이 관계합니다 이밖에도 Andrew Morton은 해당 패치의 관계자들,
즉 그 패치에 대해서 argue가 있었던 사람이나 해당 패치를 꼭 알고 해야
하는 사람들을 patch description에 Cc하곤 합니다.
MM쪽은 이렇듯 하나의 패치를 만들기 위해 많은 사람들이 작업을 하게 되며,
관계하게 됩니다.

아 그리고 mm tree가 Memory Management Tree가 아닙니다.
쓰고 나니 mm tree가 그럼 무엇의 약자냐고 물어보는 이가 있어 부연합니다.
mm tree는 memory management의 약어이긴 합니다.
하지만 mm tree의 기능은 더 이상 mm만 care하지 않는다는 것입니다.
mm tree는 memory management 뿐만이 아니라 다양한 subsystem들도 포함하며,
마치 예전 홀수 버젼의 test version이라고 생각하시면 대충 맞습니다.
참고로 mmtom은 "MM of the moment or MM of the minute"의 약어입니다.
Andrew도 잊어먹었다고 하더군요.

Offline Scheduler Sep 12, 2009

http://lkml.org/lkml/2009/8/22/89

최근 mainline의 hot issue중의 하나이다.
multi or many core system에서 CPU중 하나를 스케줄러에서 offline시키고 해당 CPU에
특정 job을 binding하여 OS noise없이 사용하자는 것이다. 즉, task를
특정 CPU에 dedication시키는 설비를 만들자는 것이다.
시간이 있으신 분들은 그 쓰레드들을 모두 읽어보아라. 현재 약 81개의 쓰레드가 달려
있는데 상당히 재미있다. barrios의 나쁜 기억력은 모든 내용을 기억할 수 없다.
생각나는 부분들만을 위주로 정리한다.

먼저 Christoph와 같은 HPC guy는 굉장히 찬성하는 입장이고, Peter, Ingo, Thomas와
같은 기존 scheduler나 HRT maintainer들은 반대의 입장이다.
Christoph가 찬성하는 이유는 간단하다. 기존까지 약간의 솔루션들이 있었지만,
offline scheduler와 같이 간단하게 모든 OS noise를 제거할 수 있는 방법은 없었다는
것이다. HPC에서는 CPU 1 cycle이라도 불필요하게 OS를 위해 App가 양보할 수 없다는
생각을 가지고 있기 때문이다. 그 생각은 barrios도 공감한다. 시스템의 주인공은
응용 프로그램들이니깐. 아. Offline scheduler의 동작원리를 간단히 설명하면(
그럴수 밖에 없다. 원래 간단하니까). CPU Hotplug facility를 사용하게 되어 있다.
즉, Offline 시키고 싶은 CPU를 Unplug시켜버리며 미리 등록되어 있던 커널 함수를
실행시키는 것이다. 이 커널 함수가 결국 태스크의 entry point가 될 것이다.

그렇다면 Peter, Ingo와 같은 maintainer들이 반대하는 이유는 무엇인가?
문제를 우회하고 있다는 것이다. OS noise에 대한 latency가 문제라면,
해당 문제를 해결하여 Linus system 전반의 문제들을 해결해야지, 그런식의
work around는 오히려 앞으로 나오게 될 좋은 접근의 다른 시도들을 막을 수
있다는 것이다. 중요한 이유는 그런 식의 OS의 제어하에 벗어나게 되는 것을
달가워하지 않는 것 같다. 얘기는 다소 잘못된 방향으로 나아가며 Chrisoph와
Perter, Ingo가 감정의 날을 세우다가 Andrew Morton이 한마디 했다.
"Problem State가 무엇이냐?"고 다들 구현을 가지고 따지고 있는 가운데
다시 토론을 본론으로 가져왔다. 또한 Andrew는 것이 필요한 일이고, Design이
깔끔하고, 유지보수가 용이하다면 merge하지 못할 이유가 없다고 입장을 밝혔다.

여기서 또 다시 Andrew의 view를 알 수 있다. 유지보수의 용이성이다. 제 아무리
좋은 기능을 잘 구현한다 하더라도, 조그만 변경이 시스템에 cirtical한 변경을
가할 수 있거나, 다른 subsystem의 변경에 민감하게 반응하는 패치라면 Andrew는
상당히 꺼려한다. 왜? 그는 Linux kernel의 maintainer이기 때문이다. 다양한 시도들
중 정말 nice한 것만을 선정하여 잘 유지하는 것이 그의 일이기 때문이다.

우리도 본론으로 다시 돌아와서, 이때 Thomas가 involve된다.
Thomas는 문제의 핵심을 언급했다. 결국 이 문제는 한 CPU에서 하나의 Task가
timer interrupt의 방해만 받지 않으면 되지 않겠느냐고 얘기하고 있다.
물론 해당 CPU에 HARD IRQ, SOFT IRQ등의 event가 발생할 수도 있다.
하지만 해당 CPU의 task가 irq를 발생시키는 device와 interaction하지 않는다면
irq는 다른 CPU쪽으로 affinity를 주면 된다. 그 얘기는 결국 SOFTIRQ도 해당 CPU에서
disable 할 수 있다는 얘기이다. 반대로 그 Task가 특정 device와 interaction한다면
해당 irq를 그 CPU와 affinity를 주면된다. 단 가정은 그 Task만 그 device와 interaction
해야만 할 것이다. 그렇지 않으면 다른 task의 job에 해당 CPU가 시달리게 될 것이다.

Thomas와 다른 개발자들의 논의 방향은 이 방향으로 흘렀다.
scheduler에서 특정 priority이상으로 설정된 task가 CPU에 binding될때, tick interrupt를
off시켜버리자는 것이다. 다음 그 task가 schedule out될 때 다시 tick interrupt를 enable하고
그때 accounting을 갱신하자는 얘기 중심으로 무게가 쏠리고 있다.

이 쓰레드에서 중요한 것은 대부분의 개발자들이 needs에 대해서는 공감하고 있다는 것이다.
결국 이 문제는 manycore환경에서 CPU들을 어떻게 잘 활용할 것인가와 연결될 것 같다는게
barrios의 생각이며 offline scheduler가 굳이 아니더라도 새로운 형태의 task가 OS noise없이
실행 할 수 있는 형태의 기능이 mainine에 merge될 것이라고 생각된다.

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로 옮겨갈 것이기 때문이다.

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

Static Trace Point에 관하여 Sep 1, 2009

http://lwn.net/Articles/245671/

좀 지나간 기사이지만, 갑자기 생각이 나서 읽어보았다.

Adding a test-and-jump operation to a kernel hot path will always be a hard sell; the cache effects of referencing a set of global marker state variables could also be significant.

http://thread.gmane.org/gmane.linux.kernel/568586

Immediate values are used as read mostly variables that are rarely updated. They
use code patching to modify the values inscribed in the instruction stream. It
provides a way to save precious cache lines that would otherwise have to be used
by these variables.

위의 2개의 link는 kernel marker가 구현될 당시,
관련 기사와 관련 패치의 일부이다.

인용구를 보면 알겠지만 mainline kernel developer들은
test-and-jump instruction 하나를 없애기 위해서도
저렇게 애를 쓴다. 왜냐하면 그 문제를 풀지 못하면 mainline에
merge되기 어려울 테니. 왜 merge되기 어려울까?

kernel marker는 kernel의 static trace point의 일부이다. 그 얘기는 커널이
release되더라도 enable 되어야 한다는 것이다. 이 논리에 대해서
이해가 가지 않는가?

static trace point란 것은 dynamic probing과는 성격이 틀리다.
static trace point는 이미 커널의 잘(?) 정의된
곳에 삽입되어 있어야 한다. 그래서 system administrator들이나
kenrel developer들은 기존에 잘 정의되어 있는 trace point를 기반으로
시스템의 성능을 분석하기 때문이다. 그러므로 사실 static trace point의
hot issue는 성능문제도 있지만 어떤 곳에 static trace point를
정의할 것이냐가 더 중요하다.

다시 본론으로 들어가서 test-and-jump instruction을 제거하기
위해서 왜 그렇게 애를 쓰는가? 기껏해야 instruction 하나 더
수행하는 것인데? 라고 묻는다면.

test-and-jump중 test를 위해 사용되는 shared variable은 귀중한
cache line을 한 line 소모한다. 그런데 shared varible은 하나일까?

1. static trace point 전체를 enable/disable할수 있으면 좋을까? 아님,
각각의 trace point를 enable/disable할 수 있으면 더 좋을까?
2. 그럼 그런 shared varibale가 하나가 필요할까? 두개가 필요할까?
3. 그럼 cache line을 하나만 소비할까? 두개 소비할까?
4. 그런데 이 trace point가 kernel의 hot path 중 하나에 들어간다면.
test를 위해서는 memory를 referencing해야 하고, 그럼 cache line이
하나가 소비될 것이고, 그 얘기는 worst case 기존에 cache line이
하나 eviction되야 하고, hot path라면 이게 반복될 것이고...

결국, trace point가 없을 때에 비해 working set의 많은 부분들이
cache line에서 eviction될 수 있다는 것이다.

왜 갑자기 뜬금없이 barrios가 잘알지도 못하는 kernel의 marker에
대해 이런 부분들을 언급하는가?

Engineer로써 생각해 볼 건 생각해보고 지킬 건 지키자.

꼬랑지) kernel marker와 tracepoint에 대해 많은 사람들이
그 쓰임새를 혼돈하고 있는 것 같다. 다음을 참조하자.
http://ltt.polymtl.ca/tracingwiki/index.php/Tracepoints_and_Markers
Markers are very much like Tracepoints, except that they declare a format string and export the data through a variable argument list. There is a small overhead associated with variable argument lists and the associated interpretation of the format string. The type of the arguments is also normally restricted to scalar types which can easily be described by the format string. The advantage of Markers is that they are self described. They do not require a prior declaration in an include (.h) file, and they can be processed by a generic probe, expecting a printf-like variable argument list.
Markers are thus used for simple ad-hoc instrumentation. Tracepoints are typically used when a formal hook is desired at an important location in the code. A tracepoint in the code is less visually invasive than a marker since it only contains the relevant arguments (no format string). Furthermore, a tracepoint is a general hooking mechanism which may be used for different purposes, one of which being tracing. The disadvantage is that for each tracepoint the developer must provide a prior definition and a corresponding probe.