tick_init()

 

커널 v2.6.21에서 tickless라는 개념이 도입 되기전 커널에서는 각 cpu의 스케쥴러들은 고정된 주기(hz)의 time tick을 받아 태스크들의 스케쥴링을 수행했다. time tick을 줄여서 그냥 tick으로 불리고 있다. 현재는 커널 v3.10에 이르러 다음과 같이 3가지의 커널 옵션을 구분해서 사용한다.

  • CONFIG_HZ_PERIODIC
    • cpu의 idle 상태와 상관 없이 기존 커널과 같이 항상 tick을 발생한다.
    • 커널 버전 및 응용에 따라 다음 중 하나의 hz를 사용한다.
      • 100hz, 200hz, 250hz, 300hz, 500hz, 1000hz
        • rpi2: 100hz
  • CONFIG_NO_HZ_IDLE
    • cpu가 idle 상태로 들어가면 tick을 끈다.
      • 최대 1000hz -> 0hz로 줄여 전력 소모를 대폭 줄인다.
    • rcu callback 처리가 남아 있는 경우 해당 cpu는 no hz 모드로 진입하지 못한다.
    • rpi2: 현재 이 모드를 사용한다.
    • dynticks idle 또는 tickless idle 이라고도 불린다.
    • 참고: Clockevents and dyntick | LWN.net
  •  CONFIG_NO_HZ_FULL
    • cpu가 idle 상태로 들어가면 tick을 끈다.
      • 최대 1000hz -> 0hz로 줄여 전력 소모를 대폭 줄인다.
    • rcu callback 처리가 남아 있는 경우 해당 cpu는 no hz 모드로 진입하지 못한다.
    • single task가 동작중인 경우 tick을 1Hz 로 낮춘다. (많은 경우에 해당한다)
      • 최대 1000hz -> 1hz로 줄여 성능이 빨라지는 효과가 있다.
      • 디버깅 모드에서 1hz가 아니라 no hz로 바꾸어 문제점 분석에 사용할 수 있다.
    • full dynticks 또는 full tickless 라고도 불린다.
    • “nohz_full=” 부트 타임 커널 파라메터를 사용하는 경우에만 동작시킬 수 있다.
      • 설정되지 않는 경우 CONFIG_NO_HZ_IDLE 커널 옵션과 동일하게 동작한다.
      • 예)
        • “nohz_full=0-3”
          • cpu#0~#3까지 적용
        • “nohz_full=4,8-15”
          • cpu#4, #8~#15까지 적용
    • 참고:

 

1 HZ

  • 초당 하나의 타이머 인터럽트

 

NO_HZ

  • 특징
    • 최소한 하나의 cpu는 주기적으로  tick을 받는다.
    • SMP에서 유효하다.
    • 구현을 위해 하드웨어적으로 hr-timer가 필요하다.
  • 장점
    • 전력 소모가 크게 줄어 든다.
  • 단점
    • 시간 계산과 RCU callback 처리를 위해 구현이 복잡해졌다.
    • rcu callback 처리가 남아 있는 경우 해당 cpu는 no hz 모드로 진입하지 못한다.

 

Tick Broadcast

cpu가 깊은 idle 상태에 있을 때 tick broadcast를 수신받아 idle 상태에서 벗어난 후 리스케쥴 여부를 확인하고 진행할 태스크가 있는 경우 수행을 하게 한다.

  • 실행할 task가 없으면 cpu는 cpuidle_idle_call() 함수를 통해 idle loop 상태에 진입한다.
    • bootup을 담당한 첫 번째 cpu는 rest_init() 함수의 마지막 cpu_startup_entry() -> cpu_idle_loop()에서 idle 루프를 돈다.
    • 그 외 cpu 들을 online 상태로 변경하는 경우 secondary_start_kernel() 함수의 마지막 cpu_startup_entry() -> cpu_idle_loop()에서 idle 루프를 돈다.
  • Tick이 발생하여 리스케쥴링이 발생하는 경우 idle 상태를 벗어난다.
    • no hz에서 tick이 없는 경우 tick broadcast에 의해 깨어나 idle 상태를 탈출할 수 있다.
  • tick device 사용
    • 클럭소스는 clock_event_device를 사용한다.
    • tick_device 구조체를 사용하여 표현한다.
    • tick device 모드
      • periodic 모드
        • tick_broadcast_mask cpu 비트맵을 대상으로 tick_broadcast_start_periodic() 함수를 사용해 broadcast tick을 주기적으로 보낼 수 있다.
      • oneshot 모드
    • tick 디바이스의 등록 함수
      • tick_install_broadcast_device(newdev)

 

Generic clock events

  • tick 구현에 대한 generic core 루틴

 

tick_init()

kernel/time/tick-common.c

/**
 * tick_init - initialize the tick control
 */
void __init tick_init(void)
{
        tick_broadcast_init();
        tick_nohz_init();
}

tick broadcast framework 및 full nohz framework을 준비한다.

 

tick_broadcast_init()

kernel/time/tick-broadcast.c

void __init tick_broadcast_init(void)
{
        zalloc_cpumask_var(&tick_broadcast_mask, GFP_NOWAIT);
        zalloc_cpumask_var(&tick_broadcast_on, GFP_NOWAIT);
        zalloc_cpumask_var(&tmpmask, GFP_NOWAIT);
#ifdef CONFIG_TICK_ONESHOT
        zalloc_cpumask_var(&tick_broadcast_oneshot_mask, GFP_NOWAIT);
        zalloc_cpumask_var(&tick_broadcast_pending_mask, GFP_NOWAIT);
        zalloc_cpumask_var(&tick_broadcast_force_mask, GFP_NOWAIT);
#endif
}

