Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

2112
737
82112


[라즈베리파이] 커널 타이머(Kernel Timer) - jiffies란 7장. 타이머관리

jiffies는 커널 타이머를 실행하는 시간 단위입니다. 공학 용어로 Resolution이라고 합니다. jiffies를 지피스라고도 하는데 리눅스 커널에서 쓰는 jiffies란 용어를 그대로 쓰겠습니다.

jiffies 개념을 이해하려면 HZ에 대해 배워야 합니다. 그럼 HZ는 뭘 의미할까요? HZ는 1초당 커널 타이머가 동적 타이머를 처리하는 횟수를 의미합니다. 그래서 커널 타이머의 실행 빈도는 HZ에 의해 정해집니다. 커널 타이머가 로컬 타이머를 처리하는 단위라고 말할 수 있습니다. 

HZ가 500이면 1초당 jiffies가 500번 +1만큼 증감하고 500번 커널 타이머가 실행합니다. 그럼 HZ가 크면 좋은 시스템일까요? 그렇지는 않습니다. HZ를 너무 큰 값으로 설정하면 시스템 과부하가 걸릴 수 있습니다. HZ값이 늘어나면 타이머를 처리하는 횟수도 증가하기 때문입니다. 반대로 HZ가 너무 적으면 동적 타이머를 처리하는 횟수가 적으므로 타이머 만료 시각 처리에 오차가 생깁니다. 

이미 수많은 커널과 CPU 개발자들이 여러 시행착오로 CPU 별로 HZ값을 이미 정해 놨습니다. 그럼 라즈베리파이에서 HZ는 얼마일까요? 라즈베리파이는 ARM CPU를 탑재하므로 HZ값이 100입니다. 참고로 ARM 계열 리눅스 커널은 HZ값이 100입니다. 이 값은 라즈비안 커널을 빌드하면 생성되는 .config 파일에서 다음과 같이 확인할 수 있습니다.
CONFIG_HZ=100

라즈비안에서 HZ는 100이니 앞으로 이 기준으로 jiffies값으로 상대 시간을 어떻게 처리하는지 알아봅시다. 

예를 들어 지금 현재 시각을 나타내는 jiffies가 1000이라고 가정합시다. 이때 어떤 함수가 2초 안에 실행하는지 점검하려고 합니다. 현재 시각 기준으로 2초 후는 어떻게 표현할까요? 현재 시각인 jiffies에 2*100(HZ)을 더하면 1200입니다. 이 1200은 현재 시각 정보를 표현하는 1000보다 2초 후 시각 정보입니다. 

현재 jiffies가 1000이면 초당 다음 값으로 업데이트됩니다.
1초 후: 1100
2초 후: 1200
3초 후: 1300

jiffies란 용어는 2가지 개념으로 생각할 수 있습니다.
현재 시각: “지금 jiffies가 304200입니다.”라는 문장은 jiffies 라는 변수가 현재 시각 정보를 나타낸다는 의미입니다.

상대 시각: “jiffie 단위로 200ms로 마감시각을 설정합니다.” 이 문장에서 jiffies는 어떤 의미일까요? jiffies 는 HZ 단위로 시간 정보를 표현하는 단위라 할 수 있습니다. 시간을 현재 시각 값인 jiffies HZ단위 기준으로 설정합니다.

이런 개념을 섞어서 jiffies라는 용어를 쓰니 약간 헷갈릴 수 있는데 다음 절에서 소개해는 ftrace 로그를 같이 분석하면 확실히 jiffies의 개념을 잡을 수 있습니다.

이번에는 Soft IRQ 관점으로 HZ의 의미를 알아봅시다.
커널 타이머는 Soft IRQ로 1초에 HZ만큼 TIMER_SOFTIRQ 아이디로 Soft IRQ 서비스를 요청하고 Soft IRQ 서비스를 실행하는 __do_softirq() 함수에서 로컬 타이머를 실행합니다. 커널 타이머를 실행하는 단위를 HZ라고 할 수 있습니다. 라즈베리파이는 HZ가 100이니 1초에 100번 커널 시스템 타이머가 실행합니다.

