20分でわかった事にする
  Power Management
      cpuidle編
@magoroku15 最底辺活動家
Androidzaurusのつぶやき


                     使用未許諾
• われらの恐竜先生、販売日にTegra 3のタブ
  レットをご購入
• 買った、直後の勉強会にてustream送出マ
  シンとして華麗にデビュー
• 独自の視点での解析 -お約束ですね-
Android Zairusの日記




                    使用未許諾
GovernorはInteractive

What dose this mean?

     Governor?
Power management ちょー入門
• 家庭のパワーマネジメント
 – 照明はコマメに消す
 – 冷房は設定温度を高めに
 →住人が決める・操作する
• CPUのパワーマネジメント
 – 不要なものは止める
 – 処理速度と落とす
 →どうやって決めるのか?操作するの
  か?
UNIX/BSD/Mac/Linux


   App

System call



                     動かすプロセスが無いとidleを呼ぶ

                    KERNEL
                               idle

              HDD
BSD 4.3
GENERIC/locore.c
1498      .globl Idle
1499 Idle: idle:
1500      mtpr $0,$IPL     # must allow interrupts here
1501      tstl _whichqs    # look for non-empty queue
1502      bneq sw1
1503      brb idle
Tegraのidle
Kernel_V9_4_2_7/arch/arm/mach-tegra
static int tegra_cpuidle_register_device(unsigned int cpu)     // cpuidleへの登録
{
   :
   state->enter = tegra_idle_enter_lp2;
   :
}
static inline void tegra_idle_lp2(struct cpuidle_device *dev,
                        struct cpuidle_state *state)
{
#ifdef CONFIG_ARCH_TEGRA_2x_SOC                       // tegra2の場合
        tegra2_idle_lp2(dev, state);
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC                       // tegra3の場合
        tegra3_idle_lp2(dev, state);
#endif
}
Tegra3のidle
Kernel_V9_4_2_7/arch/arm/mach-tegra/sleep.S
void tegra3_idle_lp2(struct cpuidle_device *dev,
                           struct cpuidle_state *state)
{
        s64 request = ktime_to_us(tick_nohz_get_sleep_length());
        bool last_cpu = tegra_set_cpu_in_lp2(dev->cpu);

       cpu_pm_enter();

       if (last_cpu && (dev->cpu == 0))              // CPU0だけ別扱い
               tegra3_idle_enter_lp2_cpu_0(dev, state, request);
       else
               tegra3_idle_enter_lp2_cpu_n(dev, state, request);

       cpu_pm_exit();
       tegra_clear_cpu_in_lp2(dev->cpu);
}
Tegra3のidle
Kernel_V9_4_2_7/arch/arm/mach-tegra/sleep.S
ENTRY(tegra_cpu_wfi)
        cpu_id r0
        cpu_to_halt_reg r1, r0
        cpu_to_csr_reg r2, r0
        mov32 r0, TEGRA_FLOW_CTRL_VIRT
        mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
        str     r3, [r0, r2]            @ clear event & interrupt status
        mov     r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
        str     r3, [r0, r1]            @ put flow controller in wait irq mode
        dsb
        wfi
        mov     r3, #0
        str     r3, [r0, r1]            @ clear flow controller halt status
        mov     r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
        str     r3, [r0, r2]            @ clear event & interrupt status
        dsb
        mov     pc, lr
ENDPROC(tegra_cpu_wfi)
WFI Wait For Interrupt
• ARMの命令
• 割り込が発生するまで、CPUを低電力モード
  で命令の実行を止める
• 眠りの深さ/寝起きの良さ
 – 深く眠ると
  • 電力低減効果大/寝起きは悪い
  • もっさり
 – 浅く眠ると
  • 電力低減効果小/寝起きは良い
  • さくさく
• WFIを呼ぶ前に眠りの深さを指定する
おっと
• この時点でTegraのStateを理解していない
  事に気づく
• Flow controllerって何?
Omap3のidle
int __init omap3_idle_init(void)
{
     :
     state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ?
              omap3_enter_idle_bm : omap3_enter_idle;
     :
}

static int omap3_enter_idle(struct cpuidle_device *dev,
              struct cpuidle_state *state)
{
     :
}
omap3のC-ステート
#define OMAP3_STATE_C1 0      /* C1 - MPU WFI + Core active */

                           IDLE
