sonumb

애플리케이션 CPU 사용률을 낮추고 싶을 때 본문

개발자 이야기/UNIX

애플리케이션 CPU 사용률을 낮추고 싶을 때

sonumb 2021. 11. 18. 19:50

개요

애플리케이션의 CPU 사용률을 낮추고자 한다면, 솔루션으로 대개 sleep() 혹은 select() 호출를 생각할 것이다.

 

하지만, 이 함수들을 사용할 수 없는 경우도 있다.

예를 들어, 특정 라이브리가 포함된 애플리케이션을 작성하였는데, 이 라이브러리의 함수 호출 시 CPU 사용률이 높다고 가정하자.

또한, 이 함수의 CPU 점유 시간도 길다고 한다.

 

어떻게 해야 할까?

 

만일 라이브러리를 수정한다면 해결할 수 있겠지만, 라이브러리 소스 코드가 없다면 해결책이 될 수 없다.

(⛔️ "라이브러리 직접 수정"이 가능하더라도, 절대로 하면 안된다. 나의 애플리케이션 외에, 다른 애플리케이션이 사용하기 때문이다.)

 

그렇다면, 라이브러리를 호출하는 코드쪽에서 CPU 사용을 제어하는 방법이 있을까?

 

→ 리얼타임 스케쥴링을 이용해 보자.

 

자세한 내용은 아래 글들을 참조. ([RTOS] 1~3편)

https://blog.naver.com/alice_k106/221149061940

https://blog.naver.com/alice_k106/221170259817

https://blog.naver.com/alice_k106/221170316769

 

소스코드

sturct의 sched_attr의 아래 세 필드에 대해 자세히 조사한 후 정리할 것.

  uint64_t sched_runtime;
  uint64_t sched_deadline;
  uint64_t sched_period;

소스 코드의 내용은 아래와 같다.

주의 할 점은 _GNU_SOURCE를 꼭 정의해야 한다는 것이다. 

#define _GNU_SOURCE

#include <linux/sched.h>
#include <sched.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>

struct sched_attr {
  uint32_t size;              /* Size of this structure */
  uint32_t sched_policy;      /* Policy (SCHED_*) */
  uint64_t sched_flags;       /* Flags */
  int32_t  sched_nice;        /* Nice value (SCHED_OTHER,
                                 SCHED_BATCH) */
  uint32_t sched_priority;    /* Static priority (SCHED_FIFO,
                                 SCHED_RR) */
  /* Remaining fields are for SCHED_DEADLINE */
  uint64_t sched_runtime;
  uint64_t sched_deadline;
  uint64_t sched_period;
};

// 실제로 스케줄링 속성을 변경하는 sched_setattr 함수
static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
{
  return syscall(SYS_sched_setattr, pid, attr, flags);
}

int main(int argc, char * argv[])
{
  int result;
  volatile int a = 0;
  int use_daedline = 0;

  struct sched_attr attr = {
    .size = sizeof (attr),
    .sched_policy = SCHED_DEADLINE,
    .sched_runtime = 400 * 1000 * 1000,
    .sched_period = 2 * 1000 * 1000 * 1000,
    .sched_deadline = 401 * 1000 * 1000
  };

  if( argc == 2 )
    {
      use_daedline = atoi(argv[1]);
    }
  else
    {
      use_daedline = 0;
    }

  if( use_daedline == 1 )
    {
      printf("use daedline\n");
      result = sched_setattr(getpid(), &attr, 0);
      if (result == -1) {
        perror("Error calling sched_setattr.");
        exit(1);
      }
    }

  while( 1 )
    {
      a++;
    }

  return 0;
}

✅ 특정 함수에서만 CPU 사용량을 줄이고 싶다면?

→ 위 코드에서는 whil(1)문이 '특정 함수'가 될 것이다.
     그렇다면, sched_setattr()호출 전에 현재 스케쥴러 속성을 세이브하고,
     while(1) 문 후로 세이브한 스케쥴러를 이용해 복구하는 로직을 삽입하면 된다.


컴파일, 실행 및 결과

$ gcc test_shed.c -o test_sched

$ sudo ./tests_sched 1
#수 초후 Ctrl+C

$ sudo ./tests_sched
# 수 초후 Ctrl+C

$

top로 조회한 결과는 아래와 같다.

$ top -c -u root | grep test_sched

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< sched_setattr() 사용할 떄,
10806 root      rt   0    4216    352    276 R  13.2  0.0   0:00.40 ./test_sched 1
10806 root      rt   0    4216    352    276 R  20.5  0.0   0:01.02 ./test_sched 1
10806 root      rt   0    4216    352    276 R  19.1  0.0   0:01.60 ./test_sched 1
10806 root      rt   0    4216    352    276 R  21.9  0.0   0:02.26 ./test_sched 1
10806 root      rt   0    4216    352    276 R  17.8  0.0   0:02.80 ./test_sched 1

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 사용하지 않을 때
10995 root      20   0    4212    348    276 R 100.0  0.0   0:03.11 ./test_sched
10995 root      20   0    4212    348    276 R  99.7  0.0   0:06.13 ./test_sched
10995 root      20   0    4212    348    276 R 100.0  0.0   0:09.15 ./test_sched
10995 root      20   0    4212    348    276 R 100.0  0.0   0:12.17 ./test_sched
10995 root      20   0    4212    348    276 R 100.0  0.0   0:15.20 ./test_sched
10995 root      20   0    4212    348    276 R 100.0  0.0   0:18.22 ./test_sched

sched_setattr() 호출하지 않으면 CPU 100% 이며, 호출한 경우 CPU 사용률이 약 20% 이다.

또한, SCHED_DEADLINE으로 세팅한 경우, 우선순위(PR) 컬럼의 값이 rt 임을 알 수 있다.

추가 이슈

권한 없음("Operation not permitted") 문제

/etc/security/limits.conf 파일에 아래내용 추가한 후, 터미널 재접속

<username>   hard rtprio 99
<username>   soft rtprio 99

 

⛔️ 이거 외에도 더 설정해야, sudo 없이도 sched_setattr()이 정상적으로 동작될 수 있음.

  • /sys/fs/cgroup/cpu/user.slice/cpu.rt_runtime_us 파일
  • 명령어: $ sudo sysctl -w kernel.sched_rt_runtime_us=-1

위의 사항을 확인하는데로 업데이트 할 것.

반응형