요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>
========================
CPU Idle Time Management
========================
:Copyright: |copy| 2019 Intel Corporation
:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
CPU Idle Time Management Subsystem
==================================
Every time one of the logical CPUs in the system (the entities that appear to
fetch and execute instructions: hardware threads, if present, or processor
cores) is idle after an interrupt or equivalent wakeup event, which means that
there are no tasks to run on it except for the special "idle" task associated
with it, there is an opportunity to save energy for the processor that it
belongs to. That can be done by making the idle logical CPU stop fetching
instructions from memory and putting some of the processor's functional units
depended on by it into an idle state in which they will draw less power.
However, there may be multiple different idle states that can be used in such a
situation in principle, so it may be necessary to find the most suitable one
(from the kernel perspective) and ask the processor to use (or "enter") that
particular idle state. That is the role of the CPU idle time management
subsystem in the kernel, called ``CPUIdle``.
The design of ``CPUIdle`` is modular and based on the code duplication avoidance
principle, so the generic code that in principle need not depend on the hardware
or platform design details in it is separate from the code that interacts with
the hardware. It generally is divided into three categories of functional
units: *governors* responsible for selecting idle states to ask the processor
to enter, *drivers* that pass the governors' decisions on to the hardware and
the *core* providing a common framework for them.
CPU Idle Time Governors
=======================
A CPU idle time (``CPUIdle``) governor is a bundle of policy code invoked when
one of the logical CPUs in the system turns out to be idle. Its role is to
select an idle state to ask the processor to enter in order to save some energy.
``CPUIdle`` governors are generic and each of them can be used on any hardware
platform that the Linux kernel can run on. For this reason, data structures
operated on by them cannot depend on any hardware architecture or platform
design details as well.
The governor itself is represented by a struct cpuidle_governor object
containing four callback pointers, :c:member:`enable`, :c:member:`disable`,
:c:member:`select`, :c:member:`reflect`, a :c:member:`rating` field described
below, and a name (string) used for identifying it.
For the governor to be available at all, that object needs to be registered
with the ``CPUIdle`` core by calling :c:func:`cpuidle_register_governor()` with
a pointer to it passed as the argument. If successful, that causes the core to
add the governor to the global list of available governors and, if it is the
only one in the list (that is, the list was empty before) or the value of its
:c:member:`rating` field is greater than the value of that field for the
governor currently in use, or the name of the new governor was passed to the
kernel as the value of the ``cpuidle.governor=`` command line parameter, the new
governor will be used from that point on (there can be only one ``CPUIdle``
governor in use at a time). Also, user space can choose the ``CPUIdle``
governor to use at run time via ``sysfs``.
Once registered, ``CPUIdle`` governors cannot be unregistered, so it is not
practical to put them into loadable kernel modules.
The interface between ``CPUIdle`` governors and the core consists of four
callbacks:
:c:member:`enable`
::
int (*enable) (struct cpuidle_driver *drv, struct cpuidle_device *dev);
The role of this callback is to prepare the governor for handling the
(logical) CPU represented by the struct cpuidle_device object pointed
to by the ``dev`` argument. The struct cpuidle_driver object pointed
to by the ``drv`` argument represents the ``CPUIdle`` driver to be used
with that CPU (among other things, it should contain the list of
struct cpuidle_state objects representing idle states that the
processor holding the given CPU can be asked to enter).
It may fail, in which case it is expected to return a negative error
code, and that causes the kernel to run the architecture-specific
default code for idle CPUs on the CPU in question instead of ``CPUIdle``
until the ``->enable()`` governor callback is invoked for that CPU
again.
:c:member:`disable`
::
void (*disable) (struct cpuidle_driver *drv, struct cpuidle_device *dev);
Called to make the governor stop handling the (logical) CPU represented
by the struct cpuidle_device object pointed to by the ``dev``
argument.
It is expected to reverse any changes made by the ``->enable()``
callback when it was last invoked for the target CPU, free all memory
allocated by that callback and so on.
:c:member:`select`
::
int (*select) (struct cpuidle_driver *drv, struct cpuidle_device *dev,
bool *stop_tick);
Called to select an idle state for the processor holding the (logical)
CPU represented by the struct cpuidle_device object pointed to by the
``dev`` argument.
The list of idle states to take into consideration is represented by the
:c:member:`states` array of struct cpuidle_state objects held by the
struct cpuidle_driver object pointed to by the ``drv`` argument (which
represents the ``CPUIdle`` driver to be used with the CPU at hand). The
value returned by this callback is interpreted as an index into that
array (unless it is a negative error code).
The ``stop_tick`` argument is used to indicate whether or not to stop
the scheduler tick before asking the processor to enter the selected
idle state. When the ``bool`` variable pointed to by it (which is set
to ``true`` before invoking this callback) is cleared to ``false``, the
processor will be asked to enter the selected idle state without
stopping the scheduler tick on the given CPU (if the tick has been
stopped on that CPU already, however, it will not be restarted before
asking the processor to enter the idle state).
This callback is mandatory (i.e. the :c:member:`select` callback pointer
in struct cpuidle_governor must not be ``NULL`` for the registration
of the governor to succeed).
:c:member:`reflect`
::
void (*reflect) (struct cpuidle_device *dev, int index);
Called to allow the governor to evaluate the accuracy of the idle state
selection made by the ``->select()`` callback (when it was invoked last
time) and possibly use the result of that to improve the accuracy of
idle state selections in the future.
In addition, ``CPUIdle`` governors are required to take power management
quality of service (PM QoS) constraints on the processor wakeup latency into
account when selecting idle states. In order to obtain the current effective
PM QoS wakeup latency constraint for a given CPU, a ``CPUIdle`` governor is
expected to pass the number of the CPU to
:c:func:`cpuidle_governor_latency_req()`. Then, the governor's ``->select()``
callback must not return the index of an indle state whose
:c:member:`exit_latency` value is greater than the number returned by that
function.
CPU Idle Time Management Drivers
================================
CPU idle time management (``CPUIdle``) drivers provide an interface between the
other parts of ``CPUIdle`` and the hardware.
First of all, a ``CPUIdle`` driver has to populate the :c:member:`states` array
of struct cpuidle_state objects included in the struct cpuidle_driver object
representing it. Going forward this array will represent the list of available
idle states that the processor hardware can be asked to enter shared by all of
the logical CPUs handled by the given driver.
The entries in the :c:member:`states` array are expected to be sorted by the
value of the :c:member:`target_residency` field in struct cpuidle_state in
the ascending order (that is, index 0 should correspond to the idle state with
the minimum value of :c:member:`target_residency`). [Since the
:c:member:`target_residency` value is expected to reflect the "depth" of the
idle state represented by the struct cpuidle_state object holding it, this
sorting order should be the same as the ascending sorting order by the idle
state "depth".]
Three fields in struct cpuidle_state are used by the existing ``CPUIdle``
governors for computations related to idle state selection:
:c:member:`target_residency`
Minimum time to spend in this idle state including the time needed to
enter it (which may be substantial) to save more energy than could
be saved by staying in a shallower idle state for the same amount of
time, in microseconds.
:c:member:`exit_latency`
Maximum time it will take a CPU asking the processor to enter this idle
state to start executing the first instruction after a wakeup from it,
in microseconds.
:c:member:`flags`
Flags representing idle state properties. Currently, governors only use
the ``CPUIDLE_FLAG_POLLING`` flag which is set if the given object
does not represent a real idle state, but an interface to a software
"loop" that can be used in order to avoid asking the processor to enter
any idle state at all. [There are other flags used by the ``CPUIdle``
core in special situations.]
The :c:member:`enter` callback pointer in struct cpuidle_state, which must not
be ``NULL``, points to the routine to execute in order to ask the processor to
enter this particular idle state:
::
void (*enter) (struct cpuidle_device *dev, struct cpuidle_driver *drv,
int index);
The first two arguments of it point to the struct cpuidle_device object
representing the logical CPU running this callback and the
struct cpuidle_driver object representing the driver itself, respectively,
and the last one is an index of the struct cpuidle_state entry in the driver's
:c:member:`states` array representing the idle state to ask the processor to
enter.
The analogous ``->enter_s2idle()`` callback in struct cpuidle_state is used
only for implementing the suspend-to-idle system-wide power management feature.
The difference between in and ``->enter()`` is that it must not re-enable
interrupts at any point (even temporarily) or attempt to change the states of
clock event devices, which the ``->enter()`` callback may do sometimes.
Once the :c:member:`states` array has been populated, the number of valid
entries in it has to be stored in the :c:member:`state_count` field of the
struct cpuidle_driver object representing the driver. Moreover, if any
entries in the :c:member:`states` array represent "coupled" idle states (that
is, idle states that can only be asked for if multiple related logical CPUs are
idle), the :c:member:`safe_state_index` field in struct cpuidle_driver needs
to be the index of an idle state that is not "coupled" (that is, one that can be
asked for if only one logical CPU is idle).
In addition to that, if the given ``CPUIdle`` driver is only going to handle a
subset of logical CPUs in the system, the :c:member:`cpumask` field in its
struct cpuidle_driver object must point to the set (mask) of CPUs that will be
handled by it.
A ``CPUIdle`` driver can only be used after it has been registered. If there
are no "coupled" idle state entries in the driver's :c:member:`states` array,
that can be accomplished by passing the driver's struct cpuidle_driver object
to :c:func:`cpuidle_register_driver()`. Otherwise, :c:func:`cpuidle_register()`
should be used for this purpose.
However, it also is necessary to register struct cpuidle_device objects for
all of the logical CPUs to be handled by the given ``CPUIdle`` driver with the
help of :c:func:`cpuidle_register_device()` after the driver has been registered
and :c:func:`cpuidle_register_driver()`, unlike :c:func:`cpuidle_register()`,
does not do that automatically. For this reason, the drivers that use
:c:func:`cpuidle_register_driver()` to register themselves must also take care
of registering the struct cpuidle_device objects as needed, so it is generally
recommended to use :c:func:`cpuidle_register()` for ``CPUIdle`` driver
registration in all cases.
The registration of a struct cpuidle_device object causes the ``CPUIdle``
``sysfs`` interface to be created and the governor's ``->enable()`` callback to
be invoked for the logical CPU represented by it, so it must take place after
registering the driver that will handle the CPU in question.
``CPUIdle`` drivers and struct cpuidle_device objects can be unregistered
when they are not necessary any more which allows some resources associated with
them to be released. Due to dependencies between them, all of the
struct cpuidle_device objects representing CPUs handled by the given
``CPUIdle`` driver must be unregistered, with the help of
:c:func:`cpuidle_unregister_device()`, before calling
:c:func:`cpuidle_unregister_driver()` to unregister the driver. Alternatively,
:c:func:`cpuidle_unregister()` can be called to unregister a ``CPUIdle`` driver
along with all of the struct cpuidle_device objects representing CPUs handled
by it.
``CPUIdle`` drivers can respond to runtime system configuration changes that
lead to modifications of the list of available processor idle states (which can
happen, for example, when the system's power source is switched from AC to
battery or the other way around). Upon a notification of such a change,
a ``CPUIdle`` driver is expected to call :c:func:`cpuidle_pause_and_lock()` to
turn ``CPUIdle`` off temporarily and then :c:func:`cpuidle_disable_device()` for
all of the struct cpuidle_device objects representing CPUs affected by that
change. Next, it can update its :c:member:`states` array in accordance with
the new configuration of the system, call :c:func:`cpuidle_enable_device()` for
all of the relevant struct cpuidle_device objects and invoke
:c:func:`cpuidle_resume_and_unlock()` to allow ``CPUIdle`` to be used again.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
CPU idle time management subsystem
1-39system의 logical CPU, 즉 hardware thread 또는 processor core가 interrupt 같은 wakeup event 뒤에 실행할 task 없이 CPU별 special `idle` task만 남은 상태라면 processor energy를 절약할 기회가 생깁니다. idle CPU가 memory에서 instruction fetching을 멈추고 자신이 의존하는 processor functional unit 일부를 저전력 idle state로 전환할 수 있기 때문입니다.
hardware는 서로 다른 power saving과 wakeup cost를 가진 여러 idle state를 제공할 수 있습니다. kernel은 현재 상황에 가장 알맞은 state를 선택하고 processor에 그 state로 진입하도록 요청해야 하며, 이 역할을 맡는 subsystem이 `CPUIdle`입니다.
`CPUIdle`은 hardware-independent code 중복을 피하도록 modular하게 설계됩니다. governor는 processor에 요청할 idle state를 선택하고, driver는 그 결정을 hardware에 전달하며, core는 governor와 driver를 잇는 공통 framework를 제공합니다.
idle 기회가 생기면 policy 선택과 hardware 진입을 분리해 처리합니다.
.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>
========================
CPU Idle Time Management
========================
:Copyright: |copy| 2019 Intel Corporation
:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
CPU Idle Time Management Subsystem
==================================
Every time one of the logical CPUs in the system (the entities that appear to
fetch and execute instructions: hardware threads, if present, or processor
cores) is idle after an interrupt or equivalent wakeup event, which means that
there are no tasks to run on it except for the special "idle" task associated
with it, there is an opportunity to save energy for the processor that it
belongs to. That can be done by making the idle logical CPU stop fetching
instructions from memory and putting some of the processor's functional units
depended on by it into an idle state in which they will draw less power.
However, there may be multiple different idle states that can be used in such a
situation in principle, so it may be necessary to find the most suitable one
(from the kernel perspective) and ask the processor to use (or "enter") that
particular idle state. That is the role of the CPU idle time management
subsystem in the kernel, called ``CPUIdle``.
The design of ``CPUIdle`` is modular and based on the code duplication avoidance
principle, so the generic code that in principle need not depend on the hardware
or platform design details in it is separate from the code that interacts with
the hardware. It generally is divided into three categories of functional
units: *governors* responsible for selecting idle states to ask the processor
to enter, *drivers* that pass the governors' decisions on to the hardware and
the *core* providing a common framework for them.
governor 구조와 선택·등록
40-71CPUIdle governor는 logical CPU가 idle임이 확인될 때 호출되는 policy code 묶음이며, energy를 절약하기 위해 processor가 들어갈 idle state를 선택합니다. governor는 어느 Linux hardware platform에서도 사용할 수 있는 generic code이므로 자신이 다루는 data structure도 architecture나 platform 세부사항에 의존하면 안 됩니다.
governor는 `struct cpuidle_governor`로 표현됩니다. 여기에는 `enable`, `disable`, `select`, `reflect` 네 callback pointer, 우선순위를 나타내는 `rating`, 식별용 name string이 들어갑니다.
governor를 사용 가능하게 만들려면 `cpuidle_register_governor()`에 object pointer를 넘겨 core의 global governor list에 등록합니다. list의 첫 governor이거나 새 `rating`이 현재 governor보다 높거나, kernel command line의 `cpuidle.governor=` 값이 새 governor 이름과 일치하면 새 governor가 활성화됩니다. 동시에 사용할 수 있는 CPUIdle governor는 하나뿐이며 user space는 runtime에 `sysfs`로 선택할 수도 있습니다.
한 번 등록한 CPUIdle governor는 unregister할 수 없습니다. 따라서 loadable kernel module에 governor를 넣는 방식은 실용적이지 않습니다.
CPU Idle Time Governors
=======================
A CPU idle time (``CPUIdle``) governor is a bundle of policy code invoked when
one of the logical CPUs in the system turns out to be idle. Its role is to
select an idle state to ask the processor to enter in order to save some energy.
``CPUIdle`` governors are generic and each of them can be used on any hardware
platform that the Linux kernel can run on. For this reason, data structures
operated on by them cannot depend on any hardware architecture or platform
design details as well.
The governor itself is represented by a struct cpuidle_governor object
containing four callback pointers, :c:member:`enable`, :c:member:`disable`,
:c:member:`select`, :c:member:`reflect`, a :c:member:`rating` field described
below, and a name (string) used for identifying it.
For the governor to be available at all, that object needs to be registered
with the ``CPUIdle`` core by calling :c:func:`cpuidle_register_governor()` with
a pointer to it passed as the argument. If successful, that causes the core to
add the governor to the global list of available governors and, if it is the
only one in the list (that is, the list was empty before) or the value of its
:c:member:`rating` field is greater than the value of that field for the
governor currently in use, or the name of the new governor was passed to the
kernel as the value of the ``cpuidle.governor=`` command line parameter, the new
governor will be used from that point on (there can be only one ``CPUIdle``
governor in use at a time). Also, user space can choose the ``CPUIdle``
governor to use at run time via ``sysfs``.
Once registered, ``CPUIdle`` governors cannot be unregistered, so it is not
practical to put them into loadable kernel modules.
CPU별 governor enable과 disable
72-105`enable(struct cpuidle_driver *drv, struct cpuidle_device *dev)` callback은 `dev`가 나타내는 logical CPU를 governor가 처리할 수 있도록 준비합니다. `drv`는 그 CPU에 사용할 CPUIdle driver를 가리키며, processor가 진입할 수 있는 `struct cpuidle_state` 목록도 포함합니다.
`enable`은 실패할 수 있으며 이때 negative error code를 반환합니다. 그러면 kernel은 해당 CPU에 대해 CPUIdle 대신 architecture-specific default idle code를 실행합니다. 나중에 그 CPU의 governor `enable` callback이 다시 성공적으로 호출될 때까지 이 fallback이 유지됩니다.
`disable(struct cpuidle_driver *drv, struct cpuidle_device *dev)`은 governor가 대상 logical CPU를 더 이상 처리하지 않게 합니다. 마지막 `enable`이 적용한 변경을 되돌리고 callback이 할당한 memory와 resource를 모두 해제해야 합니다.
enable 실패는 subsystem 전체가 아니라 해당 CPU를 architecture fallback으로 보냅니다.
The interface between ``CPUIdle`` governors and the core consists of four
callbacks:
:c:member:`enable`
::
int (*enable) (struct cpuidle_driver *drv, struct cpuidle_device *dev);
The role of this callback is to prepare the governor for handling the
(logical) CPU represented by the struct cpuidle_device object pointed
to by the ``dev`` argument. The struct cpuidle_driver object pointed
to by the ``drv`` argument represents the ``CPUIdle`` driver to be used
with that CPU (among other things, it should contain the list of
struct cpuidle_state objects representing idle states that the
processor holding the given CPU can be asked to enter).
It may fail, in which case it is expected to return a negative error
code, and that causes the kernel to run the architecture-specific
default code for idle CPUs on the CPU in question instead of ``CPUIdle``
until the ``->enable()`` governor callback is invoked for that CPU
again.
:c:member:`disable`
::
void (*disable) (struct cpuidle_driver *drv, struct cpuidle_device *dev);
Called to make the governor stop handling the (logical) CPU represented
by the struct cpuidle_device object pointed to by the ``dev``
argument.
It is expected to reverse any changes made by the ``->enable()``
callback when it was last invoked for the target CPU, free all memory
allocated by that callback and so on.
idle state 선택, tick 제어, feedback와 PM QoS
106-155`select(struct cpuidle_driver *drv, struct cpuidle_device *dev, bool *stop_tick)` callback은 `dev`가 나타내는 CPU를 가진 processor가 들어갈 idle state를 선택합니다. 후보는 `drv->states`의 `struct cpuidle_state` 배열이며, 반환값은 negative error가 아닌 경우 이 배열의 index로 해석됩니다.
`stop_tick`이 가리키는 bool은 callback 호출 전에 true로 설정됩니다. governor가 false로 지우면 scheduler tick을 멈추지 않고 선택 state에 진입합니다. 다만 해당 CPU의 tick이 이미 멈춰 있었다면 진입 전에 다시 시작하지 않습니다. `select`는 필수 callback이므로 `struct cpuidle_governor`의 pointer가 `NULL`이면 governor 등록에 실패합니다.
`reflect(struct cpuidle_device *dev, int index)` callback은 직전 `select` 결정의 정확도를 평가하고 그 결과를 다음 idle-state 선택 개선에 사용할 기회를 governor에 제공합니다.
governor는 processor wakeup latency에 대한 PM QoS constraint도 반영해야 합니다. CPU number를 `cpuidle_governor_latency_req()`에 넘겨 현재 effective limit를 얻고, `select`는 그 값보다 `exit_latency`가 큰 idle state index를 반환해서는 안 됩니다.
latency constraint 안에서 state index와 scheduler tick 정책을 결정하고 실제 결과를 반영합니다.
:c:member:`select`
::
int (*select) (struct cpuidle_driver *drv, struct cpuidle_device *dev,
bool *stop_tick);
Called to select an idle state for the processor holding the (logical)
CPU represented by the struct cpuidle_device object pointed to by the
``dev`` argument.
The list of idle states to take into consideration is represented by the
:c:member:`states` array of struct cpuidle_state objects held by the
struct cpuidle_driver object pointed to by the ``drv`` argument (which
represents the ``CPUIdle`` driver to be used with the CPU at hand). The
value returned by this callback is interpreted as an index into that
array (unless it is a negative error code).
The ``stop_tick`` argument is used to indicate whether or not to stop
the scheduler tick before asking the processor to enter the selected
idle state. When the ``bool`` variable pointed to by it (which is set
to ``true`` before invoking this callback) is cleared to ``false``, the
processor will be asked to enter the selected idle state without
stopping the scheduler tick on the given CPU (if the tick has been
stopped on that CPU already, however, it will not be restarted before
asking the processor to enter the idle state).
This callback is mandatory (i.e. the :c:member:`select` callback pointer
in struct cpuidle_governor must not be ``NULL`` for the registration
of the governor to succeed).
:c:member:`reflect`
::
void (*reflect) (struct cpuidle_device *dev, int index);
Called to allow the governor to evaluate the accuracy of the idle state
selection made by the ``->select()`` callback (when it was invoked last
time) and possibly use the result of that to improve the accuracy of
idle state selections in the future.
In addition, ``CPUIdle`` governors are required to take power management
quality of service (PM QoS) constraints on the processor wakeup latency into
account when selecting idle states. In order to obtain the current effective
PM QoS wakeup latency constraint for a given CPU, a ``CPUIdle`` governor is
expected to pass the number of the CPU to
:c:func:`cpuidle_governor_latency_req()`. Then, the governor's ``->select()``
callback must not return the index of an indle state whose
:c:member:`exit_latency` value is greater than the number returned by that
function.
CPUIdle driver와 idle-state selection 필드
156-200CPUIdle driver는 subsystem의 나머지 부분과 hardware 사이의 interface를 제공합니다. 먼저 자신을 나타내는 `struct cpuidle_driver` 안의 `states` 배열을 `struct cpuidle_state` 항목으로 채웁니다. 이 목록은 해당 driver가 처리하는 모든 logical CPU가 공유하는 processor idle state 집합입니다.
`states` 항목은 `target_residency`가 작은 순서로 정렬해야 합니다. index 0은 최소 target residency를 가진 가장 얕은 state가 됩니다. target residency가 state의 depth를 반영하므로 이 순서는 일반적으로 얕은 state에서 깊은 state 순서와 같습니다.
기존 governor가 선택 계산에 사용하는 주요 필드는 세 가지입니다. `target_residency`는 진입 시간까지 포함해 더 얕은 state보다 energy를 더 절약하려면 머물러야 하는 최소 시간이며 microseconds 단위입니다. `exit_latency`는 wakeup 뒤 CPU가 첫 instruction 실행을 시작하기까지 걸릴 수 있는 최대 시간으로 역시 microseconds 단위입니다.
`flags`는 idle-state property를 나타냅니다. governor는 현재 `CPUIDLE_FLAG_POLLING`을 사용하며, 이 flag는 실제 hardware idle state 대신 processor idle 진입을 피하는 software polling loop interface임을 나타냅니다. core가 특수 상황에서 사용하는 다른 flag들도 있습니다.
CPU Idle Time Management Drivers
================================
CPU idle time management (``CPUIdle``) drivers provide an interface between the
other parts of ``CPUIdle`` and the hardware.
First of all, a ``CPUIdle`` driver has to populate the :c:member:`states` array
of struct cpuidle_state objects included in the struct cpuidle_driver object
representing it. Going forward this array will represent the list of available
idle states that the processor hardware can be asked to enter shared by all of
the logical CPUs handled by the given driver.
The entries in the :c:member:`states` array are expected to be sorted by the
value of the :c:member:`target_residency` field in struct cpuidle_state in
the ascending order (that is, index 0 should correspond to the idle state with
the minimum value of :c:member:`target_residency`). [Since the
:c:member:`target_residency` value is expected to reflect the "depth" of the
idle state represented by the struct cpuidle_state object holding it, this
sorting order should be the same as the ascending sorting order by the idle
state "depth".]
Three fields in struct cpuidle_state are used by the existing ``CPUIdle``
governors for computations related to idle state selection:
:c:member:`target_residency`
Minimum time to spend in this idle state including the time needed to
enter it (which may be substantial) to save more energy than could
be saved by staying in a shallower idle state for the same amount of
time, in microseconds.
:c:member:`exit_latency`
Maximum time it will take a CPU asking the processor to enter this idle
state to start executing the first instruction after a wakeup from it,
in microseconds.
:c:member:`flags`
Flags representing idle state properties. Currently, governors only use
the ``CPUIDLE_FLAG_POLLING`` flag which is set if the given object
does not represent a real idle state, but an interface to a software
"loop" that can be used in order to avoid asking the processor to enter
any idle state at all. [There are other flags used by the ``CPUIdle``
core in special situations.]
state 진입 callback과 coupled-state metadata
201-235각 `struct cpuidle_state`의 필수 `enter` callback은 processor에 해당 idle state 진입을 요청하는 routine을 가리키며 `NULL`이면 안 됩니다. 인자는 현재 logical CPU의 `struct cpuidle_device`, driver의 `struct cpuidle_driver`, 그리고 `drv->states`에서 선택 state를 가리키는 index입니다.
대응하는 `enter_s2idle()` callback은 system-wide suspend-to-idle 구현에만 사용합니다. 일반 `enter()`와 달리 어느 시점에도 interrupt를 다시 enable해서는 안 되고, `enter()`가 때때로 수행할 수 있는 clock event device state 변경도 시도하면 안 됩니다.
`states`를 채운 뒤 valid entry 수를 driver의 `state_count`에 기록합니다. 여러 관련 logical CPU가 함께 idle일 때만 사용할 수 있는 coupled state가 있으면 `safe_state_index`는 CPU 하나만 idle이어도 요청 가능한 non-coupled state를 가리켜야 합니다.
driver가 system의 logical CPU 일부만 처리한다면 `cpumask`가 그 CPU 집합을 가리키도록 설정합니다.
The :c:member:`enter` callback pointer in struct cpuidle_state, which must not
be ``NULL``, points to the routine to execute in order to ask the processor to
enter this particular idle state:
::
void (*enter) (struct cpuidle_device *dev, struct cpuidle_driver *drv,
int index);
The first two arguments of it point to the struct cpuidle_device object
representing the logical CPU running this callback and the
struct cpuidle_driver object representing the driver itself, respectively,
and the last one is an index of the struct cpuidle_state entry in the driver's
:c:member:`states` array representing the idle state to ask the processor to
enter.
The analogous ``->enter_s2idle()`` callback in struct cpuidle_state is used
only for implementing the suspend-to-idle system-wide power management feature.
The difference between in and ``->enter()`` is that it must not re-enable
interrupts at any point (even temporarily) or attempt to change the states of
clock event devices, which the ``->enter()`` callback may do sometimes.
Once the :c:member:`states` array has been populated, the number of valid
entries in it has to be stored in the :c:member:`state_count` field of the
struct cpuidle_driver object representing the driver. Moreover, if any
entries in the :c:member:`states` array represent "coupled" idle states (that
is, idle states that can only be asked for if multiple related logical CPUs are
idle), the :c:member:`safe_state_index` field in struct cpuidle_driver needs
to be the index of an idle state that is not "coupled" (that is, one that can be
asked for if only one logical CPU is idle).
In addition to that, if the given ``CPUIdle`` driver is only going to handle a
subset of logical CPUs in the system, the :c:member:`cpumask` field in its
struct cpuidle_driver object must point to the set (mask) of CPUs that will be
handled by it.
driver·device 등록과 해제 순서
236-267CPUIdle driver는 등록한 뒤에만 사용할 수 있습니다. `states`에 coupled idle state가 없다면 `cpuidle_register_driver()`에 `struct cpuidle_driver`를 넘길 수 있고, coupled state가 있다면 `cpuidle_register()`를 사용합니다.
driver 등록 뒤에는 처리할 모든 logical CPU의 `struct cpuidle_device`도 등록해야 합니다. `cpuidle_register_device()`가 이를 수행합니다. `cpuidle_register_driver()`는 device 등록을 자동으로 하지 않지만 `cpuidle_register()`는 함께 처리하므로, 일반적으로 모든 경우에 `cpuidle_register()` 사용이 권장됩니다.
cpuidle_device 등록은 해당 CPU의 CPUIdle `sysfs` interface를 만들고 governor `enable` callback을 호출합니다. 따라서 반드시 CPU를 처리할 driver가 먼저 등록된 뒤 device를 등록해야 합니다.
해제 순서는 의존성의 역순입니다. `cpuidle_unregister_device()`로 driver가 처리하는 모든 CPU device를 먼저 해제한 뒤 `cpuidle_unregister_driver()`를 호출합니다. 또는 `cpuidle_unregister()`로 driver와 그 CPU device들을 함께 해제할 수 있습니다.
driver가 CPU device보다 먼저 생기고 나중에 사라집니다.
A ``CPUIdle`` driver can only be used after it has been registered. If there
are no "coupled" idle state entries in the driver's :c:member:`states` array,
that can be accomplished by passing the driver's struct cpuidle_driver object
to :c:func:`cpuidle_register_driver()`. Otherwise, :c:func:`cpuidle_register()`
should be used for this purpose.
However, it also is necessary to register struct cpuidle_device objects for
all of the logical CPUs to be handled by the given ``CPUIdle`` driver with the
help of :c:func:`cpuidle_register_device()` after the driver has been registered
and :c:func:`cpuidle_register_driver()`, unlike :c:func:`cpuidle_register()`,
does not do that automatically. For this reason, the drivers that use
:c:func:`cpuidle_register_driver()` to register themselves must also take care
of registering the struct cpuidle_device objects as needed, so it is generally
recommended to use :c:func:`cpuidle_register()` for ``CPUIdle`` driver
registration in all cases.
The registration of a struct cpuidle_device object causes the ``CPUIdle``
``sysfs`` interface to be created and the governor's ``->enable()`` callback to
be invoked for the logical CPU represented by it, so it must take place after
registering the driver that will handle the CPU in question.
``CPUIdle`` drivers and struct cpuidle_device objects can be unregistered
when they are not necessary any more which allows some resources associated with
them to be released. Due to dependencies between them, all of the
struct cpuidle_device objects representing CPUs handled by the given
``CPUIdle`` driver must be unregistered, with the help of
:c:func:`cpuidle_unregister_device()`, before calling
:c:func:`cpuidle_unregister_driver()` to unregister the driver. Alternatively,
:c:func:`cpuidle_unregister()` can be called to unregister a ``CPUIdle`` driver
along with all of the struct cpuidle_device objects representing CPUs handled
by it.
runtime idle-state 목록 재구성
268-279AC 전원과 battery 전환처럼 system configuration이 바뀌면 사용 가능한 processor idle-state 목록도 달라질 수 있습니다. CPUIdle driver는 이런 runtime notification에 대응해 core와 CPU별 device를 안전하게 정지한 뒤 `states` 배열을 갱신합니다.
먼저 `cpuidle_pause_and_lock()`으로 CPUIdle을 임시 중지하고 변경 영향을 받는 모든 `struct cpuidle_device`에 `cpuidle_disable_device()`를 호출합니다. 새 configuration에 맞게 `states` 배열을 수정한 뒤 관련 device마다 `cpuidle_enable_device()`를 호출하고, 마지막으로 `cpuidle_resume_and_unlock()`으로 CPUIdle 사용을 다시 허용합니다.
global pause와 CPU별 disable 사이에서만 driver state 목록을 수정합니다.
``CPUIdle`` drivers can respond to runtime system configuration changes that
lead to modifications of the list of available processor idle states (which can
happen, for example, when the system's power source is switched from AC to
battery or the other way around). Upon a notification of such a change,
a ``CPUIdle`` driver is expected to call :c:func:`cpuidle_pause_and_lock()` to
turn ``CPUIdle`` off temporarily and then :c:func:`cpuidle_disable_device()` for
all of the struct cpuidle_device objects representing CPUs affected by that
change. Next, it can update its :c:member:`states` array in accordance with
the new configuration of the system, call :c:func:`cpuidle_enable_device()` for
all of the relevant struct cpuidle_device objects and invoke
:c:func:`cpuidle_resume_and_unlock()` to allow ``CPUIdle`` to be used again.
요약과 해설
cpuidle.rst:1-279CPUIdle은 governor가 generic policy로 idle state를 선택하고 driver가 hardware 진입을 수행하며 core가 두 계층과 CPU별 device lifecycle을 조정합니다. governor는 PM QoS wakeup latency 안에서 state를 고르고, driver는 target residency 순으로 states 배열을 제공하며, driver·device 등록 순서와 runtime pause/disable/update/enable/resume 절차를 지켜야 합니다.