Home [Linux System Programming] Ch06 고급 프로세스 관리
Post
Cancel

[Linux System Programming] Ch06 고급 프로세스 관리

[Ch06 고급 프로세스 관리]

  • 5장에서는 프로세스가 무엇인지, 생성, 제어, 종료에 관한 시스템 콜과 관련된 시스템에 대해 알아봤음.
  • 이번 장에서는 리눅스 프로세스 스케줄러와 스케줄링 알고리즘을 알아본다.

6.1 프로세스 스케줄링

  • 프로세스 스케줄러는 커널의 서브 시스템으로써 유한한 리소스인 프로세서의 시간을 시스템 내의 프로세스에 나눠준다.
    • 즉, 다음에 실행할 프로세스를 선택하기 위한 커널의 구성요소임.
  • 실행 가능한 프로세스
    • 블록되지 않은 프로세스
  • 블록된 프로세스
    • 자고 있거나, 커널로부터 입출력을 기다리고 있는 프로세스
  • 프로세서의 개수보다 실행 가능한 프로세스가 더 많이 존재할 때는 스케줄러가 필요함

  • 선점형 멀티태스킹
    • 리눅스
    • 다른 프로세스를 위해 실행 중인 프로세스를 멈추는 행위를 선점이라고 함.
    • 스케줄러가 선점하기 전까지 프로세스에 허락된 실행 시간을 프로세스 타임 슬라이스라고 한다.
  • 비선점형 멀티태스킹
    • 프로세스가 스스로 실행을 멈추기 전까지 계속 실행함.
    • 자발적으로 실행을 잠시 쉬는 것을 양보라고 함
    • 너무 오래 실행되는 그런 단점때문에 최신 OS는 거의 선점형 을 사용한다.

6.1.1 타임 슬라이스

  • 스케줄러가 각 프로세스에 할당하는 타임 슬라이스는 시스템 전반의 동작 방식과 성능에 관한 중요한 변수이다.
  • 타임 슬라이스가 너무 크다면 프로세스는 다음 실행 시간까지 오래 기다려야 하며, 동시 수행 능력을 떨어트림.
  • 반대로 너무 작으면 잦은 프로세스 전환으로 인해 일시적인 지역성과 같은 장점을 잃게 됨.
  • 목적에 따라 크기를 다르게한다.
    • 시스템이 처리할 수 있는 용량을 극대화하여 성능 향상을 하려고 큰 슬라이스를 사용함.
    • 혹은 빠른 응답속도를 확보하기 위해서 작은 슬라이스를 사용함.
    • → 이상적인 사이즈를 결정하기가 어려움!

6.1.2 입출력 위주 프로세스와 CPU 위주 프로세스

  • 사용 가능한 타임 슬라이스를 끊임없이 계속 사용하는 프로세스를 CPU 위주 프로세스라고 한다.
    • 스케줄러에서 허락하는 시간을 모두 사용함
  • 예시

    • 무한루프
    • 과학계산, 수학연산, 이미지 처리 등
    1
    2
    3
    
    // 100% processor-bound
    while (1)
      ;
    
  • 실행 시간보다 리소스를 사용하기 위해 기다리는 시간을 더 많이 사용하는 프로세스를 IO 위주 프로세스 라고 한다.

    • 네트워크 입출력, 파일 입출력 기다림.
    • cp, mv 같은 파일 유틸리티 , User GUI 등.
  • 각각의 특성에 맞게 스케줄러를 선택해야함.
  • CPU 위주
    • 일시적인 지역성을 통해 캐시 적중률을 최대화하고 작업을 빨리 끝내기 위해 큰 타임 슬라이스를 사용
  • IO 위주

    • 입출력 요청을 보내기까지 아주 짧은 시간이면 충분하고 대부분의 시간을 커널 리소스를 얻기 위해 블록되기 때문에 큰 슬라이스가 필요없음.
  • 현실에서는 CPU와 입출력을 같이 사용함