tick broadcast framework을 준비한다.

  • tick_broadcast_mask
    • idle(sleep) 모드에 있는 cpu 비트맵
  • tick_broadcast_on
    • 주기적으로 broadcast가 수행되는 cpu 비트맵
  • tick_broadcast_oneshot_mask
    • oneshot으로 broadcast 해야 할 cpu 비트맵
  • tick_broadcast_pending_mask
    • broadcast가 지연된 cpu 비트맵
  • tick_broadcast_force_mask
    • 강제로 broadcast해야 할 cpu 비트맵
  • 참고: The tick broadcast framework | LWN.net

 

tick_nohz_init()

kernel/time/tick-sched.c

void __init tick_nohz_init(void)
{
        int cpu;

        if (!tick_nohz_full_running) {
                if (tick_nohz_init_all() < 0)
                        return;
        }

        if (!alloc_cpumask_var(&housekeeping_mask, GFP_KERNEL)) {
                WARN(1, "NO_HZ: Can't allocate not-full dynticks cpumask\n");
                cpumask_clear(tick_nohz_full_mask);
                tick_nohz_full_running = false; 
                return;
        }

        /*
         * Full dynticks uses irq work to drive the tick rescheduling on safe
         * locking contexts. But then we need irq work to raise its own
         * interrupts to avoid circular dependency on the tick 
         */
        if (!arch_irq_work_has_interrupt()) {
                pr_warning("NO_HZ: Can't run full dynticks because arch doesn't "
                           "support irq work self-IPIs\n");
                cpumask_clear(tick_nohz_full_mask);
                cpumask_copy(housekeeping_mask, cpu_possible_mask);
                tick_nohz_full_running = false;
                return;
        }
        
        cpu = smp_processor_id();

        if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) {
                pr_warning("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", cpu);
                cpumask_clear_cpu(cpu, tick_nohz_full_mask);
        }

        cpumask_andnot(housekeeping_mask,
                       cpu_possible_mask, tick_nohz_full_mask);

        for_each_cpu(cpu, tick_nohz_full_mask)
                context_tracking_cpu_set(cpu);

        cpu_notifier(tick_nohz_cpu_down_callback, 0);
        pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",
                cpumask_pr_args(tick_nohz_full_mask));
}

CONFIG_NO_HZ_FULL 커널 옵션을 사용한 경우 full tickless(no hz)로 동작을 하기 위한 framework을 준비한다.

  • 코드 라인 5~8에서 “nohz_full=” 부트 타임 커널 파라메터를 사용하지 않은 경우 처리를 포기한다.
  • 코드 라인 10~15에서 housekeeping_mask에 cpu 마스크를 할당한다. 할당이 실패하는 경우 처리를 포기한다.
  • 코드 라인 22~29에서 SMP 머신이 아닌 경우 처리를 포기한다.
  • 코드 라인 31~36에서 tick_nohz_fullmask에서 현재 cpu에 해당하는 비트를 클리어한다.
  • 코드 라인 38~39에서 housekeeping_mask에 possible cpu들에 대해 nohz full이 설정되지 않은 cpu들만 설정한다.
    • housekeeping_mask <- cpu_possible_mask & ~tick_nohz_full_mask
  • 코드 라인 41~42에서 CONFIG_CONTEXT_TRACKING 커널 옵션을 사용하는 경우 nohz full 설정된 cpu들에 대해서만 context tracking을 허용하도록 설정한다.
  • 코드 라인 44에서 cpu 상태 변화 시 호출되도록 우선 순위를 0으로 cpu notify chain에 tick_nohz_cpu_down_callback() 함수를 추가한다.
  • 코드 라인 45~46에서 “NO_HZ: Full dynticks CPUs:”  정보 메시지를 출력한다.

 

참고

4 thoughts to “tick_init()”

  1. 이전에 “Bare-Metal Multicore Performance in General-Purpose Operating System”문서를
    읽다가 이해가 안가는 부분이 있어서 “Paul McKenney”에게 질문한 적이 있습니다.

    질문 내용중 하나가 “Full tickless”가 Performance vs Power중 어느것에 초점을 둔것인가에
    대한 질문이었습니다. 다음과 같은 답변을 받았습니다.
    비슷한 내용이 있어서 공유해 봅니다.

    “It all depends on your workload. The two workloads that I know of that
    benefit much from tickless are HPC and realtime.

    You might be able to save a little bit of power in HPC workloads, but
    mostly in cases where they got done faster. And the HPC guys usually
    care a lot more about 1% performance than they do about 1% power savings.

    Thanx, Paul

    ◦cpu가 idle 상태로 들어가면 tick을 끈다.
    ◾최대 1000hz -> 0hz로 줄여 전력 소모를 대폭 줄인다.
    -> 죄송한데 이 내용은 어디에서 보신건가요??

  2. 먼저 오류를 찾아주신 것에 대해 감사드립니다.

    – nohz idle 상태에서만 시스템에 설정된 hz 틱 -> 0 hz로 바뀌면서 전력 소모를 극적으로 줄이고,
    – nohz full 상태에서는 cpu와 클럭이 살아있으므로 전력 소모는 거의 차이가 없을 것이며 성능 위주로 동작하게 됩니다.

    지적해주신 문장은 nohz idle에 들어가야할 문장입니다. ^^;

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.