Linux v6.6 · 개념과 코드 읽기

scheduler tick: 주기적으로 실행 시간을 계상하고 재선택을 요청하기

이 코드는 어떤 문제를 푸나요?

타이머 tick이 왔다고 매번 다른 task로 바꾸는 것은 아닙니다. Linux v6.6의 scheduler_tick은 현재 task인 rq->curr를 대상으로 시간과 열 제한 상태를 갱신한 뒤 정책별 task_tick을 호출합니다. 필요하다는 판단과 실제 context switch는 서로 다른 단계입니다.

읽을 범위: v6.6 · kernel/sched/core.c · scheduler_tick 5638–5678행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.

먼저 알아둘 개념

계상과 전환

얼마나 실행했는지 기록하는 일, 재스케줄이 필요하다고 표시하는 일, 실제 context switch는 서로 다른 단계입니다.

스케줄링 클래스 콜백

fair, RT 등 각 정책이 자신의 시간 규칙을 적용하도록 task_tick 함수를 호출합니다. 공통 tick 코드가 모든 정책의 세부 조건을 직접 작성하지 않습니다.

현재 task

이 버전의 공통 tick은 rq->curr로 얻은 task를 계상하고 그 스케줄링 클래스를 호출합니다. v6.18.37의 donor 개념을 이 코드에 소급해서 적용하지 않습니다.

처음 읽을 때

tick 전후에 실행한 누적 시간이 늘어났지만 다음 task는 그대로일 수 있는 예를 생각해 보세요. tick은 교체 명령이 아니라 정책이 판단할 정기 기회입니다.

더 깊이 살펴볼 때

thermal pressure와 rq_clock_thermal의 계상을 실행 시간 갱신과 구분해 보세요. v6.6에는 이 함수의 sched_ext 처리나 lazy preemption 승격 경로가 없으므로 실제 소스에 있는 경로를 따라가셔야 합니다.

그림으로 보는 변화

scheduler tick: 주기적으로 실행 시간을 계상하고 재선택을 요청하기의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 현재 CPU 상태 갱신

rq_clock, thermal pressure, 계상 기준

화살표는 tick 한 번의 처리 순서입니다. 이 버전에서는 열 제한에 따른 용량 감소를 별도로 반영합니다.

2. 현재 task의 정책 호출

curr->sched_class->task_tick

fair·RT 등 정책마다 자신의 소진 조건을 판단합니다. tick이 곧 task 교체라는 뜻은 아닙니다.

3. 주변 처리와 SMP 균형 조정

perf, workqueue, trigger_load_balance

화살표는 잠금 해제 뒤의 처리 순서입니다. 부하 균형 조정은 CONFIG_SMP 조건 안에 있습니다.

scheduler_tick를 한 줄씩 읽기

줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.

void scheduler_tick(void)
{
	int cpu = smp_processor_id();
	struct rq *rq = cpu_rq(cpu);
	struct task_struct *curr = rq->curr;
	struct rq_flags rf;
	unsigned long thermal_pressure;
	u64 resched_latency;

	if (housekeeping_cpu(cpu, HK_TYPE_TICK))
		arch_scale_freq_tick();

	sched_clock_tick();

	rq_lock(rq, &rf);

	update_rq_clock(rq);
	thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));
	update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure);
	curr->sched_class->task_tick(rq, curr, 0);
	if (sched_feat(LATENCY_WARN))
		resched_latency = cpu_resched_latency(rq);
	calc_global_load_tick(rq);
	sched_core_tick(rq);
	task_tick_mm_cid(rq, curr);

	rq_unlock(rq, &rf);

	if (sched_feat(LATENCY_WARN) && resched_latency)
		resched_latency_warn(cpu, resched_latency);

	perf_event_task_tick();

	if (curr->flags & PF_WQ_WORKER)
		wq_worker_tick(curr);

#ifdef CONFIG_SMP
	rq->idle_balance = idle_cpu(cpu);
	trigger_load_balance(rq);
#endif
}
void scheduler_tick(void)

Linux v6.6의 공통 scheduler_tick 함수입니다. 현재 CPU의 실행 시간을 계상하고 정책별 tick 처리를 연결합니다.

	int cpu = smp_processor_id();

지금 실행 중인 CPU 번호를 구합니다.

	struct rq *rq = cpu_rq(cpu);

해당 CPU의 실행 큐를 찾습니다.

	struct task_struct *curr = rq->curr;

이 버전은 rq->curr를 현재 처리 대상 task로 읽습니다. 최신 버전의 rq->donor와 구분하셔야 합니다.

	struct rq_flags rf;