HZ 단위 값은 mod_timer(), add_timer() 함수 및 timer_after()와 timer_before()에 전달하는 인자입니다. 관련 코드를 보면서 HZ단위로 시각값을 어떻게 전달하는지 알아봅시다.

우선 mod_timer() 함수를 보겠습니다.
1       static timer_list dynamic_timer
2 int timeout = 0;
3 timeout = jiffies;
4 timeout += 2 * HZ;
5
6 mod_timer(&dynamic_timer, timeout);

먼저 3번 줄 코드를 봅시다.
timeout이라는 지역변수에 현재 시각을 표현하는 jiffies 값을 대입합니다. 

4번 줄 코드는 timeout이라는 지역변수에 (2 * HZ) 값을 더합니다. HZ는 1초 동안 jiffies가 증감하는 횟수를 표현하니 (2 * HZ) 값은 2초를 나타내는 HZ 단위 시간 정보입니다. 

6번 줄 코드는 mod_timer() 함수 두 번째 인자로 timeout을 전달합니다. 현재 시각 기준으로 2초후에 동적 타이머를 실행하라는 의미입니다.

이렇게 로컬 타이머가 2초 후에 만료하려면 다음과 같이 (jiffies + 2 * HZ) 인자를 mod_timer() 함수에 채워서 호출해야 합니다.

다음 mod_timer() 함수 선언부를 봅시다.
[/include/linux/timer.h]
extern int mod_timer(struct timer_list *timer, unsigned long expires);

두 번째 인자가 expires인데 여기에 HZ 단위 시간 정보를 전달해야 합니다.

이번에 커널 코드에서 아주 많이 볼 수 있는 timer_after() 함수 사용 예를 확인합시다.
int elapsed_time = jiffies + ( 3 * HZ )
//
// 특정 함수 실행 구간
//
if (timer_after(jiffies, elapsed_time) {
panic(“Current function should have been executed within elapsed_time\n”);
}

jiffies는 이 코드가 실행할 때 시각 정보이고 elapsed_time는 HZ단위 시각 정보입니다. 현재 시각인 jiffies 값이 elapsed_time보다 크면 panic()이란 함수를 호출해서 커널 크래시를 유발하는 코드입니다. 조금 더 구체적으로 이 코드는 함수 특정 구간 실행 시간이 3초를 지나면 커널 크래시를 일으킵니다.

이렇게 timer_after() 함수에 전달하는 두 인자도 HZ 기준 시간 값들입니다.

커널 타이머에서 HZ는 상대 시간을 표현하는 매우 중요한 단위입니다. 그래서 이 개념을 정확히 이해해야 코드를 제대로 읽을 수 있습니다. 혹시 HZ와 jiffie에 대한 개념이 이해가 안 가도 걱정할 필요는 없습니다. 라즈베리파이를 동작시켜 ftrace 로그를 받아 timer 로그를 분석하면 자연히 머릿속에 들어올 겁니다.

다음에 소스 코드에서 jiffies와 jiffies_64 변수의 의미를 알아보겠습니다.


Reference(프로세스 관리)
4.9 프로세스 컨택스트 정보는 어떻게 저장할까?
 4.9.1 컨택스트 소개
 4.9.2 인터럽트 컨택스트 정보 확인하기
 4.9.3 Soft IRQ 컨택스트 정보 확인하기
 4.9.4 선점 스케줄링 여부 정보 저장
4.10 프로세스 디스크립터 접근 매크로 함수
 4.10.1 current_thread_info()
 4.10.2 current 매크로란
4.11 프로세스 디버깅
 4.11.1 glibc fork 함수 gdb 디버깅
 4.11.2 유저 프로그램 실행 추적 

핑백

덧글

댓글 입력 영역