6.1.3 선점형 스케줄링

  • 전통적인 유닉스 프로세스 스케줄링에서 모든 실행 가능한 프로세스는 타임 슬라이스를 할당받음
  • 프로세스가 주어진 타임 슬라이스를 다 소진하면 커널은 그 프로세스를 잠시 멈추고 다른 프로세스를 실행.
  • → 모든 프로세스는 자신보다 우선순위가 높은 프로세스가 있을지라도 그 프로세스가 타임 슬라이스를 모두 소진하거나 블록된다면 결국 실행될 기회를 얻게됨.
  • → 모든 프로세스는 반드시 계속 진행되어야 한다는 규칙을 만들어냄

6.2 CFS 스케줄러

  • Completely Fair Scheduler
  • CFS 전의 전통 유닉스 시스템들은 우선순위타임 슬라이스 라는 변수를 사용해서 스케줄링을 구현했음
  • CFS는 타임 슬라이스 대신 CPU 시간의 일부를 각 프로세스에 할당한다.
    • N개의 프로세스에 각각 1/N 만큼의 CPU 시간을 할당한다.
    • 그리고 이를 각 프로세스의 nice 값에 따라 가중치를 준다.
    • nice 값이 기본값인 0을 그대로 사용하는 프로세스의 가중치는 1이며, 따라서 할당받는 CPU 시간에는 변화가 없다.
    • 기본값보다 적은 nice 값을 사용하는 (우선순위가 높은) 프로세스는 CPU 시간을 더 많이 할당 받음
  • 각 프로세스가 수행될 시간을 결정하기 위해 CFS 스케줄러는 프로세스 별로 가중치가 적용된 값을 한정된 시간(Target Latency) 로 나눈다.
    • 시스템의 스케줄링 레이턴시를 나타냄.
    • 예시
      • Target Latency : 20 밀리초
      • 5개의 프로세스
      • → 각 4밀리초
      • But, 프로세스가 많다면 Context Switching Overhead 때문에 일시적인 지역성의 효과는 줄어들고 시스템 전체 처리 성능은 매우 지장받음
        • →이런 상황을 피하기 위해 CFS는 최소단위 (Minimum Granularity) 를 사용함
  • 최소 단위
    • 프로세스가 실행되는 최저 시간 단위
    • 모든 프로세스는 할당된 CPU 시간과 관계없이 최소 단위만큼은 실행된다는 의미
    • 근데 이를 사용하면 공정성이 무너짐!
      • → 납득할 수 있는 만큼의 평범한 상황에서는 최소 단위가 적용되지 않고, Target latency 만으로 공정성을 유지할 수 있다.

6.3 프로세서 양보하기

  • 리눅스는 선점형 멀티태스킹 운영체제지만, 프로세스가 명시적으로 실행을 양보해서 스케줄러가 새로운 프로세스를 실행하도록 하는 시스템 콜을 제공한다.
1
2
3
#include <sched.h>

int sched_yield (void);
  • sched_yield() 를 호출하면 현재 실행 중인 프로세스를 잠시 멈춘 다음 스케줄러가 다음에 실행할 새로운 프로세스를 선택하도록 한다.
  • 다른 실행 가능한 프로세스가 없으면 sched_yield() 를 호출한 프로세스의 실행이 즉시 재개됨.
    • → 이런 불확실성과 일반적으로 더 나은 대안에 대한 믿음 때문에 이 시스템 콜은 잘 안씀.

6.3.1 적당한 사용법

  • 리눅스 커널은 가장 효율적이고 최적의 스케줄링 결정을 내리기에 부족함이 없음
  • → 일개 어플리케이션이 무엇을 언제 선점해야 할지 결정하는 것보다 커널이 훨씬 더 나은 결정을 할 수 있음 !!
  • 쓰는 경우가 있긴 하지만 잘 안씀.