昼寝
#define OMAP3_STATE_C2 1      /* C2 - MPU WFI + Core inactive */
#define OMAP3_STATE_C3 2      /* C3 - MPU CSWR + Core inactive */
#define OMAP3_STATE_C4 3      /* C4 - MPU OFF + Core iactive */
#define OMAP3_STATE_C5 4      /* C5 - MPU RET + Core RET */
#define OMAP3_STATE_C6 5      /* C6 - MPU OFF + Core RET */
#define OMAP3_STATE_C7 6      /* C7 - MPU OFF + Core OFF */

爆睡
ステートの指定はどうするの?
• CPUIdle Framework
  – CPU依存のCステート
  – Governor(統治者)によるポリシーベースの管理
  – /sys/power/cpuidle_deepest_state
  – /sys/proc/pm_prepwstst
• Governor
  – “ladder”,”menu”
  – drivers/cpuidle/governors
cpuidleの構成

    /sys/devices/syste/cpu/cpuidle                     ユーザレベル
                                                       インターフェース




 menu           ladder                                 Governor

                                                       Cpuidle アーキ無依存
                    Generic cpuidle


omap3-cpuidle       tegra2-cpuidle    tegra3-cpuidle   Cpuidle アーキ依存
cpuidle
• 実行可能なプロセスがない状態を管理
 – 昔は単純な停止orループ
 – ARMでは命令を追加して明にidleを通知 WFI
 – WFIを呼ぶ前に、寝る深さC-Stateを指定
• 標準でLadderとmenuのGovernor
 – ユーザプログラムで統計情報から指定も可
• 他の省電力機能もcpuidleを起点に動作
他のフレームワーク
• cpufreq
  – 動作周波数を変更
  – 電源電圧も合わせて変更
• runtime_pm
  – SoC内部コアを機能単位ごとに停止するヒントを
    管理
  – SoC内の機能毎にusecountを用意し、idleのタイミ
    ング未使用の機能を止める
  – Beagle のpm_branchで実機評価可能
• cpuhotplug
  – cpuidleのC-state変更をCPU単位に拡張
上級者向けの話題
• Runtime_PM
  – http://elinux.org/OMAP_Power_Management
  – http://git.kernel.org/?p=linux/kernel/git/khilman/l
    inux-omap-pm.git
• BeagleboardでSleep時の電流を8mWにした
  話
  – http://groups.google.com/group/beagleboard/bro
    wse_thread/thread/197a8ef6b46cc828
  – 回路を改造して、ボード上のコントローラの
    電源供給を止める
おわり

