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

v6.6 / kernel/sched/core.c

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

## scheduler_tick

```c

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
}

```

### 5638행

```c

void scheduler_tick(void)

```

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

### 5640행

```c

	int cpu = smp_processor_id();

```

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

### 5641행

```c

	struct rq *rq = cpu_rq(cpu);

```

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

### 5642행

```c

	struct task_struct *curr = rq->curr;

```

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

### 5643행

```c

	struct rq_flags rf;

```

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

### 5644행

```c

	unsigned long thermal_pressure;

```

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

### 5645행

```c

	u64 resched_latency;

```

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

### 5647행

```c

	if (housekeeping_cpu(cpu, HK_TYPE_TICK))

```

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

### 5648행

```c

		arch_scale_freq_tick();

```

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

### 5650행

```c

	sched_clock_tick();

```

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

### 5652행

```c

	rq_lock(rq, &rf);

```

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

### 5654행

```c

	update_rq_clock(rq);

```

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

### 5655행

```c

	thermal_pressure = arch_scale_thermal_pressure(cpu_of(rq));

```

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

### 5656행

```c

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

```

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

### 5657행

```c

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

```

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

### 5658행

```c

	if (sched_feat(LATENCY_WARN))

```

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

### 5659행

```c

		resched_latency = cpu_resched_latency(rq);

```

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

### 5660행

```c

	calc_global_load_tick(rq);

```

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

### 5661행

```c

	sched_core_tick(rq);

```

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

### 5662행

```c

	task_tick_mm_cid(rq, curr);

```

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

### 5664행

```c

	rq_unlock(rq, &rf);

```

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

### 5666행

```c

	if (sched_feat(LATENCY_WARN) && resched_latency)

```

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

### 5667행

```c

		resched_latency_warn(cpu, resched_latency);

```

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

### 5669행

```c

	perf_event_task_tick();

```

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

### 5671행

```c

	if (curr->flags & PF_WQ_WORKER)

```

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

### 5672행

```c

		wq_worker_tick(curr);

```

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

### 5674행

```c

#ifdef CONFIG_SMP

```

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

### 5675행

```c

	rq->idle_balance = idle_cpu(cpu);

```

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

### 5676행

```c

	trigger_load_balance(rq);

```

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

### 5677행

```c

#endif

```

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