6.4 프로세스 우선 순위

  • nice 값은 프로세스가 be nice 하기를 바라면서 만들어짐.
  • -20 ~ 19 의 값을 가지고 있다.
  • 값이 높을 수록 Nice 하기때문에 우선순위가 낮음.

6.4.1 nice()

1
2
3
#include <unistd.h>

int nice (int inc);
  • 호출이 성공하면 프로세스의 nice 값을 inc로 지정하고 새롭게 업데이트 된 값을 리턴한다.
  • 오직 CAP_SYS_NICE 값을 가진 프로세스만 negative 값을 받을 수 있다.
    • 보통 root 만 이럼.
  • 결과적으로 non root 프로세스는 오직 우선순위를 낮출 수만 있음.
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    
    int ret;
    
    errno = 0;
    ret = nice (10);    /* increase our nice by 10 */
    if (ret == 1 && errno != 0)
            perror ("nice");
    else
            printf ("nice value is now %d\n", ret);
    
  • inc 값에 0을 넣으면 프로세스의 현재 nice 값을 알 수 있다.

6.4.2 getpriority() 와 setpriority()

1
2
3
4
5
#include <sys/time.h>
#include <sys/resource.h>

int getpriority (int which, int who);
int setpriority (int which, int who, int prio);
  • which
    • PRIO_PROCESS
    • PRIO_PGRP
    • PRIO_USER
    • 각각 who 값이 pid, pgid, uid를 판단한다.
  • 만약 who 가 0이면 현재 pid,pgid, uid를 받아옴.
  • getpriority() 는 지정된 프로세스들 중에서 가장 높은 우선순위를 리턴함.
  • setpriority()prio 값으로 특정된 프로세스들 전부를 지정함.
  • 예시
    • 현재 프로세스의 우선순위를 출력한다. ```c int ret;

    ret = getpriority (PRIO_PROCESS, 0); printf (“nice value is %d\n”, ret);

    1
    2
    3
    4
    5
    6
    7
    
    - 현재 프로세스 그룹의 전체 프로세스의 우선순위를 10으로 지정한다.
    ```c
    int ret;
    
    ret = setpriority (PRIO_PGRP, 0, 10);
    if (ret == −1)
            perror ("setpriority");
    

6.4.3 I/O 우선순위

  • 기본적으로 I/O 스케줄러는 프로세스의 nice 값을 기준으로 I/O 우선순위를 결정한다.
1
2
int ioprio_get (int which, int who)
int ioprio_set (int which, int who, int ioprio)
  • glibc 는 지원하지 않음.

6.5 프로세서 친화

  • 리눅스는 싱글 시스템에서 멀티프로세서를 지원함.
  • 멀티프로세싱 머신에서 프로세스 스케줄러는 어떤 프로세스가 각 CPU에서 돌 것인지 판단해야만 한다.
  • 프로세스가 놀 동안 CPU가 놀고 있으면 안됨.
  • 프로세스가 한 CPU에 스케줄링 되고 다음에 다시 스케줄링 될 때 같은 CPU에 되어야함.
    • migrating 부분에서 이점이 있음
  • 가장 큰 비용은 migration 할 때 캐쉬의 영향이다.
  • 프로세스 스케줄러는 프로세스를 특정 CPU에 오랫동안 두어야함.

6.5.1 sched_getaffinity() 와 sched_setaffinity()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#define _GNU_SOURCE

#include <sched.h>

typedef struct cpu_set_t;

size_t CPU_SETSIZE;

void CPU_SET (unsigned long cpu, cpu_set_t *set);
void CPU_CLR (unsigned long cpu, cpu_set_t *set);
int CPU_ISSET (unsigned long cpu, cpu_set_t *set);
void CPU_ZERO (cpu_set_t *set);

int sched_setaffinity (pid_t pid, size_t setsize,
                       const cpu_set_t *set);

