kernel の統計
stats of kernel
ネコはここまで考えている なんて言う楽しい本を読んだ。動物心理学から読みとく心の進化って副題がついていた。よく、猫は3年の恩を3日で忘れるとか言われるけど、それって本当って疑問から、色々と調査実験した結果をかみ砕いて説明してる。
例えば、声から顔を思い浮べるのか、とか、ネコは、どこに、何が を思いだせると等。論文が発表されて世界に話題になり、CNNやらBBCの取材を受けたそうだ。みんなミステリアスな猫に魅了されているんですなあ。
で、本の巻末に論文の補足が載ってた。分析にはRを使ったそうだ。2項検定やらオイラーの知らないGLMパッケージを駆使したやつが使われていた。統計が物を言う世界なんですなあ。
オイラーの統計と言うと今迄は血圧ばかりであったけど、趣向を変えてOpenBSDのカーネルの成分分析をしてみる。
結論を先に出しておくね。色々なハードで動くカーネルがどういうオブジェクトから構成されているかを分析(おこまがしいですが)してみた。
前回、/etc/rcの最後で /usr/libexec/reorder_kernel
が走って、カーネルをオブジェクトに分解し、それをランダムに配置組立してるって書いた。その分解されたオブジェクトのサイズを採取したんだ。(サイズとファイル名前を欲しい場合は、コメントの行のようにする)
vbox# cd /usr/share/relink/kernel/GENERIC.MP/ vbox# ls -l *.o | awk '{print $5}' > /tmp/i386 ## ls -l *.o | awk '{printf("%8d %s\n", $5, $9)}'
これが結果。r64Sは、前回作った特製(縮小版)のriscv64ね。それ以外はGENERIC版。
amd64 i386 r64 r64S ---------------------------------------- N : 2072 1641 872 495 Min. : 400 276 456 456 1st Qu.: 39604 20384 63106 43200 Median : 105792 46844 167356 101008 Mean : 186715 79313 252977 164147 3rd Qu.: 320078 104044 351036 219828 Max. :1268064 810056 2772752 1270408 Sd : 182448 87519 295427 184376
まずRのパッケージ、 R-cran-psychを追加しておく。(at FreeBSD)
> library(psych) > amd <- read.csv("amd64", header=FALSE) > describe(amd) var n mean sd median trimmed mad min max range V1 1 2072 186715.1 182448.4 105792 163585.7 126317.5 400 1268064 1267664 skew kurtosis se V1 1.235344 1.824532 4008.162 > summary(amd) V1 Min. : 400 1st Qu.: 39604 Median : 105792 Mean : 186715 3rd Qu.: 320078 Max. :1268064
普通は統計情報と言うとsummaryになるけど、残念な事に母数(N)と標準偏差(Sd)が出てこない。これは明らかに欠陥と思うぞ。で、余計なパッケージpsychを入れてdescribe関数を使うんだけど、これも勝手が悪い。
そこで合わせ技で、summaryの前後にN,Sdを追加。そうして出来たやつをクリッピング。後はpasteコマンドで結合。体裁を整るんで、emacsのレクタングル編集、C-x r d 削除機能を使った。
R以外はどうよ。
by octave
-- : statistics (X) -- : statistics (X, DIM) Return a vector with the minimum, first quartile, median, third quartile, maximum, mean, standard deviation, skewness, and kurtosis of the elements of the vector X.
maximaにも統計関数が有ったように思うけど、忘却の彼方だな。それより身近にあるやつ (決してPythonなんて事は、オイラーの場合有馬泉)。
by gnuplot
お手軽。
gnuplot> stats "amd64" Records: 2072 Mean: 186715.1351 Std Dev: 182404.3961 Sample StdDev: 182448.4286 Skewness: 1.2362 Kurtosis: 4.8172 Minimum: 400.0000 [ 229] Maximum: 1.26806e+06 [1109] Quartile: 39600.0000 Median: 105792.0000 Quartile: 320676.0000
でも、やっぱりグラフでしょ。簡単に箱ひげグラフで概要把握。
gnuplot> plot 'r64S' with boxplot
ふーむ、世の中の縮図っぽいな。イーロン・マスクやらアマゾン親父みたいな富豪がいるかと思えば、貧困でやせ細っているファイルも多数。
sakae@pen:/tmp/REL$ sort r64S -n >z : gnuplot> plot 'z' w l
データを並びかえておいて、それをグラフしてみると、二次関数ぽく表示された。
gnuplot> set logscale y; plot 'z' w l
片対数グラフにしてみた。結構広い範囲において、グラフがほぼ直線になった。やはり二次関数ぽい分布になってると思えるな。
こんな事をやってると、ソースの行数とオブジェクトファイルの大きさに相関は有るか、 とか、同一オブジェクト・ファイルを取出した時、64Bitバージョンと32Bitバージョンで相関は有るか、 なんて事を調べたくなるものだ。
同じ発想の人がおられたので、指を咥えて眺めておく。
reorder_kernel.sh
次はカーネルのランダム化がどのように行われているか、興味津々で調べてみたい。シェルスクリプトだった。概要は下記。
KERNEL=$(sysctl -n kern.osversion) KERNEL=${KERNEL%#*} KERNEL_DIR=/usr/share/relink/kernel cd $KERNEL_DIR/$KERNEL make newbsd [ -f /etc/bsd.re-config ] && config -e -c /etc/bsd.re-config -f bsd make newinstall sync echo "\nKernel has been relinked and is active on next reboot.\n" cat $SHA256
もう少し詳しくって事でトレース、
sh -x reorder_kernel
更に、ログファイルが作成されるので、その一部 relink.log
+ sha256 -C /var/db/kernel.SHA256 /bsd (SHA256) /bsd: OK + cd /usr/share/relink/kernel/GENERIC.MP + make newbsd LD="ld" LDFLAGS="-g" sh makegap.sh 0xcccccccc gapdummy.o ld -T ld.script -X --warn-common -nopie -o newbsd ${SYSTEM_HEAD} vers.o ${OBJS} text data bss dec hex 13031367 229896 1130496 14391759 db99cf mv newbsd newbsd.gdb ctfstrip -S -o newbsd newbsd.gdb rm -f bsd.gdb mv -f newbsd bsd + [ -f /etc/bsd.re-config ] + make newinstall install -F -m 700 bsd /bsd && sha256 -h /var/db/kernel.SHA256 /bsd + sync + echo \nKernel has been relinked and is active on next reboot.\n
掘り出し物ってかお宝発見。gdbにかけられるカーネルが作られていたよ。GENERICなもので好ければ、このセットが使えるな。前回みたいに苦労してカーネルを作る事はなかったわい。
vbox# ls -ltr -rw-r----- 1 root wheel 10752 Sep 28 03:41 smc93cx6.o -rw-r----- 1 root wheel 1150 Sep 28 03:41 makegap.sh -rw-r----- 1 root wheel 3440 Sep 28 03:41 locore0.o -rw-r----- 1 root wheel 436 Sep 28 03:41 gapdummy.o -rw-r----- 1 root wheel 135420 Sep 28 03:41 Makefile -rw-r----- 1 root wheel 13788 Sep 28 03:41 pcdisplay_subr.o : -rw-r----- 1 root wheel 1748 Sep 28 03:54 swapgeneric.o -rw-r----- 1 root wheel 4259 Sep 28 03:54 ld.script -rw-r----- 1 root wheel 69552 Sep 28 03:54 ioconf.o -rw-r--r-- 1 root wobj 30832 Oct 27 02:41 ukbd.o -rw-r--r-- 1 root wobj 2108 Oct 27 02:42 vers.o -rw-rw---- 1 root wheel 634 Nov 24 05:41 gap.link -rw-rw---- 1 root wobj 20104 Nov 24 05:41 gap.o -rw-rw---- 1 root wheel 19376 Nov 24 05:41 lorder -rwxrwx--- 1 root wobj 77267468 Nov 24 05:41 newbsd.gdb -rwxrwx--- 1 root wobj 15214971 Nov 24 05:41 bsd -rw-r--r-- 1 root wheel 507 Nov 24 05:41 relink.log
所で、再配置ってどうやってる? makegap.shが毎回走ってランダム牲を作り出す。
random_uniform() { : echo `jot -r 1 0 $_upper_bound 2>/dev/null` } RANDOM1=`random_uniform $((3 * PAGE_SIZE))` RANDOM2=`random_uniform $PAGE_SIZE` : cat > gap.link << __EOF__ : .bss : { . = . + $RANDOM5; /* fragment of page */ . = ALIGN(16); *(.bss .bss.*) } :bss } __EOF__ $LD $LDFLAGS -r gap.link $GAPDUMMY -o gap.o
jot -r でランダムデータを作る。それらのデータで、リンカーの配置をランダム化。更に念を入れて、ランダムなサイズのオブジェクトファイルを作成。それをカーネルの一部にする事により、配置が予測出来無いようにしてる。
more stats
最初にやった統計には、重大な欠陥がある事に気付いてしまった。その、きっけけは、relink.logに出て来た、ctfstripってコマンド。70年の人生で初めて出会うコマンド。なにかと思ってしらべたら、デバッグ情報だけを取り除くものだった。普通のstripと何が違う?
vbox$ ls -l kern_event.o -rw-r----- 1 sakae wheel 120252 Nov 24 15:04 kern_event.o vbox$ ctfstrip -S -o aa kern_event.o vbox$ ls -l aa -rw-r--r-- 1 sakae wheel 30696 Nov 24 15:48 aa vbox$ strip kern_event.o vbox$ ls -l kern_event.o -rw-r----- 1 sakae wheel 18772 Nov 24 15:49 kern_event.o
オリジナルのファイル容量は、120Kを越る巨大なやつ。そこからデバッグ情報だけを削除してaaってファイルを作成。そのサイズは30K。要するにgdbの為に水膨れしてた訳。 次に、普通のストリップを実施。わーい、更に小くなったぞ。
vbox$ nm kern_event.o nm: kern_event.o: no name list vbox$ nm aa 00000ab0 T KQREF 00000ad0 T KQRELE :
でもね、stripしちゃうと、本当に必要な名前まで削除されちゃうんだ。これでは使い物にならない。ctfstripで新に作ったものは大丈夫。ストリップは天下の大罪、下手にやると たいーほ されるぞ。
よって、こんなスクリプトをかませて、gdb情報だけを削除するのさ。
#!/bin/sh for f in *.o do name=`basename $f .o` ctfstrip -S -o ${name}.O $f done
尚、basenameでサフィックスを削除出来るなんで、初めて知った。もぐりのスクリプターだなあ。まあ、こうやって野次馬根性を発揮するから、引出しの道具が増えるんだな。
色々な石でのファイルの出来具合を確認したい。共通なって事で、/sys/kern/kern*.c 相当だけを抜き出してみた。kern/ エリアのほぼ 1/3 をサンプリング調査って事になる。
結果はソースの行数でソートした、ベスト10です。実際は35ヶ有ります。
i386
org .o ctfstrip strip lines source ----------------------------------------------------------------------- 168216 39976 27160 2540 kern_sysctl.c 113552 25296 16528 2452 kern_sig.c 120252 30696 18772 2200 kern_event.c 96808 17492 12772 1643 kern_pledge.c 96624 18212 11844 1474 kern_descrip.c 63268 10832 6392 1129 kern_prot.c 57308 14868 9464 989 kern_time.c 53568 14756 9552 981 kern_tc.c 63564 17992 9804 965 kern_timeout.c 70184 12228 6884 916 kern_exec.c
amd64
290120 77328 35512 2540 kern_sysctl.c 197464 64624 29816 2452 kern_sig.c 222960 86144 38072 2200 kern_event.c 151536 45584 17472 1643 kern_pledge.c 168664 48688 20152 1474 kern_descrip.c 116008 34280 15664 1129 kern_prot.c 93096 31288 13792 989 kern_time.c 89384 31680 16896 981 kern_tc.c 110104 45464 17440 965 kern_timeout.c 105272 29552 8096 916 kern_exec.c
r64
781512 170552 25088 2540 kern_sysctl.c 486136 121216 16688 2452 kern_sig.c 562104 155096 20176 2200 kern_event.c 304216 59208 12008 1643 kern_pledge.c 391000 91960 13000 1474 kern_descrip.c 246272 56256 6320 1129 kern_prot.c 201872 54120 8392 989 kern_time.c 244144 71104 8568 981 kern_tc.c 226648 67944 9008 965 kern_timeout.c 216056 41824 6048 916 kern_exec.c
このままでは目がチラチラするので、gnuplotの散布図を作ってみます。
gnuplot> plot "i386" pointtype 6
また、わざわざ図にしなくても
gnuplot> stat "i386" : Minimum: 6152.0000 [33] 2021.0000 [32] Maximum: 168216.0000 [26] 39976.0000 [26] Quartile: 26508.0000 5468.0000 Median: 53568.0000 9924.0000 Quartile: 64088.0000 14168.0000 Linear Model: y = 0.2256 x - 994.7 Slope: 0.2256 +- 0.01267 Intercept: -994.7 +- 805.1 Correlation: r = 0.9517
こんな風に、回帰曲線の推定やら相関係数まで表示してくれる。普通に使うならgnuplotで十分な気がするぞ。
今度はソースの行数(wcしただけなんでコメントも含まれる)と生成されたオブジェクト(striped)の突合せ。using x:y が自由に使えるので嬉しい。
gnuplot> stats 'i386' using 4:3 : Linear Model: y = 8.501 x + 98.51 ;; i386 Linear Model: y = 13.7 x + 663.1 ;; amd64 Linear Model: y = 8.49 x - 216.1 ;; r64
回帰式だけを拾ってみた。相関係数は 0.96ぐらいになってたんで、鉄板で予想がピタリと的中するというお墨付き。
amd64の場合は、他の石に比べて効率が悪い。大雑把に1000行のソースをコンパイルすると、13700バイトのオブジェクトファイルが出来ると予想。他の2つの石は8500バイトになるって予想。
syspatch
更に上のリストを見て気付いた事がある。*.oは、大体 Sep 28 03:41 から始まって Sep 28 03:54 に終了。カーネルのコンパイルに13分かかりましたって証拠が出てる。その日付以外に、仲間外れの Oct 27 02:41 ukbd.o なんてのが出てくる。これだけ仲間外れ。
更に後の日付のNov 24 05:41は、オイラーの指示によるものだ。
OpenBSD 7.2のリリース日は Oct 20 なんで、カーネルのコンパイルは随分前のSep 28に行われた。ukbd.o はリリース日以降なんて、パッチなんだな。そう、syspatchね。
vbox$ ls /var/syspatch/ 72-001_x509/ 72-002_asn1/ 72-003_ukbd/ 72-004_expat/ 72-005_pixman/
ここの72-003以下を見ると 003ukbd.patch.sig に
Apply by doing: signify -Vep /etc/signify/openbsd-72-base.pub -x 003_ukbd.patch.sig \ -m - | (cd /usr/src && patch -p0) And then rebuild and install a new kernel: KK=`sysctl -n kern.osversion | cut -d# -f1` cd /usr/src/sys/arch/`machine`/compile/$KK make obj make config make make install Index: sys/dev/usb/ukbd.c
こういうのが案内されてた。これで、更新されるんだね。make installで何が行われるかは、先程のrelinkの中にあるMakefileを見れば分る。
update-link: mkdir -p -m 700 /usr/share/relink/kernel rm -rf /usr/share/relink/kernel/GENERIC.MP /usr/share/relink/kernel.tgz mkdir /usr/share/relink/kernel/GENERIC.MP tar -chf - Makefile makegap.sh ld.script *.o | \ tar -C /usr/share/relink/kernel/GENERIC.MP -xf - newinstall: install -F -m 700 bsd /bsd && sha256 -h /var/db/kernel.SHA256 /bsd install: update-link hardlink-obsd newinstall
また、パッチをロールバックするのに必要なtar玉も提供されてる。この玉は、syspatchした時に作られるとな。
vbox$ tar ztvf rollback.tgz -rw-rw---- 1 root wheel 19048 Nov 4 14:08 usr/share/relink/kernel/GENERIC.MP/gap.o -rw-r----- 1 root wheel 30868 Sep 28 03:53 usr/share/relink/kernel/GENERIC.MP/ukbd.o -rw-r----- 1 root wheel 2112 Sep 28 03:54 usr/share/relink/kernel/GENERIC.MP/vers.o
/usr/share/relink 以下は、リリース以降の作業場所って地位が与えられている訳ね。なお、これらはinstall時やsysupgrade時に作成若しくは更新される。大事なファイル群なので、神聖につき侵すべからず、です。
memo
riscv64を起動する時の力持ちは、下記が参考になる。それってopensbiとの連携かな。
vbox$ emacs ./stand/efi/include/efiapi.h vbox$ emacs ./stand/efi/include/efidef.h