LinuxのFull tickless
を試してみた
第九回カーネル/VM探検隊
Hiraku Toyooka (@hiraku_wfs)
自己紹介
•

豊岡 拓(とよおか ひらく)

•

Twitter: @hiraku_wfs

•

横浜でLinuxのお仕事してます

•

が、今日は業務とは直接関係ない話
Ticklessとは
•

CPUが暇な(idle)時にtickを入れなくする
•

省電力

•

Linux, FreeBSDなどに実装されている
task

1ms

idle

tickless

task

time
Full tickless
•

CPUが暇じゃなくてもtickを消す
•

Linux 3.10から導入された

•

tickのオーバヘッドが無くなる
task A

tickless

task B

time
どんなワークロードのため?
•

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
| |
rcuos/0-18
user_loop-2412

CPU#
|
[001]
[001]

TIMESTAMP FUNCTION
|
|
1233.121545: tick_stop: success=yes msg=
1233.122098: tick_stop: success=no msg=more than 1 task in runqueue

sleep-2413
sleep-2413
sleep-2413

[001]
[001]
[001]

1233.122419: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232550001205
1233.122429: tick_stop: success=yes msg=
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
user_loop-2412
user_loop-2412

[001]
[001]
[001]

1233.123419: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232551000974
1233.123431: tick_stop: success=yes msg=
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
user_loop-2412
user_loop-2412

[001]
[001]
[001]

1233.123439: tick_stop: success=yes msg=
1233.351523: hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232779000584
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
user_loop-2412
user_loop-2412
user_loop-2412
user_loop-2412

[001]
[001]
[001]
[001]
[001]

1233.351548:
1233.352523:
1233.352526:
1233.435561:
1233.435564:

workqueue_execute_start: work struct ffff88042f44fac8: function od_dbs_timer
hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232780000291
tick_stop: success=yes msg=
hrtimer_expire_entry: hrtimer=ffff88042f44d900 function=tick_sched_timer now=1232863000250
tick_stop: success=no msg=more than 1 task in runqueue

以下、500行(full tickless無効の場合10000行)くらい続く. . .
結果(要約)
Full tickless無効 Full tickless有効
タイマ発火回数

(10秒間)

10019回

102回

•

明らかにtickが減っている→動作はしている

•

しかし、tickless期間は平均0.1秒(10秒 102)
•

制約の1秒にはまだ遠い
※ HZ=1000(1秒間に1000回のtick)環境で実行
kworkerスレッド(workqueue)
Full ticklessなし Full ticklessあり
タイマ発火回数

(10秒間)

102回

kworker動作回数

(10秒間)
•

10019回

1043回

96回

ビジーループ以外にCPUごとのkworkerスレッドが動い
ている(別のCPUに移動できない)

→動作可能タスクが複数

→full tickless modeに移行しない
kworkerスレッドが実行していたもの
関数名
od_dbs_timer
output_poll_execute
[drm_kms_helper]
vmstat_update

サブシステム
CPUfreq

(CPU frequency scaling)
DRM

(Direct Rendering Manager)
メモリ管理

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-CPUkthreads.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
対策 - それ以外
関数名

サブシステム

blk_delay_work

ブロックデバイス

ioc_release_fn

ブロックデバイス

disk_events_workfn

ブロックデバイス

flush_to_ldisc

TTY

•

未対策

•

インメモリ動作にしてブロックデバイスを使わないとか?

•

TTY…
とりあえずリトライした結果
Full ticklessあり Full ticklessあり

Full ticklessなし
(対策なし)
(対策あり)
タイマ発火回数

(10秒間)

10019回

102回

33回

kworker動作回数

(10秒間)

1043回

96回

6回

•

tickless期間が平均0.1→0.3秒に改善
一応、0.8秒近く持続してる時もある
まとめ
•

カーネルビルドはかんたん

•

事前セットアップが大変

•

今後の課題
•

残りのkworker実行関数の対策

(根本的にはworkqueueの改造が必要かも)

•

ARMとかでも試してみたい

•

性能評価

LinuxのFull ticklessを試してみた