int sched_getaffinity (pid_t pid, size_t setsize,
                       cpu_set_t *set);
  • sched_getaffinity() 는 프로세스 pid의 CPU 친밀도를 얻고 cpu_set_t 타입의 값에다가 저장한다.
  • 만약 pid가 0이면 호출은 현재 프로세스의 affinity를 얻어옴.
  • setsizecpu_set_t 타입인데 타입의 사이즈 변화에 사용된다.
  • 예제
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    cpu_set_t set;
    int ret, i;
    
    CPU_ZERO (&set);
    ret = sched_getaffinity (0, sizeof (cpu_set_t), &set);
    if (ret == 1)
            perror ("sched_getaffinity");
    
    for (i = 0; i < CPU_SETSIZE; i++) {
            int cpu;
    
            cpu = CPU_ISSET (i, &set);
            printf ("cpu=%i is %s\n", i,
                    cpu ? "set" : "unset");
    }
    
    • 현재 프로세스의 affinity 를 출력한다.
      1
      2
      3
      4
      5
      6
      
      cpu=0 is set
      cpu=1 is set
      cpu=2 is unset
      cpu=3 is unset
      ...
      cpu=1023 is unset
      
    • 두개의 프로세스가 돌아가는 상태일 때의 출력값
    • 만약 0,1 중에서 0만 쓰고 싶다면,, ```c cpu_set_t set; int ret, i;

    CPU_ZERO (&set); /* clear all CPUs / CPU_SET (0, &set); / allow CPU #0 / CPU_CLR (1, &set); / disallow CPU #1 */ ret = sched_setaffinity (0, sizeof (cpu_set_t), &set); if (ret == −1) perror (“sched_setaffinity”);

    for (i = 0; i < CPU_SETSIZE; i++) { int cpu;

    1
    2
    3
    4
    5
    6
    7
    
        cpu = CPU_ISSET (i, &set);
        printf ("cpu=%i is %s\n", i,
                cpu ? "set" : "unset"); } ``` # 6.6 실시간 시스템 - 실시간 : Time Limit 이 존재함. - Low latency or 빠른 응답시간 : 빠르면 빠를수록 좋은 것 - 예제   - Task A는 특정 기능을 1초안에 수행하지 않으면 전체 시스템에 치명적인 위해를 가할 수 있음.
    - → Time limit : 1초.
    - → 1초라는 시간을 준수하면서 특정 기능을 수행하는 것을 `실시간`이라고 함   - Task B는 기능을 수행함에 있어 Time Limit 은 없다.
    - → 빠르면 좋긴하겠지만 느리다고 해서 치명적인 손상을 입히는 것은 아님. - 리눅스 기반의 Real-time OS   - 리눅스 기반의 RTOS와 일반 리눅스 OS는 크게 차이가 없다.
    - 모든 OS는 preemptive 한 작업 수행을 보장함.   - **일반 리눅스는 interrupt가 들어왔을 때 현재 수행 중인 시스템 콜을 끝낸 뒤 Context switching**이 일어나지만, **RT 커널 기반의 리눅스는 현재 작업 중인 프로세스의 시스템 콜 수행마저도 Interrupt를 걸어 작업 Switching에 대한 Latency를 최소화**한다
    

Untitled

  • 일반 프로세스 레벨에서는 nice/renice를, RT 프로세스에서는 chrt를 쓰면됨.

6.6.1 Hard Real-Time VS Soft Real-Time System

  • hard real-time system
    • os의 데드라인을 무조건 따라야함.
    • 데드라인을 넘어서는것은 제약적인 실패이고 큰 버그를 야기함.
    • 예제
      • ABS 시스템, 총기 시스템, 의료 장비, 시그널 프로세싱..
  • soft real-time system
    • 데드라인을 넘는 것을 크리티컬하다고 생각하지 않음.
    • 예제
      • 비디오 프로세싱 애플리케이션
        • 데드라인이 넘어서 조금의 프레임이 깨져도 크게 영향이 없다.

