2016年9月アーカイブ

皆さん「このプログラム動かしたらどのくらいメモリ/CPU使うか調べといて、今日中にね。」て言われることよくありますよね。そんな場合に備えること書きます。なおこれは架空のタスクであり実在する(略

● 使用メモリを調べる
常駐してるようなプログラムなら、ps とか free とか dstat とか /proc/(PID)/status とか /proc/meminfo とか、好きに使えればいいよ、うん。そうじゃなくて、プログラム動かしたらすぐに終わるような場合でしかもいつ最大使用メモリなのかわからない場合はめんどいです。そんなあなたにお勧めなのが GNU time。timeというとbash組み込みtimeがメジャーですが、たいていのデストリで /usr/bin/time あたりに入ってるこれを使えば、処理にかかった時間だけじゃなくて使用したメモリとかもわかります。うん今回の用途にピッタリ。

しかし、ググればすぐに出てくるGNU timeのバグを見てみんな驚きとまどう。「え?このデストリに入ってる /usr/bin/time は直ってるの?直ってないの?」/usr/bin/time -V すると 1.7 と出る。うんだって GNU time って v1.7からバージョンあがってない(2016.09.21時点)もん。バージョン見てもマニュアル見てもパッチ当たってるか書いてない。うわぁん、出てきた数字そのままでいいのか4で割れば(4KBページサイズなCPUの場合)いいのかわからないよー(AA略

● Ubuntuの場合
trusty(14.04LTS)の場合、このへんのページにいってtime_1.7-24.debian.tar.gzをダウンロードしてきて解凍して中身を見ればよい。こんなパッチが当たってる。
- bug-address.patch
- configure.patch
- info-direntry.patch
- info-nav.patch
- non-normal-exit.patch
- quiet.patch
- ru_maxrss.patch
- rusage-portability.patch
「ru_maxrss.patch」が目的のパッチでした。time_1.7-24 なら 4で割る必要がないようです。

● CentOSの場合
time-1.7-38.el6.src.rpm を 例えばこのへんからDLしてきてRPMを解凍する。
$ rpm2cpio time-1.7-38.el6.src.rpm |cpio -idv
するとこんなパッチが出てくる。
- time-1.7-destdir.patch
- time-1.7-ru_maxrss-is-in-kilobytes-on-Linux.patch
- time-1.7-verbose.patch
「time-1.7-ru_maxrss-is-in-kilobytes-on-Linux.patch」が目的のパッチでした。time-1.7-38 なら 4で割る必要がないようです。ちなみに、CentOSはRHELのクローンなのでID:702826でトラックされてるようです。

● わからない場合
バージョン古かったりバージョンわからなかったりしてソースファイル類にだ取りつけない場合、実際に動かして比較してみるという手がある。
$ curl -O -L http://ftp.gnu.org/gnu/time/time-1.7.tar.gz
$ cd time-1.7
$ ./configure
$ make
$ TIME="%M" ./time -v ls
$ TIME="%M" /usr/bin/time -v ls
同じならパッチが当たっていない=4で割る必要がある、異なったら(ちょうど4分の1)パッチが当たっている、と判断できる。うん同じものを同じように動かしてみると確実でわかりやすい。ちなみにクロスビルドの場合、ac_cv_func_wait3=yesをつけないとメモリ他が取れない側(HAVE_WAIT3)の #ifdef になっちゃうようです、ぐぬぬ・・・
$ ac_cv_func_wait3=yes ./configure

● GNU time がやってること
wait3(2)で struct rusage* をもらってきてそれの ru_maxrss を出してます。・・・うんシンプル。getrusage(2)でも同じのが取れますが、こっちだと「いつ最大になったか」がわからんので、プロセス終了した後 wait3 で、もしくはプロセスが終了した後waitするまでの間の /proc/(PID)/status の VmHWM、ということになります。

というわけで、決して「それなら***すれば一発でわかりますよ」とか答えないようにしましょう。いろんな条件の組み合わせで繰り返しテストさせられることうけあいなのですよ。

Linuxスケジューラ

/mt/img/16/linux_sched.html

ぐだぐだ書いたり追記したりしそうなので、直接は書かずに別ページにしておくことにした。

ファイルがあるのにexecがENOENTになる問題

ファイルが確かに存在していてファイルの形式がELFで正しいターゲットアーキなのにも関わらずexecするとENOENT(file not found)で失敗してしまうという問題にはまった。アクセス権がないとか実行ビットが立ってないとかならEPERM(permission denied)になるはずなのでそっち系ではない。straceしてもそれっぽい原因が見つからない。Linux kernelのコードを追おうかと思ったけど、さすがに思いとどまってググってるとドンピシャで見つかった。

https://github.com/hiboma/hiboma/blob/master/execve%E3%81%8B%E3%82%99ENOENT%E3%82%92%E8%BF%94%E3%81%99%E3%82%B1%E3%83%BC%E3%82%B9.md
ローダが無い場合に do_execve -> search_binary_handler で ENOENT 返すケースがある

readelf -e してまさにこのパターンであること確認。/lib64/ld-linux-aarch64.so を向いていた。ln -s /lib64 /lib して解決。先にググってよかった。

Yoctoビルドでパッチ当てる方法

該当モジュールのレシピの *.bb ファイルの SRC_URI に 「file:///home/rarul/diff/modified.patch;patch=1」と足して、
$ bitbake -c clean u-boot;
$ bitbake -c compile -f u-boot;
$ botbake core-image-minimal
とすればよい。以上。・・・とわかるのに半日ついやしました。

Yocto・・・というかbitbakeはたくさんのモジュールをまとめてビルドするのには便利だけど、ちょっと変更を加えてビルドし直して、という用途には面倒。レシピでモジュールのダウンロード元からブランチ名からSHA-1のcommit IDまで管理するので、手動でソースコードを直接変更しても bitbake するときに上書き・・・というか元に戻されてしまう。かといって手動でビルドしようにも、レシピが複雑に重なっていると最終イメージを作る手順が複雑でいちいち手動ビルドしてられなくなる。かくして、1行変更したいだけなのにどうすればいいかわからず、数時間平気でつぶしてしまうことになる。

こんなページとかこんなページでは、マジメにパッチ当てるためのレイヤーを新規に追加して・・・というまっとうなやり方を紹介しているけど、名前がルールと直接結びつく bitbake 特有のレシピに全くなじめず、またレイヤー追加するだけなのにこんなクソ長い説明ページが必要だということになってて・・・で半日で挫折しました。

ちなみに、bitbake でビルドできるレイヤー名は bitbake-layers show-layers とかすれば表示できるみたい。Yoctoビルド数ヶ月やって初めて知った・・・ビルドするためだけに36章もある3MBのHTMLマニュアル読まないといけないとか、やっぱYocto何かおかしいんじゃないかと思う。

※ 2017/02/23(Thu)追記
どっかの会社の内部からの妙なリファラがあるな、と思っていたら、同じ会社の別部署だった。ナニソレ...PukiWikiのメニューに興味をそそる文字列が並んでいた。

Icecream

十分に並列ビルド(make -jNなど)ができる環境にて、「横にあるCPUが遊んでるパソコンもコンパイルに使えればいいのに」と思うことはよくあるはず。そういうのを分散コンパイル(Ditributed Compile)といい、その手の歴史が長くて知名度が高いメジャーなやつとしてdistccがある。

ただdistccにも弱点があって、マスターとスレーブでgccバージョンが違ったら吐かれるコードが変わっちゃうよとか、マスターでスレイブのIPアドレス一覧を管理しないといけないよとか、マスターから見てどのスレーブが暇なのかわからんとか、などなど。それらを解決できるやつとしてIcecreamというのが最近ホットみたい。Ubuntu 14.04 LTSだと apt にも入っていて簡単に試せる。<

# apt-get install icecc icecc-monitor
# /etc/init.d/icecc-scheduler start (icecc-scheduler はネットワーク上で1つだけ実行する)
# vi/etc/icecc/icecc.conf
ICECC_SCHEDULER_HOST="192.168.1.111" (マニュアルに寄ればブロードキャストで探すらしいけどダメだったので手動で指定)
# /etc/init.d/iceccd start
分散コンパイルに参加させたいマシンそれぞれにて iceccd を起動すればよい。マシンをたくさん用意できるなら ICECC_MAX_JOBS も適切に設定した方がいいかもしれない。

これで準備完了。マスター(コンパイルのジョブを作る人)からは、
$ export PATH=/usr/lib/icecc/bin:$PATH
として普通にビルドで。 /usr/lib/icecc/bin には cc c++ gcc g++ の名前で /usr/bin/icecc への symlink になってる。ccacheと同じようにwrapperとして動かせばよい。icemonを使えば分散ビルドしている様子がGUIで見て取れる。

Icecreamにはコンパイラのツールをマスターからスレーブに送りつける機能がある。たいていはクロスコンパイル目的かと。
$ mkdir ~/icecream
$ cd icecream
$ icecc --build-native --gcc /usr/local/aarch64-linux/bin/aarch64-linux-gcc /usr/local/aarch64-linux/bin/aarch64-linux-g++
$ mv ****************.tgz aarch64-linux.tgz
とパッケージをあらかじめ作っておいて
# cd /usr/lib/icecc/bin
# ln -s /usr/bin/icecc aarch64-linux-gcc
# ln -s /usr/bin/icecc aarch64-linux-g++
でwrapperとして動くようにsymlink作っておき、
$ export ICECC_VERSION=~/icecream/aarch64-linux.tgz
としてから普通にビルドで。スレーブにaarch64-linux-gccがインストールされていなくてもOKとなる。

ICECC_VERSIONはマルチホスト・マルチターゲット対応となっている。マニュアルから参照すると仕様としては、
「<native_filename>(,<platform>:<cross_compiler_filename>=<target>)*」
具体的には、
ICECC_VERSION=/work/9.1-i386.tar.bz2,ia64:/work/9.1-cross-ia64.tar.bz2,Darwin_PowerPCMac:/work/osx-generate-i386.tar.gz
とか
ICECC_VERSION=/work/i386-native.tar.gz,/work/arm-eabi-toolchain1.tar.gz=arm-eabi,/work/arm-linux-androideabi-toolchain2.tar.gz=arm-linux-androideabi
とか。ツールのパッケージはそれぞれに用意する。ただしマルチターゲット機能は v1.0.1 では対応してなくて v1.1 からの対応となる...けどv1.1の正式版がなかなかでてないようなのよねぇ。。なので、マルチターゲット機能を使いたい人は自分で Github からコード落としてきてコンパイルして使おう。

最後におおざっぱに使ってみた感触を。理想的に並列ビルドができる環境だと、3台でIcecream使ってビルドすると、1台で普通にビルドするのと比べて、おおむね半分の時間でビルドできる。逆に、シングルでビルドするとオーバヘッドがおおむね2から3割かかる。gccとかllvmとかlinuxとかglibcとかchromiumとかqtとか、そういう大物だけねらい打ちで使った方が効果がある気がする。

このアーカイブについて

このページには、2016年9月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2016年7月です。

次のアーカイブは2016年10月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.9.0