runqueue 잠금 처리에 필요한 상태를 보관합니다.

	unsigned long thermal_pressure;

열 제한 때문에 줄어든 CPU 처리 용량을 담습니다. 이 버전의 이름과 대상은 thermal pressure입니다.

	u64 resched_latency;

재스케줄 지연 경고용 시간을 저장할 변수를 준비합니다.

	if (housekeeping_cpu(cpu, HK_TYPE_TICK))

tick housekeeping을 담당하는 CPU인지 확인합니다. v6.6에서는 HK_TYPE_TICK 분류를 사용합니다.

		arch_scale_freq_tick();

해당 CPU에서 주파수에 따른 스케줄러 용량 계상을 갱신합니다.

	sched_clock_tick();

스케줄러 시계의 tick 처리를 수행하여 실행 시간 계산 기준을 유지합니다.

	rq_lock(rq, &rf);

실행 큐의 시간과 정책 상태를 일관되게 갱신하려고 rq 잠금을 잡습니다.

	update_rq_clock(rq);

실행 큐의 현재 시계를 갱신합니다.

	thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));

아키텍처가 보고한 열 제한에 따른 CPU 용량 감소량을 읽습니다.

	update_thermal_load_avg(rq_clock_thermal(rq), rq, thermal_pressure);

thermal 계상용 시계와 읽은 pressure로 열 제한에 따른 부하 평균을 갱신합니다. 일반 실행 시간과 용량 감소를 구분합니다.

	curr->sched_class->task_tick(rq, curr, 0);

현재 task가 속한 스케줄링 클래스의 task_tick을 호출합니다. 마지막 0은 queued 인자로 전달되는 값이며 각 정책이 자신의 시간 규칙을 적용합니다.

	if (sched_feat(LATENCY_WARN))

재스케줄 지연 경고 기능이 켜져 있는지 확인합니다.

		resched_latency = cpu_resched_latency(rq);

켜져 있다면 실제 지연량을 계산하여 뒤의 경고 판단에 사용합니다.

	calc_global_load_tick(rq);

전체 시스템 load 계상에 이번 tick을 반영합니다.

	sched_core_tick(rq);

core scheduling에서 필요한 tick 처리를 수행합니다.

	task_tick_mm_cid(rq, curr);

현재 task의 메모리 문맥 concurrency ID 관리에도 tick을 반영합니다.

	rq_unlock(rq, &rf);

실행 큐 내부 갱신을 마쳤으므로 잠금을 해제합니다.

	if (sched_feat(LATENCY_WARN) && resched_latency)

경고 기능이 켜져 있고 실제 재스케줄 지연이 있는 경우인지 확인합니다.

		resched_latency_warn(cpu, resched_latency);

잠금 밖에서 지연 경고를 수행합니다.

	perf_event_task_tick();

성능 계측 기능의 task tick 처리를 이어 갑니다.

	if (curr->flags & PF_WQ_WORKER)

현재 task가 workqueue worker인지 확인합니다.

		wq_worker_tick(curr);

worker라면 workqueue 관련 tick 관리도 수행합니다.

#ifdef CONFIG_SMP

다중 CPU 지원 빌드에서만 아래 부하 균형 조정 코드를 포함합니다.

	rq->idle_balance = idle_cpu(cpu);

현재 CPU가 idle인지 실행 큐에 기록하여 균형 조정 판단에 제공합니다.

	trigger_load_balance(rq);

부하 균형 조정이 필요한 시점인지 확인하고 관련 처리를 촉발합니다. v6.6에서는 trigger_load_balance를 호출합니다.

#endif

SMP 전용 부하 균형 조정 부분이 끝납니다.

함께 생각해 볼 질문

tick 한 번마다 task가 반드시 바뀌나요?

아닙니다. 실행 시간이 기록되고 정책 판단이 이루어지지만 계속 현재 task가 적절할 수 있습니다.

task_tick 콜백을 쓰는 이유는 무엇인가요?

공통 시간 갱신과 각 정책의 시간 규칙을 나누기 위해서입니다. RT와 fair가 같은 소진 규칙을 쓰지 않습니다.

재스케줄 플래그를 세우면 그 줄에서 즉시 전환하나요?

그렇지 않습니다. 적절한 선점 지점이나 복귀 경로에서 실제 스케줄러 전환으로 이어질 수 있습니다.

출처와 읽은 범위

Linux stable v6.6 · kernel/sched/core.c

해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고

맨 위로 ↑