Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

19113
1478
166889


[리눅스커널] 프로세스: 태스크 디스크립터(task_struct 구조체) - 프로세스 실행 시각 4. 프로세스(Process) 관리

태스크 디스크립터에는 프로세스의 실행 시각 정보를 알 수 있는 다음과 같은 필드가 있습니다.

u64 utime 
u64 stime 
struct sched_info sched_info.last_arrival

먼저 utime 필드를 소개합니다.

u64 utime

유저 모드에서 프로세스 실행한 시각을 나타냅니다. 이 필드는 account_user_time() 함수의 6번째 줄에서 바뀝니다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/cputime.c
1 void account_user_time(struct task_struct *p, u64 cputime)
2 {
3 int index;
4
5 /* Add user time to process. */
6 p->utime += cputime;

이번에는 stime 필드를 살펴보겠습니다.

u64 stime

커널 모드에서 프로세스가 실행한 시각을 저장합니다. 이 필드는 다음 코드와 같이 account_system_index_time() 함수에서 변경됩니다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/cputime.c
01 void account_system_index_time(struct task_struct *p,
02        u64 cputime, enum cpu_usage_stat index)
03 {
04 /* Add system time to process. */
05 p->stime += cputime;
06

마지막으로 sched_info.last_arrival 필드를 봅시다.

struct sched_info sched_info.last_arrival
---
이 구조체는 10장 ‘프로세스 스케줄링’에서 상세히 다룹니다.
---

sched_info 필드는 프로세스 스케줄링 정보를 저장합니다. 이 가운데 last_arrival은 프로세스가 마지막에 CPU에서 실행된 시간을 나타냅니다. 그렇다면 sched_info.last_arrival 필드는 언제 변경될까요?  다음 코드를 보면서 이를 확인해 봅시다. 

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/stats.h
01 static void sched_info_arrive(struct rq *rq, struct task_struct *t)
02 {
03 unsigned long long now = rq_clock(rq), delta = 0;
04
05 if (t->sched_info.last_queued)
06 delta = now - t->sched_info.last_queued;
07 sched_info_reset_dequeued(t);
08 t->sched_info.run_delay += delta;
09 t->sched_info.last_arrival = now;

09번째 줄을 보면 현재 시각 정보인 now를 ‘t->sched_info.last_arrival’에 저장합니다. 이처럼 sched_info.last_arrival 필드는 sched_info_arrive() 함수의 9번째 줄에서 업데이트됩니다. 

그럼 sched_info_arrive() 함수는 언제 호출될까요? context_switch() 함수 내에서 컨텍스트 스위칭를 수행하기 직전에 prepare_task_switch() 함수를 호출합니다. 이 prepare_task_switch() 함수가 호출하는 함수들을 따라가다 보면 sched_info_arrive() 함수가 호출됩니다. 

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/core.c
01 static __always_inline struct rq *
02 context_switch(struct rq *rq, struct task_struct *prev,
03        struct task_struct *next, struct rq_flags *rf)
04 {
05 struct mm_struct *mm, *oldmm;
06
07 prepare_task_switch(rq, prev, next);

context_switch() 함수를 시작으로 다음 순서로 함수를 호출해 sched_info_arrive() 함수가 실행됩니다.

context_switch()
prepare_task_switch()
sched_info_switch()
__sched_info_switch()
sched_info_arrive()

코드 분석 내용을 정리하면 context_switch() 함수 내에서 컨텍스트 스위칭을 수행하기 직전에 위와 같은 함수 흐름으로 sched_info_arrive() 함수가 호출됩니다. 커널은 sched_info_arrive() 함수에서 프로세스의 실행 시간을 업데이트합니다.

---
크래시 유틸리티 프로그램으로 ps -l 명령어를 입력하면 다음과 같이 프로세스가 실행된 시각을 나노초 단위로 볼 수 있습니다. 참고로 크래시 유틸리티(Crash Utility)는 커널 크래시를 디버깅할 수 있는 유틸리티 프로그램입니다. 레드햇의 앤더슨이란 분이 이끌어가는 오픈소스 프로젝트로서 자세한 사항은 다음 URL을 참고하세요.

URL: https://people.redhat.com/anderson/crash_whitepaper/

크래시 유틸리티는 리눅스 커널 개발자들이 자주 활용하는 프로그램이니 잘 알아두면 좋습니다. 

다시 주제로 돌아가 크래시 유틸리티 프로그램으로 ps -l 명령어를 입력해 프로세스가 실행된 시각을 확인하는 예시를 소개하겠습니다. 다음 URL에는 크래시 유틸리티의 포럼에서 프로세스 실행 시간을 확인하는 내용이 담겨 있습니다. 

https://www.redhat.com/archives/crash-utility/2015-January/msg00024.html
1 > crash> p jiffies
2 > jiffies = $9 = 5310085968
3 > crash>
4 > 
5 > crash> ps -l
6 > ..
7 > [4058835599089874] PID: 4136 TASK: ffff8801309ce640 CPU: 4 COMMAND: "kcapwdt" 

5번째 줄에서 ps 명령어에 -l 옵션을 추가해서 입력하니 7번째 줄과 같이 나노초 단위로 프로세스 실행 시각 정보를 알 수 있습니다.

이어서 7번째 줄을 해석하면 다음과 같습니다.

태스크 디스크립터를 나타내는 task_struct 구조체의 주소가 ffff8801309ce640인 "kcapwdt" 프로세스(PID: 4136)가 4058835599089874 시각에 실행됐다.

4058835599089874라는 시간 정보는 “kcapwdt” 프로세스의 태스크 디스크립터인 task_struct 구조체의 필드인 sched_info.last_arrival에 저장된 값입니다. 
---


#프로세스

프로세스 소개 
프로세스 확인하기  
프로세스는 어떻게 생성할까?  
유저 레벨 프로세스 실행 실습  
커널 스레드  
커널 내부 프로세스의 생성 과정   
프로세스의 종료 과정 분석  
태스크 디스크립터(task_struct 구조체)  
스레드 정보: thread_info 구조체  
프로세스의 태스크 디스크립터에 접근하는 매크로 함수  
프로세스 디버깅  
   * glibc의 fork() 함수를 gdb로 디버깅하기  


"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)


# Reference: For more information on 'Linux Kernel';

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2





핑백

덧글

댓글 입력 영역