linuxのfull ticklessを試してみた
DESCRIPTION
第九回カーネル/VM探検隊での発表スライドTRANSCRIPT
LinuxのFull ticklessを試してみた第九回カーネル/VM探検隊
Hiraku Toyooka (@hiraku_wfs)
自己紹介
• 豊岡 拓(とよおか ひらく)
• Twitter: @hiraku_wfs
• 横浜でLinuxのお仕事してます
• が、今日は業務とは直接関係ない話
Ticklessとは• CPUが暇な(idle)時にtickを入れなくする
• 省電力
• Linux, FreeBSDなどに実装されている
timetask task
1ms tickless
idle
Full tickless• CPUが暇じゃなくてもtickを消す
• Linux 3.10から導入された
• tickのオーバヘッドが無くなる
timetask A task B
tickless
どんなワークロードのため?• Real-time • 最悪レイテンシを下げたい(極限まで)
• HPC • スループットを上げたい(極限まで)
※ただし、現在は以下の制約がある
• CPUで動作可能なタスクが1個の時だけtickを止める
• 1秒に1回はtickを入れないといけない
• CPU0はfull tickless modeにはならない
ビルド• Fedoraなど一般的なディストロのカーネルでは無効化されている
• git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
• menuconfigで”Full dynticks system”を有効化(CONFIG_NO_HZ_FULL=y)してコンパイル
実行• x86_64 2コア(CPU0, CPU1)環境で実行 • 起動パラメータに”nohz_full=1”を追加 • CPU1のみfull tickless可能に
• dmesg | grep NO_HZ • “NO_HZ: Full dynticks CPUs: 1.” ならOK • sched_clock(TSCとか)の進みが不安定な環境ではNGになる (例: VirtualBox on Mac OS X)
dynticks-testing(*1)
• CPU1でビジーループを10秒走らせて、その間tickがどれだけ入ったかを記録
• カーネルトレース(ftrace)の結果が出てくる
• Full ticklessのための事前セットアップもやってくれる
• 全ての外部割り込み先、RCU関連カーネルスレッドをCPU0に移動
• ただし、他タスクがCPU1に入ってこないようにする設定はやってくれない ==> Cgroup cpusetで設定
*1 git://git.kernel.org/pub/scm/linux/kernel/git/frederic/dynticks-testing.git
結果# TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | rcuos/0-18 [001] 1233.121545: tick_stop: success=yes msg= user_loop-2412 [001] 1233.122098: tick_stop: success=no msg=more than 1 task in runqueue ! sleep-2413 [001] 1233.122419: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232550001205 sleep-2413 [001] 1233.122429: tick_stop: success=yes msg= sleep-2413 [001] 1233.122721: tick_stop: success=no msg=more than 1 task in runqueue ! sleep-2413 [001] 1233.122724: tick_stop: success=no msg=more than 1 task in runqueue ! user_loop-2412 [001] 1233.123419: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232551000974 user_loop-2412 [001] 1233.123431: tick_stop: success=yes msg= user_loop-2412 [001] 1233.123435: tick_stop: success=no msg=more than 1 task in runqueue ! user_loop-2412 [001] 1233.123436: tick_stop: success=no msg=more than 1 task in runqueue ! user_loop-2412 [001] 1233.123439: tick_stop: success=yes msg= user_loop-2412 [001] 1233.351523: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232779000584 user_loop-2412 [001] 1233.351531: tick_stop: success=no msg=more than 1 task in runqueue ! user_loop-2412 [001] 1233.351544: tick_stop: success=no msg=more than 1 task in runqueue ! kworker/1:2-2261 [001] 1233.351548: workqueue_execute_start: work struct ffff88042f44fac8: function od_dbs_timer user_loop-2412 [001] 1233.352523: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232780000291 user_loop-2412 [001] 1233.352526: tick_stop: success=yes msg= user_loop-2412 [001] 1233.435561: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232863000250 user_loop-2412 [001] 1233.435564: tick_stop: success=no msg=more than 1 task in runqueue ! 以下、500行(full tickless無効の場合10000行)くらい続く. . .
結果(要約)
• 明らかにtickが減っている→動作はしている
• しかし、tickless期間は平均0.1秒(10秒÷102) • 制約の1秒にはまだ遠い
Full tickless無効 Full tickless有効
タイマ発火回数(10秒間) 10019回 102回
※ HZ=1000(1秒間に1000回のtick)環境で実行
kworkerスレッド(workqueue)
• ビジーループ以外にCPUごとのkworkerスレッドが動いている(別のCPUに移動できない) →動作可能タスクが複数 →full tickless modeに移行しない
Full ticklessなし Full ticklessあり
タイマ発火回数(10秒間) 10019回 102回
kworker動作回数 (10秒間) 1043回 96回
kworkerスレッドが実行していたもの関数名 サブシステム
od_dbs_timer CPUfreq(CPU frequency scaling)
output_poll_execute [drm_kms_helper]
DRM(Direct Rendering Manager)
vmstat_update メモリ管理
blk_delay_work ブロックデバイス
ioc_release_fn ブロックデバイス
disk_events_workfn ブロックデバイス
flush_to_ldisc TTY
対策 - od_dbs_timer()• 実行されていた関数がdrivers/cpufreq/cpufreq_ondemand.cにあるので、周波数の動的変更が関係しているに違いない!
• # cpupower frequency-set -g performance としたら出なくなった
• CONFIG_CPU_FREQ=nでカーネル再ビルドでも良いらしい(*1)
*1 linux/Documentation/kernel-per-CPU-kthreads.txt
対策 - output_poll_execute()• drm_kms_helperをrmmodできれば良い# init 3# echo 0 > /sys/class/vtconsole/vtcon1/bind# rmmod radeon# rmmod drm_kms_helper
• ただし、モニタ&キーボードが使えなくなる
対策 - vmstat_update()• linux/Documentation/kernel-per-CPU-kthreads.txt によると、 It is not possible to entirely get rid of OS jitter from vmstat_update() on CONFIG_SMP=y systems, but you can decrease its frequency by writing a large value to /proc/sys/vm/stat_interval.
• 実はdynticks-testingでは既に頻度を下げているsysctl vm.stat_interval=120
対策 - それ以外
• 未対策
• インメモリ動作にしてブロックデバイスを使わないとか?
• TTY…
関数名 サブシステム
blk_delay_work ブロックデバイスioc_release_fn ブロックデバイスdisk_events_workfn ブロックデバイスflush_to_ldisc TTY
とりあえずリトライした結果
• tickless期間が平均0.1→0.3秒に改善
Full ticklessなし Full ticklessあり (対策なし)
Full ticklessあり(対策あり)
タイマ発火回数(10秒間) 10019回 102回 33回
kworker動作回数 (10秒間) 1043回 96回 6回
一応、0.8秒近く持続してる時もある
まとめ• カーネルビルドはかんたん
• 事前セットアップが大変
• 今後の課題 • 残りのkworker実行関数の対策(根本的にはworkqueueの改造が必要かも)
• ARMとかでも試してみたい • 性能評価