20分でわかった事にするパワーマネジメント

  • 1.
    20分でわかった事にする PowerManagement cpuidle編 @magoroku15 最底辺活動家
  • 2.
    Androidzaurusのつぶやき 使用未許諾 • われらの恐竜先生、販売日にTegra 3のタブ レットをご購入 • 買った、直後の勉強会にてustream送出マ シンとして華麗にデビュー • 独自の視点での解析 -お約束ですね-
  • 3.
    Android Zairusの日記 使用未許諾
  • 4.
  • 5.
    Power management ちょー入門 •家庭のパワーマネジメント – 照明はコマメに消す – 冷房は設定温度を高めに →住人が決める・操作する • CPUのパワーマネジメント – 不要なものは止める – 処理速度と落とす →どうやって決めるのか?操作するの か?
  • 6.
    UNIX/BSD/Mac/Linux App System call 動かすプロセスが無いとidleを呼ぶ KERNEL idle HDD
  • 7.
    BSD 4.3 GENERIC/locore.c 1498 .globl Idle 1499 Idle: idle: 1500 mtpr $0,$IPL # must allow interrupts here 1501 tstl _whichqs # look for non-empty queue 1502 bneq sw1 1503 brb idle
  • 8.
    Tegraのidle Kernel_V9_4_2_7/arch/arm/mach-tegra static int tegra_cpuidle_register_device(unsignedint cpu) // cpuidleへの登録 { : state->enter = tegra_idle_enter_lp2; : } static inline void tegra_idle_lp2(struct cpuidle_device *dev, struct cpuidle_state *state) { #ifdef CONFIG_ARCH_TEGRA_2x_SOC // tegra2の場合 tegra2_idle_lp2(dev, state); #endif #ifdef CONFIG_ARCH_TEGRA_3x_SOC // tegra3の場合 tegra3_idle_lp2(dev, state); #endif }
  • 9.
    Tegra3のidle Kernel_V9_4_2_7/arch/arm/mach-tegra/sleep.S void tegra3_idle_lp2(struct cpuidle_device*dev, struct cpuidle_state *state) { s64 request = ktime_to_us(tick_nohz_get_sleep_length()); bool last_cpu = tegra_set_cpu_in_lp2(dev->cpu); cpu_pm_enter(); if (last_cpu && (dev->cpu == 0)) // CPU0だけ別扱い tegra3_idle_enter_lp2_cpu_0(dev, state, request); else tegra3_idle_enter_lp2_cpu_n(dev, state, request); cpu_pm_exit(); tegra_clear_cpu_in_lp2(dev->cpu); }
  • 10.
    Tegra3のidle Kernel_V9_4_2_7/arch/arm/mach-tegra/sleep.S ENTRY(tegra_cpu_wfi) cpu_id r0 cpu_to_halt_reg r1, r0 cpu_to_csr_reg r2, r0 mov32 r0, TEGRA_FLOW_CTRL_VIRT mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG str r3, [r0, r2] @ clear event & interrupt status mov r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME str r3, [r0, r1] @ put flow controller in wait irq mode dsb wfi mov r3, #0 str r3, [r0, r1] @ clear flow controller halt status mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG str r3, [r0, r2] @ clear event & interrupt status dsb mov pc, lr ENDPROC(tegra_cpu_wfi)
  • 11.
    WFI Wait ForInterrupt • ARMの命令 • 割り込が発生するまで、CPUを低電力モード で命令の実行を止める • 眠りの深さ/寝起きの良さ – 深く眠ると • 電力低減効果大/寝起きは悪い • もっさり – 浅く眠ると • 電力低減効果小/寝起きは良い • さくさく • WFIを呼ぶ前に眠りの深さを指定する
  • 12.
    おっと • この時点でTegraのStateを理解していない 事に気づく • Flow controllerって何?
  • 13.
    Omap3のidle int __init omap3_idle_init(void) { : state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ? omap3_enter_idle_bm : omap3_enter_idle; : } static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { : }
  • 14.
    omap3のC-ステート #define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */ IDLE 昼寝 #define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */ #define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */ #define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */ #define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */ #define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */ #define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */ 爆睡
  • 15.
    ステートの指定はどうするの? • CPUIdle Framework – CPU依存のCステート – Governor(統治者)によるポリシーベースの管理 – /sys/power/cpuidle_deepest_state – /sys/proc/pm_prepwstst • Governor – “ladder”,”menu” – drivers/cpuidle/governors
  • 16.
    cpuidleの構成 /sys/devices/syste/cpu/cpuidle ユーザレベル インターフェース menu ladder Governor Cpuidle アーキ無依存 Generic cpuidle omap3-cpuidle tegra2-cpuidle tegra3-cpuidle Cpuidle アーキ依存
  • 17.
    cpuidle • 実行可能なプロセスがない状態を管理 –昔は単純な停止orループ – ARMでは命令を追加して明にidleを通知 WFI – WFIを呼ぶ前に、寝る深さC-Stateを指定 • 標準でLadderとmenuのGovernor – ユーザプログラムで統計情報から指定も可 • 他の省電力機能もcpuidleを起点に動作
  • 18.
    他のフレームワーク • cpufreq – 動作周波数を変更 – 電源電圧も合わせて変更 • runtime_pm – SoC内部コアを機能単位ごとに停止するヒントを 管理 – SoC内の機能毎にusecountを用意し、idleのタイミ ング未使用の機能を止める – Beagle のpm_branchで実機評価可能 • cpuhotplug – cpuidleのC-state変更をCPU単位に拡張
  • 19.
    上級者向けの話題 • Runtime_PM – http://elinux.org/OMAP_Power_Management – http://git.kernel.org/?p=linux/kernel/git/khilman/l inux-omap-pm.git • BeagleboardでSleep時の電流を8mWにした 話 – http://groups.google.com/group/beagleboard/bro wse_thread/thread/197a8ef6b46cc828 – 回路を改造して、ボード上のコントローラの 電源供給を止める
  • 20.