6.6.2 Latency, Jitter and Deadlines

  • Latency
    • 잠재적 시간 지연
    • 응답에 대한 실행이 나타나기 까지의 시간을 의미
    • 지연이 os 데드라인보다 작거나 같다면 잘 동작하는 것이다.
  • Jitter
    • 응답간의 시차
    • 지연 요소의 변동량. 즉, Latency 나 delay의 변화량 수준
    • 연속적인 이벤트 간의 시간 편자는 레이턴시가 아니라 지터임.

6.6.3 Linux’s Real-Time Support

  • 리눅스는 시스템 콜을 지원하여서 soft real-time 애플리케이션을 지원한다.

6.6.4 Linux Scheduling Policies and Priorities

  • 리눅스는 두가지 스케줄링 정책을 제공함.
  • 로부터 매크로를 제공받는다.
    • SCHED_FIFO, SCHED_RR, SCHED_OTHER
  • 모든 프로세스들은 nice 값이랑 별개로 static priority 를 가지고 있음.
    • 기본적으로 0이다.
  • 실시간 프로세스에서는 1-99까지의 값을 가진다.
  • 일반적으로 SCHED_OTHER 를 사용함
    • 기본적으로 여러 프로세스 간 Time-sharing 방식(CFS Scheduler) 또는 우선순위 기반 스케줄링을 사용.
  • FIFO, RR
    • RT를 위한

FIFO 전략

  • FIFO는 timeslices가 없는 매우 심플한 실시간 전략이다.
  • 더 높은 우선순위를 가진 프로세스가 없는 한 계속 진행한다.
  • SCHED_FIFO 매크로를 사용함
  • 정책에 타임슬라이스가 없기 때문에 비교적 간단하다.
    • 프로세스가 가장 높은 우선순위에 있다면 항상 실행됨.
    • 프로세스가 블록되거나 sched_yield() 가 실행되거나, 더 높은 우선순위의 프로세스가 들어오기 전까지 계속 실행됨.
  • Q) 같은 우선순위의 프로세스들이 있다면?

Rount-Robin 전략

  • FIFO 클래스와 동일하지만 같은 우선순위일 때 추가적인 전략들이 있다.
  • SCHED_RR 매크로를 사용
  • 스케줄러는 RR-classed 프로세스 각각에 타임 슬라이스를 배정한다.
  • 프로세스가 자신의 타임슬라이스를 다 쓰면 스케줄러는 그 프로세스를 우선순위 리스트에 끝으로 보낸다.
  • 주어진 우선순위에 프로세스가 하나밖에 없다면 RR은 FIFO 와 동일하다.
  • RR 또한 같은 우선순위의 프로세스들 중에서 스케줄링을 계속 하기 때문에 FIFO와 거의 유사함.

Normal 전략

  • SCHED_OTHER 은 기복적인 스케줄링 전략을 대표한다. (default non-real-time class)
  • 모든 normal-classed 프로세스는 고정된 우선순위 값으로 0을 가지고 있다.
  • 결과적으로 동작중인 FIFO or RR 프로세스들은 normal 프로세스를 점유할 것이다.
  • 이 스케줄러는 nice 값을 사용함.

Batch 스케줄링 전략

  • SCHED_BATCH 는 Batch or idle 스케줄링 전략이다.
  • real-time과 어느정도는 반대된다.
  • 다른 프로세스들이 타임슬라이스를 다 썼더라도, 시스템에 동작 가능한 프로세스가 있다면 실행하지 않는다.

Linux 스케줄링 전략 설정하기

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <sched.h>

struct sched_param {
        /* ... */
        int sched_priority;
        /* ... */
};

int sched_getscheduler (pid_t pid);

