Linux 6.6부터 기존의 CFS(Completely Fair Scheduler)를 대체하는 EEVDF(Earliest Eligible Virtual Deadline First) 스케줄러가 메인라인에 병합되었다. EEVDF는 1996년 Stoica & Zhang이 제안한 알고리즘을 기반으로 하며, CFS의 구조적 한계였던 레이턴시 불공정 문제를 근본적으로 개선한다. 커널 소스 기준으로 kernel/sched/fair.c 내에 CFS 코드와 함께 공존하되, 스케줄링 결정 로직은 EEVDF가 주도한다.
CFS와의 핵심 차이
CFS는 vruntime(가상 실행 시간)이 가장 작은 태스크를 선택한다.
이 방식은 CPU 시간 분배는 공정하지만, 레이턴시에 민감한 태스크가 긴 타임슬라이스를 가진 태스크에 밀리는 문제가 있었다.
EEVDF는 두 가지 개념을 추가한다.
- Eligible time(적격 시간) — 태스크가 CPU를 요청할 수 있는 가상 시간. 이 시간이 되기 전까지는 스케줄링 대상에서 제외된다.
- Virtual deadline(가상 데드라인) — 태스크가 타임슬라이스를 마쳐야 하는 가상 시간. EEVDF는 eligible한 태스크 중 virtual deadline이 가장 이른 태스크를 선택한다.
결과적으로 짧은 타임슬라이스를 요청하는 인터랙티브 태스크가 자연스럽게 더 이른 데드라인을 가지게 되어,
CPU 집약적 태스크보다 먼저 스케줄된다.
핵심 개념: lag와 vruntime
EEVDF에서도 vruntime은 유지된다. 여기에 lag라는 값이 추가된다.
lag = ideal_runtime - actual_runtime
lag가 양수이면 태스크가 받아야 할 CPU 시간보다 덜 받은 상태(크레딧),
음수이면 더 많이 받은 상태(부채)다.
eligible time은 lag를 기반으로 계산되므로, 부채가 쌓인 태스크는 일정 시간 eligible 상태가 되지 않는다.
virtual deadline은 다음과 같이 결정된다.
virtual_deadline = eligible_time + slice / weight
slice는 태스크에 할당된 타임슬라이스이며,
weight는 nice 값에서 파생된 스케줄링 가중치다.
nice 값이 낮을수록(우선순위 높음) weight가 크고, 결과적으로 virtual deadline이 당겨진다.
동작 확인 방법
스케줄러 통계 확인
# 태스크별 스케줄링 통계 (CONFIG_SCHEDSTATS 필요)
cat /proc/schedstat
# 특정 프로세스의 스케줄 지연 확인
cat /proc/$(pgrep nginx | head -1)/schedstat
# 출력: [cpu_time] [runqueue_wait_time] [timeslices]
perf sched로 실측
# 스케줄 이벤트 5초간 기록
perf sched record -a -- sleep 5
# 레이턴시 분석
perf sched latency
# 태스크별 스케줄 타임라인
perf sched timehist | head -50
현재 스케줄러 정책 확인
# 프로세스의 스케줄러 정책 및 우선순위
chrt -p $(pgrep bash | head -1)
# 출력 예시
pid 1234's current scheduling policy: SCHED_OTHER
pid 1234's current scheduling priority: 0
커널 버전 및 EEVDF 적용 확인
uname -r
# 6.6 이상이면 EEVDF 활성화
# EEVDF 관련 커널 설정 확인
zcat /proc/config.gz | grep -E "SCHED_CLASS|FAIR_GROUP"
튜닝 파라미터
EEVDF 관련 파라미터는 /proc/sys/kernel/에 있다.
ls /proc/sys/kernel/sched_*
| 파라미터 | 기본값 | 설명 |
|---|---|---|
sched_min_granularity_ns | 4,000,000 (4ms) | 태스크가 CPU를 선점당하지 않고 실행할 수 있는 최소 시간 |
sched_latency_ns | 24,000,000 (24ms) | 모든 runnable 태스크가 한 번씩 실행되는 목표 주기 |
sched_wakeup_granularity_ns | 4,000,000 (4ms) | wake-up된 태스크가 현재 실행 중인 태스크를 선점하려면 이 차이 이상 vruntime이 앞서야 함 |
sched_nr_latency | 8 | latency 목표를 보장하는 태스크 수 상한. 초과 시 granularity 기준으로 전환 |
인터랙티브 워크로드(데스크톱, 게임) 최적화 예시:
# 응답성 향상 - 선점 주기 단축
sysctl -w kernel.sched_min_granularity_ns=1000000 # 1ms
sysctl -w kernel.sched_latency_ns=6000000 # 6ms
sysctl -w kernel.sched_wakeup_granularity_ns=500000 # 0.5ms
서버/배치 처리 최적화 예시 (컨텍스트 스위칭 감소):
sysctl -w kernel.sched_min_granularity_ns=10000000 # 10ms
sysctl -w kernel.sched_latency_ns=80000000 # 80ms
sysctl -w kernel.sched_wakeup_granularity_ns=8000000 # 8ms
프로세스별 타임슬라이스 힌트 (Linux 6.6+)
EEVDF는 sched_attr의 sched_runtime 필드를 통해 태스크별 타임슬라이스를 지정할 수 있다.
SCHED_OTHER 정책에서도 동작한다.
#include <linux/sched/types.h>
#include <syscall.h>
struct sched_attr attr = {
.size = sizeof(attr),
.sched_policy = SCHED_OTHER,
.sched_runtime = 1000000, /* 1ms 타임슬라이스 힌트 */
};
syscall(SYS_sched_setattr, 0, &attr, 0);
주의사항 및 팁
- CFS 코드가 완전히 제거된 것은 아니다 — Linux 6.6 기준으로 그룹 스케줄링(cgroup CPU 할당량) 관련 일부 로직은 여전히 CFS 구조를 사용한다. EEVDF와 CFS는
fair.c안에서 공존한다. sched_latency_ns를 너무 낮추면 컨텍스트 스위칭 폭증 — 6ms 이하로 내리면 CPU 오버헤드가 체감될 수 있다.perf stat -e context-switches로 확인하며 조정한다.- PREEMPT_RT 패치와 병행 시 주의 — 실시간 커널(
PREEMPT_RT)과 조합 시SCHED_FIFO/SCHED_RR태스크가 EEVDF 큐 밖에서 동작하므로 혼용 시 우선순위 역전에 주의한다. - cgroup v2 cpu.weight와 연동 — EEVDF의 weight는
/sys/fs/cgroup/<group>/cpu.weight와 직결된다. 컨테이너 환경에서 CPU 자원 배분을 세밀하게 하려면 이 값을 조정한다. - 커널 6.8+ 에서 개선 지속 — EEVDF는 아직 튜닝 중인 기능이다. 배포판 커널보다 업스트림 커널에 추가 개선이 먼저 반영되므로, 성능 민감한 환경에서는 커널 패치노트를 주기적으로 확인한다.
마치며
EEVDF는 CFS의 vruntime 기반 공정성을 유지하면서 eligible time과 virtual deadline을 도입해 인터랙티브 태스크의 응답성을 구조적으로 개선했다.
파라미터 튜닝 방향은 CFS 시절과 동일하게 sched_latency_ns와 sched_min_granularity_ns를 워크로드 특성에 맞게 조정하는 것에서 출발한다.
참고:
LWN: An EEVDF CPU scheduler for Linux,
EEVDF 패치 커버 레터 (Peter Zijlstra),
CFS 스케줄러 설계 문서