本エントリの要約
Linux kenrel v4.14-rc3 から /proc/$pid/status
と /proc/$pid/stat
/proc/sched_debug
で表示されるタスクの状態に I (idle)
が追加されている
これに対応するカーネル内の定数は TASK_IDLE (注: 定数自体は v4.2-rc1 に追加された )
#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
- TASK_IDLE は TASK_UNINTERRUPTIBLE の状態を取りつつも、 TASK_NOLOAD = ロードアベレージには寄与しない状態のタスクを示す
- TASK_IDLE は カーネルスレッドのみが取りうる状態のようだ ( kthreadd から生えた workqueue のスレッドや oom_reaper 等 )
ps や top で見るとカーネルスレッドの一部が I
と表示されるのが確認できる
I
のタスクを探してね
以降、調べた経緯を記す。興味ない人はすっ飛ばしてね
イントロダクション
kernel 4.14-rc7 を触っていたところ、 ps auxf
で出力される STAT
欄に I
で標示されるタスクがあるのに気がついた
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2 0.0 0.0 0 0 ? S 10月30 0:00 [kthreadd] root 4 0.0 0.0 0 0 ? I< 👈 10月30 0:00 \_ [kworker/0:0H] root 6 0.0 0.0 0 0 ? I< 👈 10月30 0:00 \_ [mm_percpu_wq] root 7 0.0 0.0 0 0 ? S 10月30 0:00 \_ [ksoftirqd/0] root 8 0.0 0.0 0 0 ? R 10月30 0:08 \_ [rcu_sched] root 9 0.0 0.0 0 0 ? I 👈 10月30 0:00 \_ [rcu_bh] root 10 0.0 0.0 0 0 ? S 10月30 0:00 \_ [migration/0] root 11 0.0 0.0 0 0 ? S 10月30 0:00 \_ [watchdog/0] ...
man で調べる
man 1 ps
http://man7.org/linux/man-pages/man1/ps.1.html には載っていない
PROCESS STATE CODES top Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to describe the state of a process: D uninterruptible sleep (usually IO) R running or runnable (on run queue) S interruptible sleep (waiting for an event to complete) T stopped by job control signal t stopped by debugger during the tracing W paging (not valid since the 2.6.xx kernel) X dead (should never be seen) Z defunct ("zombie") process, terminated but not reaped by its parent For BSD formats and when the stat keyword is used, additional characters may be displayed: < high-priority (not nice to other users) N low-priority (nice to other users) L has pages locked into memory (for real-time and custom IO) s is a session leader l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do) + is in the foreground process group
man 1 top
http://man7.org/linux/man-pages/man1/top.1.html も同様で載っていない
29. S -- Process Status The status of the task which can be one of: D = uninterruptible sleep R = running S = sleeping T = stopped by job control signal t = stopped by debugger during trace Z = zombie
最近追加されたものだと推測できる。もしくは man 作ってる人達が見落としているってのもあるだろう (よくあるみたいだよ)
man の upstream を調べる
man 1 ps
man 1 top
の upstream は procps-ng だが、ここをみても (まだ) 説明は無かった
📝 rc 無しバージョンのカーネルがリリースされたら issue をあげたらいいかな?
strace で調べる
ps は /proc
のデータを整形して出力するなのを経験的に知っているので、strace を取ってアタリをつけた
$ strace -yy -s100 -- ps ax -ostat ... stat("/proc/4", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0 open("/proc/4/stat", O_RDONLY) = 6</proc/4/stat> read(6</proc/4/stat>, "4 (kworker/0:0H) I 👈2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 0 0 0 18446744073709551615 0 0 0 0 "..., 2048) = 156 close(6</proc/4/stat>) = 0 open("/proc/4/status", O_RDONLY) = 6</proc/4/status> read(6</proc/4/status>, "Name:\tkworker/0:0H\nUmask:\t0000\nState:\tI (idle)\nTgid:\t4\nNgid:\t0\nPid:\t4\nPPid:\t2\nTracerPid:\t0\nUid:\t0\t0\t"..., 2048) = 893 close(6</proc/4/status>) = 0 write(1</dev/pts/0>, "I<\n", 3I< 👈 ) = 3
/proc/$pid/stat
もしくは /proc/$pid/status
から取り出した文字列なのが分かる
[vagrant@localhost ~]$ cat /proc/4/stat 4 (kworker/0:0H) I 👈 2 0 0 0 -1 69238880 0 0 0 0 0 0 0 0 0 -20 1 0 0 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
カーネルのソースを探す
The Linux Kernel Archives から最新のソースコードを取ってこよう。git blame で追いかけるならリポジトリを clone しておく方がよいか
/proc/$pid/stat や /proc/$pid/status のソースコードは fs/proc/*.c
以下に転がっている。適当に grep をかけて回って I
は TASK_IDLE の省略形であることを調べだした。以下のコミットを探し出す
$ grep idle fs/proc/* | head -1 fs/proc/array.c: "I (idle)", /* 0x80 */
ここをエントリポイントとして git blame でコミットを調べだして過去を遡っていく
関連のコミット
TASK_IDLE は下記のコミットで /proc/$pid/status
/proc/$pid/stat
に表示されるよになった ( v4.14-rc3 )
TASK_IDLE は下記のコミットで追加された ( v4.2-rc1 )
どういう用途なのかはコミットメッセージを読むと分かる
Currently people use TASK_INTERRUPTIBLE to idle kthreads and wait for 'work' because TASK_UNINTERRUPTIBLE contributes to the loadavg. Having all idle kthreads contribute to the loadavg is somewhat silly. Now mostly this works OK, because kthreads have all their signals masked. However there's a few sites where this is causing problems and TASK_UNINTERRUPTIBLE should be used, except for that loadavg issue. This patch adds TASK_NOLOAD which, when combined with TASK_UNINTERRUPTIBLE avoids the loadavg accounting. As most of imagined usage sites are loops where a thread wants to idle, waiting for work, a helper TASK_IDLE is introduced.
なるほどなー
感想
- 新しいステートが増えることで
ps
や/proc/pid/status
,/proc/pid/stat
をパースしてごそごそやっているツールがあれば副作用がでるだろうか?- とりあえずカーネルスレッドだけなので あまり影響はなさそうだが
- 些細な変更にみえるが、ユーザランドで確認できるステートが増えるというのは滅多にないことだよな
- TASK_UNINTERRUPTIBLE + TASKNO_LOAD にするのは興味深いが、そもそもロードアベレージの計算が TASK_RUNNING と TASK_UNINTERRUPTIBLE とで混ざっているのが厄介だよなぁ。Brendan Gregg は何と言ってたかな