int sched_setscheduler (pid_t pid,
                        int policy,
                        const struct sched_param *sp);
  • sched_getscheduler()sched_setscheduler() 를 사용해서 리눅스 스케줄링 값을 조작할 수 있다.
  • sched_getscheduler() 호출이 성공하면 pid 프로세스의 스케줄링 전략을 리턴한다.
  • pid가 0이면 호출을 실행한 프로세스의 스케줄링 정책이 반환됨.
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    int policy;
    
    /* get our scheduling policy */
    policy = sched_getscheduler (0);
    
    switch (policy) {
    case SCHED_OTHER:
            printf ("Policy is normal\n");
            break;
    case SCHED_RR:
            printf ("Policy is round-robin\n");
            break;
    case SCHED_FIFO:
            printf ("Policy is first-in, first-out\n");
            break;
    case -1:
            perror ("sched_getscheduler");
            break;
    default:
            fprintf (stderr, "Unknown policy!\n");
    }
    
  • sched_setscheduler() 를 호출하면 pid 에다가 policy를 넣어준다.
  • sp
    • 정책과 관련된 다른 파라미터들을 넣어주는 곳
    • shced_param
      • 구조 안의 유효한 값들은 policy에 따라 다름.
      • SCHED_RR과 SCHED_FIFO 는 sched_priority가 필요하고 SCHED_OTHER는 필요없음.
  • 예시
    • 이 예시는 RR 정책으로 static priority를 1로 수정한다. ```c struct sched_param sp = { .sched_priority = 1 }; int ret;

    ret = sched_setscheduler (0, SCHED_RR, &sp); if (ret == −1) { perror (“sched_setscheduler”); return 1; } ```

  • 스케줄링 정책을 지정할 때 SCHED_OTHER를 제외하고는 CAP_SYS_NICE 설정이 필요하다.

6.6.5 스케줄링 파라미터 설정하기

  • POSIX는 스케줄링 정책과 관련된 파라미터들을 설정하고 가져올 수 있게 하기 위해서 sched_getparam()sched_setparam() 을 지원한다.
1
2
3
4
5
6
7
8
9
10
11
#include <sched.h>

struct sched_param {
        /* ... */
        int sched_priority;
        /* ... */
};

int sched_getparam (pid_t pid, struct sched_param *sp);

int sched_setparam (pid_t pid, const struct sched_param *sp);
  • sched_getscheduler() 호출은 오직 스케줄링 정책만 리턴하지만 sched_getparam() 은 sp에다가 pid 프로세스와 연관된 스케줄링 파라미터들을 전달한다.
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    struct sched_param sp;
    int ret;
    
    ret = sched_getparam (0, &sp);
    if (ret == 1) {
            perror ("sched_getparam");
            return 1;
    }
    
    printf ("Our priority is %d\n", sp.sched_priority);
    
  • 만약 pid가 0이면 호출한 프로세스의 파라미터를 넘김.
  • sched_setscheduler() 또한 스케줄링 파라미터를 저장하긴 하지만, sched_setparam() 은 나중에 파라미터를 변경할 때 유용하다.
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    struct sched_param sp;
    int ret;
    
    sp.sched_priority = 1;
    ret = sched_setparam (0, &sp);
    if (ret == 1) {
            perror ("sched_setparam");
            return 1;
    }
    

유효한 우선순위 값 범위 결정하기

  • 리눅스에서는 1-99 값의 범위로 RT 스케줄링 정책을 지원한다.
  • 리눅스는 현재 유효한 우선순위 값을 알기 위해서 시스템 콜을 지원한다.
1
2
3
4
5
#include <sched.h>

int sched_get_priority_min (int policy);

int sched_get_priority_max (int policy);
  • 각각 유효한 우선순위 값의 최소값과 최대값을 리턴함.
  • policy
    • 스케줄링 정책을 넣어줌
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    int min, max;
    
    min = sched_get_priority_min (SCHED_RR);
    if (min == 1) {
            perror ("sched_get_priority_min");
            return 1;
    }
    
    max = sched_get_priority_max (SCHED_RR);
    if (max == 1) {
            perror ("sched_get_priority_max");
            return 1;
    }
    
    printf ("SCHED_RR priority range is %d - %d\n", min, max);
    

