일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Pointer
- go
- UNIX Internals
- 긴옵션
- Windows via c/c++
- newSQL
- 포인터변수
- OS 커널
- 약어
- 컴퓨터 강좌
- Golang
- bash
- TiDB
- UNIX
- 함수포인터
- 포인터
- SQLite
- 한빛미디어
- Symbol
- DBMS
- TiKV
- DBMS 개발
- Preprocessor
- kernel
- 커널
- FreeBSD
- 구조와 원리
- 전처리기
- getopts
- Programming
- Today
- Total
sonumb
애플리케이션 CPU 사용률을 낮추고 싶을 때 본문
개요
애플리케이션의 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
위의 사항을 확인하는데로 업데이트 할 것.