[Linux:Kernel] Linux CPUFreq Governor

이 문서의 저작권은 GPL 라이센스를 따릅니다(This document is released under the GPL license).

              리눅스(TM) 커널 안의 CPU 주파수와 전압 조정 코드
                         L i n u x    C P U F r e q

                      C P U F r e q   G o v e r n o r s

                      – 사용자와 개발자들을 위한 정보 –

                    Dominik Brodowski  <linux@brodo.de>
                  추가와 교정은 Nico Golde <nico@ngolde.de>
                 번역 : 양정석 <dasomoli@gmailREMOVETHIS.com>
   Clock scaling allows you to change the clock speed of the CPUs on the
    fly. This is a nice method to save battery power, because the lower
            the clock speed, the less power the CPU consumes.
차례:
—–
1.   CPUFreq 가버너가 뭔가요?

2.   리눅스 커널 안의 가버너들
2.1  성능(Performance)
2.2  전력절약(Powersave)
2.3  사용자공간(Userspace)
2.4  수요충족(Ondemand)
2.5  보수적(Conservative)
2.6  상호적(Interactive)

3.   CPUfreq 코어 안의 가버너 인터페이스

1. CPUFreq 가버너가 뭔가요?
===========================

대부분의 cpufreq 드라이버들(사실, longrun 하나를 빼고 모두다) 또는 대
부분의 cpu 주파수 조정 알고리즘조차 오직 CPU에 하나의 주파수를 셋팅
하는 것만을 제공합니다. 동적인 주파수 조정을 제공함에 따라 cpufreq
코어는 한 “목표 주파수”의 이들 드라이버들을 말할 수 있어야만 합니다.
그래서 이들 지정된 드라이버들은 원래 있던 “->setpolicy” 호출 대신에
“->target” 호출을 제공하도록 바뀔 것입니다. “longrun”을 위해 모두가
같게 머물긴 하겠지만 말입니다.

CPUFreq 정책 안에서 무슨 주파수가 사용되어져야 하는 지는 어떻게 결정할
까요? 그건 “cpufreq 가버너”를 사용해서 합니다. 이 패치에는 이미
두 개가 있습니다– 주파수를 정적으로 가장 낮게 또는 가장 높은 주파수로
설정하는 “powersave”와 “performance” 가 이미 각각 있습니다.
적어도 둘 이상의 이같은 가버너가 수시일 내에 추가될 준비가 될 겁니다.
그러나 동적 주파수 조정에 관한 수많은 다른 이론과 모델들이 있는 것처럼
더 많이 될 것 같아 보입니다. cpufreq로서 그런 일반적인 인터페이스의
사용은 조정 가버너들에게 이들은 널리 테스트될 수 있다는 것과, 각각의 특정
용도에 대해 선택될 수 있는 가장 좋은 것을 제공합니다.

기본적으로, 다음 흐름도를 따릅니다:

CPU는 기정된 “제한사항”안에서 독립적으  |        CPU는 지정 주파수로만
로 스위칭될 수 있음                     |           셋팅될 수 있음

                                  “CPUfreq 정책”
                은 주파수 제한(policy->{min,max})과 사용될 CPUFreq로
                                   구성됩니다
                         /                    \
                        /                      \
                       /                       cpufreq 가버너가 (동적으로 혹은
                      /                         정적으로) policy->{min,max}의
                     /                         제한 사항안에서 무슨 target_freq를
                    /                          사용할 지 결정합니다.
                   /                                \
                  /                                  \
        ->setpolicy 호출을 사용하여,            ->target 호출을 사용하여,
         제한 사항과 “정책”을 셋팅.              가장 가까운 주파수를 target_freq
                                                 로 셋팅. policy->{min,max} 안에
                                                 있음이 보장됨.

2. 리눅스 커널 안의 가버너들
============================

2.1 성능(Performance)
———————

CPUfreq 가버너 “performance”는 CPU를 정적으로 scaling_min_freq 와
scaling_max_freq 경계 안에서 가장 높은 주파수로 셋팅합니다.
2.2 전력절약(Powersave)
———————–

CPUfreq 가버너 “powersave”는 CPU를 정적으로 scaling_min_freq 와
scaling_max_freq 경게 안에서 가장 낮은 주파수로 셋팅합니다.
2.3 사용자공간(Userspace)
————————-

CPUfreq 가버너 “userspace”는 사용자에게, 또는 UID “root”로 실행되는
어떤 사용자공간 프로그램에게 CPU-device 디렉토리 안에 이용가능한
“scaling_setspeed” sysfs 파일을 만듦으로써 CPU를 지정된 주파수로
셋팅할 수 있도록 합니다.
2.4 수요충족(Ondemand)
———————-