6.6.6 sched_rr_get_interval()

  • SCHED_RR은 time slice를 사용한다는 것을 제외하고 SCHED_FIFO와 동일하게 작동한다.
  • 만약 SCHED_RR 프로세스가 타임슬라이스를 다 썼다면, 스케줄러는 현재 우선순위의 동작 리스트 중 가장 마지막으로 간다.
  • 이런 방법에서는 같은 우선순위의 모든 SCHED_RR 프로세스들은 Rount robin 으로 순회한다.
  • 높은 우선순위의 프로세스들 (SCHED_FIFO of the same or higher priority) 은 SCHED_RR 프로세스의 타임슬라이스가 더 남았건 상관안하고 점유한다.

  • POSIX 는 주어진 프로세스의 timeslice의 길이를 얻을 수 있는 인터페이스를 제공한다.
1
2
3
4
5
6
7
8
#include <sched.h>

struct timespec {
        time_t  tv_sec;     /* seconds */
        long    tv_nsec;    /* nanoseconds */
};

int sched_rr_get_interval (pid_t pid, struct timespec *tp);
  • 호출이 성공하면 timespec 구조의 tp에다가 pid에 할당된 타임슬라이스의 길이를 저장한다.
  • POSIX에 따르면 이 함수는 SCHED_RR에만 사용할 수 있지만, 리눅스에서는 어떤 프로세스든 적용할 수 있다.
  • 예시
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    struct timespec tp;
    int ret;
    
    /* get the current task's timeslice length */
    ret = sched_rr_get_interval (0, &tp);
    if (ret == 1) {
            perror ("sched_rr_get_interval");
            return 1;
    }
    
    /* convert the seconds and nanoseconds to milliseconds */
    printf ("Our time quantum is %.2lf milliseconds\n",
            (tp.tv_sec * 1000.0f) + (tp.tv_nsec / 1000000.0f));
    
    • 만약 프로세스가 FIFO 로 돌고있다면 tv_sec과 tv_nsec는 둘 다 0이다.

6.6.7 Real-time 프로세스의 주의점

6.6.8 Determinism (결정론)

  • RT 프로세스는 결정론에 크게 좌지우지 한다.
  • RT 컴퓨팅에서 행동은 결정론적인데, 만약 같은 인풋을 받았을 때 항상 같은 양의 시간에 같은 결과를 만들어야하기 때문.
  • 최신 컴퓨터는 결정론적이지 않은데, 여러 계층에 걸친 캐시와 여러 개의 프로세스, 페이징, 스와핑, 그리고 멀티태스킹은 명령이 얼마나 걸릴지 예측할 수 없음
  • 실시간 애플리케이션은 예측할 수 없는 부분과 최악의 지연을 제한하려고 시도한다.

선행 폴트 데이터와 메모리 락

  1. 종종 선행 폴트를 일으켜 스왑된 데이터를 메모리에 올린 다음, 주소 공간 내 모든 페이지를 실제 물리 메모리에 ‘락을 걸거나’, ‘고정 배선’한다.
  2. 메모리 락을 걸고 나면 커널은 절대로 이 페이지를 디스크로 스왑하지 않는다.

CPU 친화도와 실시간 프로세스

  1. 각 실시간 프로세스를 위해 프로세서 하나를 예약해두고 나머지 프로세스는 남은 프로세서상에서 시분할 방식으로 동작하게 한다.
  2. 구현 방법:
    1. init 프로그램을 수정 - CPU_CLR (1, &set): CPU #1을 금지한다.
      1. 실행 가능한 프로세서 집합은 부모 프로세스로부터 상속받게 된다.
    2. 실시간 프로세스가 CPU #1에서만 실행되도록 affinity를 준다. - CPU_SET (1, %set)
This post is licensed under CC BY 4.0 by the author.