안녕하세요,
최근 linux kernel에서 프로그래밍 할 일이 있어서, linux-2.6.31.4 버전에서 CFS 프로세스 스케줄러관련 소스를 분석하고 있습니다.
CFS에서는 time slice가 명시적으로 없고 동적으로 계산을 해서 사용하는 듯 하네요.
제가 프로그래밍 하면서 schedule()함수에서 time slice가 동적으로 필요한데 어떻게 구해야 할지 잘 모르겠네요.
아래와 같이 get_task_timeslice()함수로 작성을 해봤는데 맞는지 잘 모르겠네요, 혹시 아시는분 있으시면 알려주세요.
그리고 추가로, Linux kernel 관련해서 질문질답시 적절히 이용할 수 있는 해외 싸이트 아시면 좀 알려주세요.
=====================================================================
/* ACTXSW Return the default timeslice of a process. -jh 20100331 */
unsigned long inline
get_task_timeslice(struct task_struct* p)
{
unsigned long time_slice;
int retval;
retval = -ESRCH;
read_lock(&tasklist_lock);
if (!p)
goto out_unlock;
retval = security_task_getscheduler(p);
if (retval)
goto out_unlock;
/*
* Time slice is 0 for SCHED_FIFO tasks and for SCHED_OTHER
* tasks that are on an otherwise idle runqueue:
*/
time_slice = 0;
if (p->policy == SCHED_RR) {
time_slice = DEF_TIMESLICE;
} else if (p->policy != SCHED_FIFO) {
struct sched_entity *se = &p->se;
unsigned long flags;
struct rq *rq;
rq = task_rq_lock(p, &flags);
if (rq->cfs.load.weight)
time_slice = NS_TO_JIFFIES(sched_slice(&rq->cfs, se));
task_rq_unlock(rq, &flags);
}
read_unlock(&tasklist_lock);
return time_slice;
out_unlock:
read_unlock(&tasklist_lock);
return retval;
}
asmlinkage void __sched schedule(void)
{
......
unsigned long time_slice = get_task_timeslice(current);
....
}
=======================================================================
좋은 하루 되세요.
댓글 10
-
배병일
2010.04.30 15:33
-
배병일
2010.04.30 16:54
http://warnus.tistory.com/391 에 관련 내용이 나오고 있네요.
시간 통계를 통해서 fair 하게 분배되도록 동적으로 부여해준다는 그런 얘기가 중간 부분쯤에 나오네요.
http://barrioskmc.egloos.com/1797590 에도요.
CFS의 big idea는 각 쓰레드들이 얼마나 많은 시간동안 실행을 했는지를 쓰레드의 weight으로 scale하여 유지하는것이다. 즉, niceness0 쓰레드는 수행시간을 1ns단위로 scale한다. 반면, niceness5 를 가진 쓰레드는실행시간을 대략 3ns단위로 scale하게 된다.
라네요.
-
김재호
2010.04.30 16:44
네, 답변감사합니다.
O(1) 스케줄러일때는 time slice가 명시적으로 있어서 task가 CPU를 얼마나 사용할 것인지를 알수가 있는데 CFS로 바뀌면서 time slice가 명시적으로 나타나 있지 않아서 현재 CPU를 사용할 task가 얼마 만큼의 시간을 부여 받았는지 알고 싶어서 입니다.
-
김남형
2010.05.01 11:05
nice (weight) 값에 따라 정적으로 할당된 (default) time slice 값만을 알려고 한다면
위에서 작성하신대로 sched_slice() 함수를 이용하면 될 것 같습니다만
하지만 알고계신 것처럼 time slice는 ns 단위로 관리되기 때문에
jiffy (ms) 단위로 변환하면 많은 정보가 손실될 수 있습니다.
(nice 값 1단계마다 weight는 1.25배씩 변경됩니다.)
만약 할당된 time slice 중에서 task가 사용하고 실제로 남아있는 값을 알려고한다면
이 값에서 sum_exec_runtime 값을 뺀 값을 이용해야 할 것입니다.
덧붙여 코드에 대해서 몇가지 말씀드리면
tasklist_lock은 말 그대로 process의 list를 탐색할 때 사용하는 lock이므로
(더구나 점차 rcu로 대체하고 있는 추세이니) 여기선 사용할 필요가 없어 보입니다.
단순히 현재 task에 대한 참조를 유지하고 싶은 경우라면 get_task_struct()를 이용하여
참조 카운트를 증가시켜두면 될 것 같습니다.
또한 user level에서 접근하는 코드가 아니니 security_task_getscheduler() 호출도 불필요해 보이고
CFS에서 관리하는 태스크의 목록 만을 살펴보고 싶다면 SCHED_FIFO policy가 아닌지를 검사하기 보다는
SCHED_NORMAL 혹은 SCHED_BATCH인지를 검사하거나
task의 sched_class가 &fair_sched_class인지를 검사하는 것이 더 나아 보입니다.
-
이정승
2010.09.01 20:03
sysctl_sched_min_granularity (minimal preemption granularity)가 4ms 설정되어 있다는 것은.
task가 최소한 4ms 안에는 선점당하지 않게 하겠다는 이야기 입니다.
(너무 빈번한 스케쥴링이 되는 것을 방지하기 위함이겠지요)
또한 말씀 주신 HZ=100 일 경우에는
실제로는 최소 스케쥴링 단위가 10ms 가 되게 됩니다.(Dynamic tick이나 , tickless kernel 이 아닌 경우)
task의 timeslice 만료 판단 후 스케쥴링 할 지 여부의 판단은
매 timer interrupt 발생 시에 하게 되는데(scheduler_tick) HZ 100인 경우에는 그 주기가 10ms 가 되기 때문이죠.
CFS가 nanosecond granulariity라고 하지만 실제로는 .....
-
김재호
2010.05.04 18:20
제 시스템의 HZ는 100이네요,
소스에서 sysctl_sched_min_granularity (minimal preemption granularity)가 4ms 이구, time slice가 1~2ms가 정상이라는 말씀이신가요? time slice가 너무 적어서 conttext switch가 자주 발생하지 않을까요? 저는 ns단위의 값인 7~20ms이 정상이라고 생각했는데, 좀더 봐야 겠네요. 의견 감사합니다~.
-
김남형
2010.05.04 15:27
ns -> ms 변경 시 그렇게 많은 손실이 일어났다면 문제가 있는 것입니다.
아마 1~2ms가 정상일 것입니다. (sysctl_sched_min_granularity)
HZ 값을 확인해 보시기 바랍니다.
그리고 sum_exec_runtime은 제가 착각한 것 같네요.. 말씀하신대로 누적 값이 맞고
time slice에서 sum_exec_runtime이 아니라 do_task_delta_exec()의 결과를 빼야할 것 같습니다.
ns = sched_slice(rq, &p->se) - do_task_delta_exec(p, rq);
-
김재호
2010.05.03 23:41
네, 안녕하세요~ 남형님.
먼저 장문의 답변 감사드립니다. 그리고 소스코드 팁도요~
time slice가 ns단위로 관리된다는 것을 제가 간과했네요, 사실 위의 코드로 실행했을때 time_slice변수 출력시 1~2ms으로 출력되어서 time slice를 이것밖에 할당받지 않나 무지 고민했었는데 ns단위로 변경시키니 역시 7~20ms 을 부여받네요. ns-->ms로 변경시 이렇게 많은 손실이 발생할줄은 정말 몰랐습니다. 무지 헤맬뻔 했네요.
근데 위에서 언급한 get_task_timeslice()함수는 사실 kernel/sched.c 소스에 있는 sys_sched_rr_get_interval() 시스템 콜 함수를 그대로 가져다가 사용한 것입니다. 이 함수에서도 마찬가지로 NS_TO_JIFFIES()를 이용하여 ns를 jiffy(ms)단위로 바꾸고 있습니다. 이런 경우 이 시스템 호출을 사용하면 많은 문제가 발생할거 같은데 아닌가요? 그리고 그 외 조언해주신 코드도 그대로 사용한 것입니다.
그리고 할당된 time slice에서 task가 사용하고 남은 시간이 sum_exec_runtime이라고 하셨는데 이 값을 얻기 위해서 커널에 있는 아래 함수를 사용했는데 거의 대부분의 task에서 할당받은 time slice보다 휠씬 큰 sec단위의 값들이 나옵니다. 아마도 task가 실행한 전체 누적값이 아닌가 합니다. 현재 할당받은 time slice부터 실행한 시간의 의미로 말씀하신거 맞으시죠? 아마 좀 더 찾아보면 있을것 같기도 찾게되면 알려드릴께요.
/*
* Return accounted runtime for the task.
* In case the task is currently running, return the runtime plus current's
* pending runtime that have not been accounted yet.
*/
unsigned long long task_sched_runtime(struct task_struct *p)
{
unsigned long flags;
struct rq *rq;
u64 ns = 0;rq = task_rq_lock(p, &flags);
ns = p->se.sum_exec_runtime + do_task_delta_exec(p, rq);
task_rq_unlock(rq, &flags);return ns;
}덕분에 많은 도움 되었습니다. ^^
-
남용우
2010.05.03 13:49
user land 에서 time slice 를 알고싶으시면, man sched_rr_get_interval해보세요.
그리고 kmod 시에서는 위의 syscall을 보시면 될꺼같습니다.
-
김재호
2010.05.03 23:44
위의 댓글에서 처럼 남용우님이 말씀하신 sched_rr_get_interval() 시스템 호출 그대로 사용해서 get_task_timeslice() 작성한 겁니다.
근데 이 함수에서 받아오는 time_slice를 그대로 사용하면 1~2ms으로만 나오고 NS_TO_JIFFIES() 매크로 사용 안하고 ns 단위로 사용하면 7~20ms 되요~
답변 감사합니다.
.
O'Reilly 책 보면 설명이 나와있다고 하는 거 같은데요.. 'ㅁ'
기본적으로는 100ms 로 제공하고 있다고 하는듯..
가용범위는 5~800ms
판단 기준은 시스템이 I/O 에 치중하는가, CPU 에 치중하는가,
CPU 가 캐쉬를 갈아 쓰는데 소요되는 시간은 대략 어느정도인가..
Context Switching 소요시간은.. 등등이 고려된다고 합니다.