CPUfreq 가버너 “ondemand” 는 현재 사용량에 따라 CPU를 셋팅합니다.
이를 수행하기 위해 CPU는 매우 빠르게 주파수를 바꿀 수 있는 능력을
가져야 합니다. 접근 가능한 파라메터 sysfs 파일이 몇 개 있습니다:

sampling_rate: uS(10^-6 초)로 측정됨, 이것은 얼마나 자주 여러분이 커널이
CPU 사용량을 살펴보고 주파수에 관해 무엇을 할 것인지에 대한 결정을 내리길
원하는지 입니다. 일반적으로 이것은 ‘10000’ 주변이나 그 이상 값으로 셋팅
됩니다. 기본값은 (users-guide.txt와 절충하여):
transition_latency * 1000
전이 지연 시간은 ns 이고 sampling_rate는 us 임을 명심하세요. 그래서 여러분은
기본적으로 같은 sysfs 값을 얻을 수 있습니다.
샘플링 레이트는 언제나 전이 지연 시간을 고려해서 조정되어야만 합니다.
bash 에서 샘플링 레이트를 전이 지연 시간의 750 배 높은 값(말했듯이, 기본값은
1000)으로 셋팅하려면:
echo `$(($(cat cpuinfo_transition_latency) * 750 / 1000)) \
    >ondemand/sampling_rate

sampling_rate_min:
샘플링 레이트는 HW 전이 지연 시간에 의해 제한됩니다:
transition_latency * 100
또는 커널 제한에 의해서요:
CONFIG_NO_HZ 가 셋팅되면, 제한은 10ms 고정값.
CONFIG_NO_HZ 가 셋팅되지 않거나 부트 파라미터로 nohz=off 가 사용되면,
그 제한은 CONFIG_HZ 옵션에 의해 결정됩니다:
HZ=1000: min=20000us  (20ms)
HZ=250:  min=80000us  (80ms)
HZ=100:  min=200000us (200ms)
커널의 가장 높은 값과 HW 전이 지연 제한이 나타나고, 가장 작은 샘플링 레이트
가 사용됩니다.

up_threshold: 주파수를 증가시키는 게 좋을지에 대한 결정을 커널이 내리는데
필요한 ‘sampling_rate’의 샘플링들 사이의 평균 CPU 사용량으로 정의됩니다.
예를 들면, 그 값이 ’95’로 셋팅되어 있을 때는 검사 간격 사이에 CPU가 평균
95% 이상 사용 중이면 CPU 주파수를 증가시킬 필요가 있다는 결정을 함을
의미합니다.

ignore_nice_load: 이 파라미터는 ‘0’ 또는 ‘1’ 을 값으로 가집니다.
‘0’ 으로 셋팅되었을 때(기본값)는 모든 프로세스들이 ‘CPU 활용도’ 값을 위해
세어집니다. ‘1’ 로 셋팅되었을 때는 ‘nice’ 값으로 실행되는 프로세스들은
전체 사용량 계산에 같이 세어지지 않습니다. 이 것은 여러분이 여러분의
랩탑에서 ‘nice’ 를 사용하여 끝나는 시간이 얼마나 오래 걸릴지를 걱정하지
않는 CPU를 많이 사용하는 심한 계산을 실행 중일 때 유용하고, 여러분의
CPU 주파수를 증가시키는데 그 프로세스가 영향을 미치는 것을 막아줍니다.

sampling_down_factor: 이 파라미터는 커널이 최고 속도에서 실행 중인 동안
주파수를 언제 감소시킬 것인지를 결정하는 속도을 제어합니다. 1(기본값)로
셋팅되었을 때는 다시 부하를 평가하기 위한 결정이 현재 클럭 속도와 상관없이
같은 간격에서 이루어 집니다. 그러나 1 보다 크게(예를 들어, 100) 셋팅되면
CPU가 높은 부하로 인해 그 최소 속도로 있을 때, 부하의 재평가를 위한
스케줄링 간격의 배수로서 수행됩니다. 이것은 부하 평가의 과부하를 줄임으로써
성능을 향상시키고, CPU 가 정말 바쁠 때 다시 느려졌다가 빨라지는 것보다 나은,
그 최고 속도를 유지하도록 도움을 줍니다. 이것은 낮은 속도/낮은 CPU 부하량의
동작에는 영향을 주지 않습니다.
2.5 보수적(Conservative)
————————

“ondemand”와 매우 비슷한, CPUfreq 가버너 “conservation” 는 현재 사용량에
따라 CPU 를 셋팅합니다. 그것은 동작 상에서, 어떤 CPU 상의 부하가 있는
순간 최고 속도로 점프하는 것보다는 우아하게 CPU 속도를 증가시키고
감소시킨다는 것이 다릅니다. 이 동작은 배터리 전원 환경에 더 잘어울립니다.
이 가버너는 다음의 몇 개 추가된 sysfs를 통해 “ondemand” 가버너와 같은
방식으로 조작할 수 있습니다:

freq_step: 이것은 CPU 주파수가 그에 의해 부드럽게 중가되거나 감소되어야
하는지 백분율로 표시된 단계를 나타냅니다. 기본적으로 CPU 주파수는 여러분의
CPU 최고 주파수의 5% 단위로 증가할 것입니다. 여러분은 이 값은 어느 곳에서나
0과 100사이에서 바꿀 수 있습니다. ‘0’은 그 부하에 상관없이 어느 속도로
여러분의 CPU 속도를 효과적으로 고정시킬 것입니다. 반면 ‘100’은 이론적으로
“ondemand” 가버너와 동일하게 동작하도록 합니다.

down_threshold: “ondemand” 가버너에서 찾을 수 있는 ‘up_threshold’ 와 같지만,
방향은 반대입니다. 예를 들면, 그 기본값이 ’20’으로 셋팅되었을 때는 그
주파수를 낮추려면 CPU 사용량이 샘플링 간격 사이에 20% 아래일 필요가 있다는
의미입니다.

2.6 상호적(Interactive)
———————–

CPUfreq 가버너 “interactive”는 지연 시간에 민감한 상호적 작업 부하에
맞추어 설계되었습니다. 이 가버너는 CPU 속도를 “ondemand” 와
“conservative” 가버너와 비슷하게, 사용량에 따라 셋팅합니다. 그러나
설정가능한 동작들이 다릅니다.

이 가버너를 위해 맞출 수 있는 값들은 다음과 같습니다:

target_loads: CPU 부하 값은 현재 CPU 부하를 그 값으로 맞추기 위해서
속도를 조정하는데 사용됩니다. 일반적으로, 목표 부하값이 낮을수록
더 자주 그 가버너가 목표 아래로 부하를 낮추기 위해 CPU 속도를
끌어올릴 것입니다. 그 형식은 하나의 목표 부하값, 그 다음 옵션으로
목표하거나 그 이상의 속도를 위한 CPU 부햐와 CPU 속도의 짝입니다.
콜론이 속도, 그리고 그와 관련된 목표 부하량을 읽기 쉽게 하기 위해
사용될 수 있습니다. 예를 들면:

   85 1000000:90 1700000:99
   
CPU 부하가 1GHz 이하에서는 85%를 목표로 하고, 90%는 1GHz에서나 그 이상
1.7GHz까지, 그리고 그 이상은 99%를 목표로 합니다. 속도가 지정되면
이들은 증가하는 순서로 나와야 합니다. 높은 목표 부하값들은 일반적으로
높은 속도로 지정되고, 그래서 목표 부하값 또한 보통 증가하는 순서로
나타납니다. 기본값은 모든 속도에 목표 부하 90% 입니다.
min_sample_time: 낮추기 전에 현재 주파수에서 소비할 시간의 최소량.
기본값은 80000 uS.

hispeed_freq: gp_hispeed_load 로 지정된 값에 CPU 부하가 도달했을 때
처음에 증가하는 중간급의 “처음 만나는 속도”. 부하가 above_hispeed_delay에
지정된 시간의 양 동안 높게 유지되면, 속도는 더 빨라집니다. 기본값은
가버너의 초기화 시간에 그 정책에 의해 허용되는 최고 속도입니다.

go_hispeed_load: hispeed_freq 로 올라가는 CPU 부하. 기본은 99%.

above_hispeed_delay: 속도가 hispeed_freq 혹은 그 이상일 때, 계속되는
고부하로 인해 속도를 올리기 전에 이 시간만큼 대기합니다.
이 형식은 하나의 대기 시간 값, 그 다음 옵션으로 CPU 속도와 이들 속도
혹은 그 이상의 속도에서 사용되는 대기 시간의 짝이 따릅니다. 콜론이
읽기 쉽게 하기 위해 속도와 그 연관된 대기 시간 사이에 사용될 수
있습니다. 예를 들면:

   80000 1300000:200000 1500000:40000

CPU 속도 1.3 GHz 까지는 80000 uS 대기 시간이 사용되고, 1.5 GHz
속도까지는 200000 uS가 속도 대기 시간으로, 1.5 GHz(그리고 그 이상)
에서는 40000 uS 대기 시간이 사용됩니다. 속도들이 지정되면 이들은
증가하는 순서로 나타나야 합니다. 기본값은 20000 uS.

timer_rate: CPU가 대기 상태가 아닐 때 CPU 부하를 재평가하기 위한
샘플링 속도. 한 개의 미룰 수 있는 타이머가 사용되는데, 어떤 다른 것을
실행될 필요가 있을 때까지 CPU는 대기 상태로부터 이 타이머를 수행할
때까지 깨어나지 않게 됩니다. (최하 속도에서 실행되지 않을 때 이
타이머를 미룰 수 있는 최대 시간은 timer_slack을 통해 설정 가능합니다)
기본값은 20000 Us.

timer_slack: 최하 속도 이상의 속도로 실행 중일 때, timer_rate를 넘어
가버너의 샘플링 타이머의 처리를 미룰 수 있는 최대 추가 시간. CPU들이
최하보다 높은 속도로 실행 중일때 대기 상태에서 추가 전력을 소비하는
플랫폼을 위해 이것은 타이머가 얼마나 오래 부하 재평가와 속도를
떨어뜨리는 것의 순위를 미룰 것인가 상한을 둡니다. 예를 들면, timer_rate
가 20000uS 이고 timer_slack 이 10000uS 이면, 타이머는 최하 속도에 있지
않을 때, 최대 30msec 까지 수행을 미룰 것입니다. -1 값은 타이머를 모든
속도에서 무한히 미루겠다는 뜻입니다. 기본은 80000 uS.

boost: 0이 아니면, 즉시 모든 CPU들의 속도를 이 속성에 0이 쓰여질 때까지
적어도 hispeed_freq 까지 일시적으로 올립니다. 0이면, 보통의 부하에
따라 CPU 속도를 hispeed_freq 아래로 떨어지는 것이 허용됩니다.
기본값은 0.

boostpulse: 쓰여질 때마다, 즉시 모든 CPU들의 속도를 적어도
boostpulse_duration에 지정된 시간 동안 hispeed_freq로 일시적으로
올리고, 그 후에 보통의 부하에 따라 hispeed_freq 아래로 속도가 떨어지는
것이 허용됩니다.

boostpulse_duration: boostpulse에 쓰여질 때 보통의 부하에 따라 속도를
떨어뜨리는 것을 허용하기 전에 hispeed_freq 에서 CPU 속도를 유지하는
시간의 길이. 기본값은 80000 uS.
3. CPUfreq 코어 안의 가버너 인터페이스
======================================

새로운 가버너는 그 자신을 CPUfreq 코어에 “cpufreq_register_governor”를
사용해서 반드시 등록해야 합니다. 그 함수로 전달될
struct cpufreq_governor 는 다음 값들을 반드시 가져야 합니다:

governor->name –            이 가버너의 유일한 이름
governor->governor –        가버너 콜백 함수
governor->owner –           (적절하다면) 가버너 모듈을 위한 .THIS_MODULE

governor->governor 콜백은 그 CPU를 위한 현재의(또는 셋팅될)
cpufreq_policy 구조체, unsigned int인 event와 함께 호출됩니다. 다음의
event들이 현재 정의되어 있습니다:

CPUFREQ_GOV_START:   이 가버너가 그 CPU policy->cpu를 위해 그 의무를
                     시작할 것입니다.
CPUFREQ_GOV_STOP:    이 가버너가 그 CPU policy->cpu를 위해 그 의무를
                     멈출 것입니다.
CPUFREQ_GOV_LIMITS:  CPU policy->cpu를 위한 제한 사항들이 policy->min
                     과 policy->max로 바뀌었습니다.

여러분이 여러분의 드라이버의 다른 “이벤트들”을 외부적으로 필요로 한다면,
CPUFreq 코어가 적절한 락킹을 보장하도록 _오직_
cpufreq_governor_l(unsigned int cpu, unsigned int event) 호출만 사용하도록
하세요.
CPUfreq 가버너는 아마 이들 두 함수 중 하나를 사용해서 CPU 프로세서
드라이버를 호출할 것입니다:

int cpufreq_driver_target(struct cpufreq_policy *policy,
                                 unsigned int target_freq,
                                 unsigned int relation);

int __cpufreq_driver_target(struct cpufreq_policy *policy,
                                   unsigned int target_freq,
                                   unsigned int relation);

target_freq 는 물론, policy->min과 policy->max 안에 있어야만 합니다.
이들 두 함수간에 무슨 차이가 있을까요? 여러분의 가버너가 여전히
governor->governor 로 호출의 직접적인 코드 경로 안에 있다면, per-CPU
cpufreq lock 이 cpufreq 코에 안에서 여전히 잡혀 있을 것이고, 다시
잠글 필요가 없습니다(사실 이렇게 하면 데드락의 원인이 됩니다). 그래서
이런 경우에는 __cpufreq_driver_target 만 사용하세요. 다른 모든 경우에는
(예를 들면, 매 초마다 깨어나는 “데몬화된” 함수가 있을 때), 그 명령이
cpufreq 프로세서 드라이버로 전달되기 전에 cpufreq per-CPU lock을
락킹하기 위해서 cpufreq_driver_target을 사용하세요. 

2 thoughts to “[Linux:Kernel] Linux CPUFreq Governor”

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다