내가 중학교 때 한창 Visual Baisc 6.0을 다루면서, 왜 Windows API를 통한 타이머의 최장 간격에 제한이 생길까 궁금해했던 적이 있었다. 그때는 단순히 32bit Long 데이터형의 overflow 때문이겠지 생각하고 넘어갔었는데, 오늘 커널세미나를 들으면서 좀더 자세히 알게 되었다.
리눅스 시스템에서 어떻게 시간 측정을 하고, Tick을 발생시키고 계산하는지에 관한 내용이었는데, 시스템 프로그래밍 프로젝트를 하면서 왜 패킷 전송을 지연시키기 위해 usleep 함수를 쓸 때 어느 정도 시간 이상을 주어야 했는지(내가 당시 의도했던 건 다른 프로세스가 스케쥴링되게 하여 패킷 전송 간격을 벌리는 거였다.), 또한 gettimeofday 같은 함수가 어떻게 동작하는 것인지, 아주 작은 시간 간격을 타이머로 지정할 때 문제가 생기는 이유가 무엇인지 알 수 있었다. 또한 jiffies와 HZ 상수에 의해 타이머 간격의 최대값이 결정된다는 사실을 알았다. (HZ가 1000인 경우 49.7일이 된다)
아주 조금이지만, 커널을 들여다보니 상당히 흥미롭다. 내가 프로그래밍하면서 가졌던 소소한 의문들에 대해서, 왜 그럴 수밖에 없었는지, 왜 그런 현상이 나타나는지 알 수 있었다.
내가 어렸을 때 신기하게 느낀 것 중 하나가, 프로그램을 한 번 실행하고 나면, 그 다음 번에 실행할 때는 훨씬 빠르다는 것이었다. 파일을 읽을 때도 마찬가지였고. 근데 시스템 재부팅을 하거나, 그 프로그램을 오랫동안 쓰지 않다가 다시 실행하면 처음 실행할 때만큼 시간이 걸린다는 점이었다. (이걸 어느 순간 느꼈던 것은 아니고 오랜 동안의 경험이 쌓이면서 이런 동작이 이뤄진다는 것을 알 수 있었다)
다음 주에 내가 세미나를 맡은 부분이 Page Caching에 관한 부분이다. 미리 조금 읽어보았는데, I/O 속도를 높이기 위해서 파일 단위(inode)로 page 정보 구조체를 두고 읽으려고 하는 부분을 메모리에 올려 cache하는 방법이다. 이렇게 해서 반복적으로 같은 곳을 읽게 되면 실제로는 파일을 읽는 게 아니라 메모리를 읽게 되므로 속도가 빨라지는 것이다. 거꾸로 그 위치에 기록하게 되면, 커널에서는 그 page cache를 'dirty' 상태로 표시하는데, 이것은 해당 내용이 변경되었으니 언젠가 디스크로 기록되어야 함을 뜻한다. 커널 내에 pdflush 데몬이라는 것이 있어서 적당한 시점이 이것을 실제 디스크에 기록해주는데, 오랫동안 해당 cache를 사용하지 않는 경우나 메모리가 부족한 경우에 행해지게 된다.
이것은 내가 경험적으로 느꼈던 것과 거의 일치하는 설명이다. 특히 소스코드를 컴파일할 때 이런 걸 많이 느끼는데, 컴퓨터를 켜고 처음 컴파일할 땐 무지 느리지만 그 다음부터는 별로 디스크를 긁지 않고도 슥슥 되는 것을 볼 수 있다. (원격 콘솔로 작업할 때도 그 차이가 느껴질 정도다)
이렇게 막연히 그럴 것이다라고 생각했던 사실들을 커널을 아주 조금만 들여다봤음에도 하나하나 알게 되는 것이 정말 매력있는 것 같다. 비록 내가 요즘 주로 쓰는 건 php, python, java 같은 매우 고수준/스크립트 언어들이지만, 그 내부에서 동작하는 것을 알게 되니까 대충 그럴 것이다라고 넘어갔던 것들에 대해 확실한 감이 오고, 성능 최적화나 어떻게 접근하는 것이 시스템에 무리를 덜 줄 지와 같은 문제들을 생각할 수 있을 것 같다. (아직은 그만한 경험이 없지만 말이다)
또 하나 흥미로운 건, 최근 나오는 Dual Core / Dual CPU 시스템들의 경우 각 코어가 완전히 따로 동작함으로써 발생하는 각종 race condition들에 대한 처리와 같은 것들이다. 세미나의 원래 목적인 Virtualization 기술에서도 가장 문제가 되는 부분이기도 하고. 아직은 아는 게 별로 없어서 구체적인 내용은 모르겠지만, 내용이 조금 어렵고 방대하긴 해도 즐겁게 들을 수 있는 세미나가 될 것 같다.
리눅스 시스템에서 어떻게 시간 측정을 하고, Tick을 발생시키고 계산하는지에 관한 내용이었는데, 시스템 프로그래밍 프로젝트를 하면서 왜 패킷 전송을 지연시키기 위해 usleep 함수를 쓸 때 어느 정도 시간 이상을 주어야 했는지(내가 당시 의도했던 건 다른 프로세스가 스케쥴링되게 하여 패킷 전송 간격을 벌리는 거였다.), 또한 gettimeofday 같은 함수가 어떻게 동작하는 것인지, 아주 작은 시간 간격을 타이머로 지정할 때 문제가 생기는 이유가 무엇인지 알 수 있었다. 또한 jiffies와 HZ 상수에 의해 타이머 간격의 최대값이 결정된다는 사실을 알았다. (HZ가 1000인 경우 49.7일이 된다)
아주 조금이지만, 커널을 들여다보니 상당히 흥미롭다. 내가 프로그래밍하면서 가졌던 소소한 의문들에 대해서, 왜 그럴 수밖에 없었는지, 왜 그런 현상이 나타나는지 알 수 있었다.
내가 어렸을 때 신기하게 느낀 것 중 하나가, 프로그램을 한 번 실행하고 나면, 그 다음 번에 실행할 때는 훨씬 빠르다는 것이었다. 파일을 읽을 때도 마찬가지였고. 근데 시스템 재부팅을 하거나, 그 프로그램을 오랫동안 쓰지 않다가 다시 실행하면 처음 실행할 때만큼 시간이 걸린다는 점이었다. (이걸 어느 순간 느꼈던 것은 아니고 오랜 동안의 경험이 쌓이면서 이런 동작이 이뤄진다는 것을 알 수 있었다)
다음 주에 내가 세미나를 맡은 부분이 Page Caching에 관한 부분이다. 미리 조금 읽어보았는데, I/O 속도를 높이기 위해서 파일 단위(inode)로 page 정보 구조체를 두고 읽으려고 하는 부분을 메모리에 올려 cache하는 방법이다. 이렇게 해서 반복적으로 같은 곳을 읽게 되면 실제로는 파일을 읽는 게 아니라 메모리를 읽게 되므로 속도가 빨라지는 것이다. 거꾸로 그 위치에 기록하게 되면, 커널에서는 그 page cache를 'dirty' 상태로 표시하는데, 이것은 해당 내용이 변경되었으니 언젠가 디스크로 기록되어야 함을 뜻한다. 커널 내에 pdflush 데몬이라는 것이 있어서 적당한 시점이 이것을 실제 디스크에 기록해주는데, 오랫동안 해당 cache를 사용하지 않는 경우나 메모리가 부족한 경우에 행해지게 된다.
이것은 내가 경험적으로 느꼈던 것과 거의 일치하는 설명이다. 특히 소스코드를 컴파일할 때 이런 걸 많이 느끼는데, 컴퓨터를 켜고 처음 컴파일할 땐 무지 느리지만 그 다음부터는 별로 디스크를 긁지 않고도 슥슥 되는 것을 볼 수 있다. (원격 콘솔로 작업할 때도 그 차이가 느껴질 정도다)
이렇게 막연히 그럴 것이다라고 생각했던 사실들을 커널을 아주 조금만 들여다봤음에도 하나하나 알게 되는 것이 정말 매력있는 것 같다. 비록 내가 요즘 주로 쓰는 건 php, python, java 같은 매우 고수준/스크립트 언어들이지만, 그 내부에서 동작하는 것을 알게 되니까 대충 그럴 것이다라고 넘어갔던 것들에 대해 확실한 감이 오고, 성능 최적화나 어떻게 접근하는 것이 시스템에 무리를 덜 줄 지와 같은 문제들을 생각할 수 있을 것 같다. (아직은 그만한 경험이 없지만 말이다)
또 하나 흥미로운 건, 최근 나오는 Dual Core / Dual CPU 시스템들의 경우 각 코어가 완전히 따로 동작함으로써 발생하는 각종 race condition들에 대한 처리와 같은 것들이다. 세미나의 원래 목적인 Virtualization 기술에서도 가장 문제가 되는 부분이기도 하고. 아직은 아는 게 별로 없어서 구체적인 내용은 모르겠지만, 내용이 조금 어렵고 방대하긴 해도 즐겁게 들을 수 있는 세미나가 될 것 같다.