psコマンドのSZって何だ?
psコマンドは誰もがお世話になる便利コマンド。派生コマンドも多いし、リアルタイムに見たいからtop使ったり、その派生使ったり、アウトローな輩が/procを直に見るからpsコマンドいらんとか言ってたり、sar経由でグラフにならないと見ない御仁もいるかもしれないけど、とにかくその誰もが最初に学ぶ基本コマンドがpsなのだ。
今日はそのpsコマンドの出力、SZについての疑問に迫る。うん、誰も興味ないのは知ってる。
psコマンドとは ~ おさらい ~
誰もが知ってると言われても俺は知らないという未開の地からの来訪者のために、wikipediaの説明を贈ろう。これを故郷で自慢してほしい。
嘘です。やる気のない人が書いたのか意味のある語句は、
… ps(ピーエス)は現在動作しているプロセスを表示する …
https://ja.wikipedia.org/wiki/Ps_(UNIX)
これだけでしたね。プロセスにも何かリンクが張ってるので、良ければそこも読んでくれて構いませんが、動いてる状態のプログラムをプロセスって言います。だからpsコマンドは自分自身のプロセスも、その一覧に表示します。例えばこんな感じ。
$ ps
PID TTY TIME CMD
40933 pts/4 00:00:00 bash
93843 pts/4 00:00:00 ps
$
今はbashとpsというプロセスが動いてるのが分かります。
psはコマンドなので、オプションを変えることにより出力が変わります。例えばオプション-fを付けると…
$ ps -f
UID PID PPID C STIME TTY TIME CMD
user 93862 1991 1 12:28 pts/6 00:00:00 /bin/bash
user 94063 93862 0 12:28 pts/6 00:00:00 ps -f
$
情報が増えました。よく使うオプションは-efとかです。
$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 6月04 ? 00:00:04 /sbin/init splash
root 2 0 0 6月04 ? 00:00:00 [kthreadd]
root 3 2 0 6月04 ? 00:00:00 [rcu_gp]
root 4 2 0 6月04 ? 00:00:00 [rcu_par_gp]
root 6 2 0 6月04 ? 00:00:00 [kworker/0:0H-kblockd]
root 9 2 0 6月04 ? 00:00:00 [mm_percpu_wq]
root 10 2 0 6月04 ? 00:00:18 [ksoftirqd/0]
root 11 2 0 6月04 ? 00:00:52 [rcu_sched]
root 12 2 0 6月04 ? 00:00:01 [migration/0]
...
$
今度は一覧されるプロセスが増えました。まあこんなコマンドです。
ではSZって何?
ps -elyで出てくる列の1つです。
$ ps -ely
S UID PID PPID C PRI NI RSS SZ WCHAN TTY TIME CMD
S 0 1 0 0 80 0 7828 41936 - ? 00:00:04 systemd
S 0 2 0 0 80 0 0 0 - ? 00:00:00 kthreadd
I 0 3 2 0 60 -20 0 0 - ? 00:00:00 rcu_gp
I 0 4 2 0 60 -20 0 0 - ? 00:00:00 rcu_par_gp
I 0 6 2 0 60 -20 0 0 - ? 00:00:00 kworker/0:0H-kblockd
I 0 9 2 0 60 -20 0 0 - ? 00:00:00 mm_percpu_wq
S 0 10 2 0 80 0 0 0 - ? 00:00:18 ksoftirqd/0
I 0 11 2 0 80 0 0 0 - ? 00:00:52 rcu_sched
S 0 12 2 0 -40 - 0 0 - ? 00:00:01 migration/0
...
$
psコマンドのオプションは、実は標準とBSD系列に分かれており、
- ps -efを典型例とする標準オプション
- ps auxを典型例とするBSD系列オプション
に2分されますが、標準オプションではメモリ使用量を知る簡単なオプションが-yしかないのです(長ったらしいフォーマット指定をすれば任意の列を出力出来ますが…)。
そしてこの-yオプションで出てくるメモリ関連の列、RSSとSZのうち、RSSは
… resident set size, the non-swapped physical memory that a task has used (in kilobytes). …
Manual page ps(1)
と分かりやすく、プロセスが使っているスワップされてない物理メモリの常駐サイズ[KB]です。ザックリとこのプロセス単独で使ってるRAM使用量くらいの意味合いです。
でもSZは…
… size in physical pages of the core image of the process. This includes text, data, and stack space. Device mappings are currently excluded; this is subject to change. See vsz and rss. …
Manual page ps(1)
よく分からない…物理メモリだし普通のセクション名だし、デバイスマッピングを除くんだからRSSと似たようなものなんだろうか…でもなぜ?何が違うんだろう?
これが最初の所感でした。何とも言いようのない違和感を覚えるものの、今どきBSD系列もおかしいし、標準で行きたい子羊は-yを使いたい一心でSZ探しの旅に出るのでした。
SZ探しの旅
何をするって?もうソースを探すしかないんですよ…
psコマンドを含むパッケージを探して…
我らが住む大地Ubuntuを構成するパッケージのうちどこにpsコマンドが住んでいるのかをまず調べます。
ローカルでコマンドを使用する方法(オススメしません)
$ sudo apt install apt-file
$ apt-file update
$ apt-file search -x '^/bin/ps$'
procps: /bin/ps
$
Webでサクッと探す方法(オススメ)
https://packages.ubuntu.com/ja/
パッケージの内容を検索で、psで検索するだけでprocpsが見つかります。
procpsのソースパッケージを取得する
まずはソースを取得するリポジトリをaptに設定する必要があります。たくさんやると時間かかるので、ピンポイントで取得するため、事前にどこにあるのか調べます。
$ apt info procps
...
APT-Sources: http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages
...
$
見つかったので、上のリポジトリを/etc/apt/source.listで探してコメントを外します。
< # deb-src http://archive.ubuntu.com/ubuntu/ focal-updates main restricted
--
> deb-src http://archive.ubuntu.com/ubuntu/ focal-updates main restricted
では更新してソース取得します。ついでにビルドに必要なパッケージも追加しておきます。
$ sudo apt update
$ sudo apt install build-essential dpkg-dev
$ apt source procps
とりあえずこの段階でソースを見ることが出来ます。
ビルドするにはビルドで依存するパッケージも必要なので、それらを入れておく必要があります。
$ sudo apt build-dep procps
あとはビルドディレクトリに行って、ビルドするだけ。
$ cd procps-3.3.16 # バージョン部分は適宜読み替えてください
$ dpkg-buildpackage -rfakeroot -b
一度ビルドが通ったら、デバッグしたくて最適化がうざそうなので、Makefileを直に編集して最適化を外します。
< CFLAGS = -g -O2 -fdebug-prefix-map=/root/ps/procps-3.3.16=. -fstack-protector-strong -Wformat -Werror=format-security
--
> CFLAGS = -g -fdebug-prefix-map=/root/ps/procps-3.3.16=. -fstack-protector-strong -Wformat -Werror=format-security
改めてリビルド。
$ make clean
$ make
後は思う存分デバッグして解析するだけです。
gdb神の力を借りる
実はこの作業dockerコンテナ内でやってるので、gdbをインストールして直に使います。
$ sudo apt install gdb
$ gdb ps/.libs/pscommand
(gdb) break main
(gdb) break pr_vsz
(gdb) break pr_rss
(gdb) break pr_sz
(gdb) run -eo vsz,rss,sz
Starting program: /root/ps/procps-3.3.16/ps/.libs/pscommand -eo vsz,rss,sz
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=1, argv=0x0) at ps/display.c:621
621 int main(int argc, char *argv[]){
(gdb) c
Continuing.
VSZ RSS SZ
Breakpoint 2, pr_vsz (outbuf=0x7f6f54a79090 "SZ\n", pp=0x200000001) at ps/output.c:584
584 static int pr_vsz(char *restrict const outbuf, const proc_t *restrict const pp){
(gdb) n
585 return snprintf(outbuf, COLWID, "%lu", pp->vm_size);
(gdb) c
Continuing.
Breakpoint 3, pr_rss (outbuf=0x0, pp=0x7ffcaa6bac10) at ps/output.c:990
990 static int pr_rss(char *restrict const outbuf, const proc_t *restrict const pp){
(gdb) n
991 return snprintf(outbuf, COLWID, "%lu", pp->vm_rss);
(gdb) c
Continuing.
Breakpoint 4, pr_sz (outbuf=0x0, pp=0x7ffcaa6bac10) at ps/output.c:898
898 static int pr_sz(char *restrict const outbuf, const proc_t *restrict const pp){
(gdb) n
899 return snprintf(outbuf, COLWID, "%lu", (pp->vm_size)/(page_size/1024));
(gdb)
はい、これで確認が取れて全て把握です。proc/readproc.cも読むと、/proc/[pid]/statusを読んで、VmSizeやらVmRSSを拾ってる模様。
列名 | 値 | |
---|---|---|
RSS | pp->vm_rss | /proc/[pid]/statusのVmRSS |
VSZ | pp->vm_size | /proc/[pid]/statusのVmSize |
SZ | (pp->vm_size)/(page_size/1024) | VSZの値を4で割ったモノ(page_sizeは4kなので) |
あとはman 5 procしても良いし、
https://www.kernel.org/doc/html/latest/filesystems/proc.html
を見てもOK。
SZとは
SZとは仮想メモリ含む全使用メモリ(スワップしてるメモリも含んだ全使用メモリ)のページ数でした(※man psを信用してはならない!?)。
4掛けると仮想メモリ含む全使用メモリ[KB]になります。
これでBSDの呪いに屈することなく、-elyを思う存分使える!ということ。ん?4掛けるのが面倒?仕様です。
一応続き的な記事を書きました。
ディスカッション
コメント一覧
まだ、コメントがありません