Process Priority

커널에서 프로세스의 우선순위에 대한 매크로상수는 prio.h에 정의되어있다.

include/linux/sched/prio.h

#define MAX_NICE        19
#define MIN_NICE        -20
#define NICE_WIDTH      (MAX_NICE - MIN_NICE + 1)

#define MAX_USER_RT_PRIO        100
#define MAX_RT_PRIO             MAX_USER_RT_PRIO

#define MAX_PRIO                (MAX_RT_PRIO + NICE_WIDTH)
#define DEFAULT_PRIO            (MAX_RT_PRIO + NICE_WIDTH / 2)

#define NICE_TO_PRIO(nice)      ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio)      ((prio) - DEFAULT_PRIO)

#define USER_PRIO(p)            ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p)       USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO           (USER_PRIO(MAX_PRIO))

위 헤더파일에 정의된 값을 보면 커널 관점에서의 최대 priority(MAX_PRIO)는 140이다. 그리고 0부터 139까지의 범위를 가지는 것을 볼 수 있다. RT태스크의 최대 priority는 100이다.

#define MAX_USER_RT_PRIO        100
#define MAX_RT_PRIO             MAX_USER_RT_PRIO
#define MAX_PRIO                (MAX_RT_PRIO + NICE_WIDTH)

유저프로세스의 nice값의 범위는 -20 ~ 19이다. 그리고 유저프로세스의 nice값은 커널에서는 100 - 139의 범위의 priority로 변환되어 사용된다.(SCHED_NORMAL/SCHED_BATCH)

#define DEFAULT_PRIO            (MAX_RT_PRIO + NICE_WIDTH / 2)
#define NICE_TO_PRIO(nice)      ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio)      ((prio) - DEFAULT_PRIO)

유저프로세스가 사용가능한 최대 priority는 100으로 정해져있다. 이런 제한은 커널스레드가 늘 유저프로세스보다 높은 우선순위를 갖게 해준다.

#define MAX_USER_RT_PRIO        100

저절로 나머지 0 - 99 범위의 priority는 RT태스크의 priority를 표현하는데 사용된다. 높은 우선순위값은 실제로는 낮은우선순위를 나타낸다.

priority를 나타내는 3개의 변수

task_struct에는 priority와 관련된 변수가 3가지가 있다.

  • prio
  • normal_prio
  • static_prio

task_struct 구조체는 태스크의 우선순위를 나타내는 3가지의 변수를 가지고 있다.

struct task_struct {
        ...
        int prio, static_prio, normal_prio;
        ...

user process의 nice가 변경되면 어떻게 될까?

user process는 nice() 함수나 nice command등으로 nice값을 변경할 수 있다.

nice overview

nice() or nice command
-> nice syscall
---> clamp increment value from userspace
---> clamp nice value from increment
---> set_user_nice()
-----> p->static_prio = NICE_TO_PRIO(nice)
-----> p->prio = effective_prio(p)
-------> p->normal_prio = p->static_prio

커널내부에서는 가장먼저 nice 시스템콜이 호출된다. 인자로 넘겨진 increment값은 태스크의 static_prio를 nice단위로 변환값에 더해져 새로운 nice값을 만든다.

SYSCALL_DEFINE1(nice, int, increment)
{
        ...
        increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH);
        nice = task_nice(current) + increment;
        nice = clamp_val(nice, MIN_NICE, MAX_NICE);
        set_user_nice(current, nice);
        ...
}
  • increment값의 범위는 -40 ~ 40
  • nice값의 범위는 -20 ~ 19

새롭게 계산된 태스크의 nice 값은 set_user_nice()를 통해 태스크의 task_struct 구조체에 반영된다. nice값이 priority관련 변수에 반영되는 과정을 살펴보자.

void set_user_nice(struct task_struct *p, long nice)
{
        ...
        p->static_prio = NICE_TO_PRIO(nice);
        ...
        p->prio = effective_prio(p);
        ...
}

전달된 nice 값을 priority로 변환해서 태스크의 static_prio에 설정한다. effective_prio()는 realtime priority를 가진 태스크가 아니라면 태스크의 normal_prio를 그대로 리턴한다. normal_prio가 어떤값으로 설정되는지를 확인하기 위해 effective_prio()를 살펴보자.

static int effective_prio(struct task_struct *p)
{
        p->normal_prio = normal_prio(p);
        if (!rt_prio(p->prio))
                return p->normal_prio;
        return p->prio;
}

static inline int normal_prio(struct task_struct *p)
{
        if (task_has_dl_policy(p))
                prio = MAX_DL_PRIO-1;
        else if (task_has_rt_policy(p))
                prio = MAX_RT_PRIO-1 - p->rt_priority;
        else
                prio = __normal_prio(p);
        return prio;
}

static inline int __normal_prio(struct task_struct *p)
{
        return p->static_prio;
}

CFS태스크의 경우 normal_prio()는 태스크의 static_prio를 그대로 리턴해준다. 이 값이 그대로 normal_prio에도 설정된다는 말이다.

정리하자면 이렇다. static_prio는 userspace에서 전달된 값으로 갱신된 nice값을 priority로 변환한 값으로 설정된다. 나머지 normal_prio, prio는 동일한 값으로 설정된다.

태스크가 rt priority로 boost-up된 경우는 prio는 변경된 static_prio를 사용하지 않고 예전의 prio를 그대로 사용한다.

RT태스크의 경우도 prio는 예전 prio를 그대로 사용한다. normal_prio는 변경된 static_prio 대신 MAX_RT_PRIO - 1 - rt_priority로 설정된다.

이건 표로 정리해야겠다...

priority의 상속

fork된 자식 태스크는 부모에게서 priority관련된 값을 상속받는다.

  • p->static_prio = parent->static_prio
  • p->prio = parent->normal_prio
    • do not leak PI boosting prio to the child
  • p->normal_prio = parent->normal_prio ???

관련된 내용은 sched_fork()를 보자...

results matching ""

    No results matching ""