2011/12/03
Linux timer
Linux timerについてちょっと調べたので、リンクを貼付け。
Timekeeping in VMware Virtual Machines
http://www.vmware.com/files/pdf/Timekeeping-In-VirtualMachines.pdf
これが一番情報量が多い。VMWareについてのことはもちろん、Timer hardware の話と種類、OS毎のtimerの扱いの概要など。
Linux timers
http://the-b.org/Linux_timers
/sys/devices/system/clocksource/clocksource0/[current_clocksource|available_clocksource] に出てくる名前についての説明。
Timekeeping best practices for Linux guests
http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1006427
VMWareのKBから。Linux distributionとそのバージョンごとにGuest用のtimer設定が羅列されている。しかも、継続的に新しいリリースについても追記が進んでるみたい。すごい。
KVM日記: HPET: High Precision Event Timer
http://d.hatena.ne.jp/kvm/20080313/1205429432
2011/11/26
qemuのdrive indexとPCI address
vl.c DriveInfo *drive_init(QemuOpts *opts, void *opaque,
int *fatal_error)
から。
qemuのPCI addressing
PCIのaddressは、"[[
:]:]"の形式で表現される。表記上の細かいことは、hw/pci.cのstatic int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)辺りに書いてある。
PCIの規格上、それぞれの上限値は、 if (dom > 0xffff || bus > 0xff || val > 0x1f) となっている。
qemuにおいては、domainは常に0のみとなるようになっている。
Host bridgeがひとつしか作れないようなので、PCI busを追加することができない。そのため、0x1f(=31)個 のPCI slot addressをやりくりしてdeviceの割り当てを行うことになる。
幾つかのdeviceは、自動的に作られる。-nodefconfig, -nodefaultsを加えることで、存在するデバイスを減らしPCI addressを節約することが出来る。
-drive
snapshotを指定すると、cache=writeback に変更される。
index値を指定すると、 unit_id = index % max_devs; bus_id = index / max_devs;の式で、unit_id, bus_id へ変換される。これは、IDEとSCSIに置いて適用され、virtioでは適用されない。
IF_IDE
1 IDE busのunit数: MAX_IDE_DEVS=2
readonlyを指定不可。
hotplug不可。
bus_idは、IDE busを示し、unitがIDE channelを表す。IDE bus x 2個分のdriveを追加することが可能になる。
Bus Driver: ich9-ahci (SATA controller), piix3-ide
ich9-ahci は、IDE busを5つ持っている。
dev: ich9-ahci, id ""
bus-prop: addr = 05.0
bus-prop: romfile =
bus-prop: rombar = 1
bus-prop: multifunction = off
bus-prop: command_serr_enable = on
class SATA controller, addr 00:05.0, pci id 8086:2922 (sub 1af4:1100)
bar 5: mem at 0xe2028000 [0xe2028fff]
bus: ide.5
type IDE
bus: ide.4
type IDE
bus: ide.3
type IDE
bus: ide.2
type IDE
bus: ide.1
type IDE
bus: ide.0
type IDE
piix3-ideは、IDE busを2つ持っている。
dev: piix3-ide, id ""
bus-prop: addr = 01.1
bus-prop: romfile =
bus-prop: rombar = 1
bus-prop: multifunction = off
bus-prop: command_serr_enable = on
class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
bar 4: i/o at 0xc000 [0xc00f]
bus: ide.1
type IDE
dev: ide-drive, id ""
dev-prop: unit = 0
dev-prop: drive = ide1-cd0
dev-prop: logical_block_size = 512
dev-prop: physical_block_size = 512
dev-prop: min_io_size = 0
dev-prop: opt_io_size = 0
dev-prop: bootindex = -1
dev-prop: discard_granularity = 0
dev-prop: ver = "0.14.1"
dev-prop: serial = "QM00003"
bus: ide.0
type IDE
IF_SCSI
1 SCSI busのunit数: MAX_SCSI_DEVS=7
readonly指定可。
hotplug可。
bus_idは、SCSI controllerを示し、unitがそれにぶら下がるmediaを示す。SCSI controller x 7個分のdriveを追加することが可能になる。
Bus Driver: lsi53c895a
dev: lsi53c895a, id ""
bus-prop: addr = 03.0
bus-prop: romfile =
bus-prop: rombar = 1
bus-prop: multifunction = off
bus-prop: command_serr_enable = on
class SCSI controller, addr 00:03.0, pci id 1000:0012 (sub 1af4:1000)
bar 0: i/o at 0xc100 [0xc1ff]
bar 1: mem at 0xe2020000 [0xe20203ff]
bar 2: mem at 0xe2022000 [0xe2023fff]
bus: scsi.0
type SCSI
dev: scsi-disk, id ""
dev-prop: drive = scsi0-hd0
dev-prop: logical_block_size = 512
dev-prop: physical_block_size = 512
dev-prop: min_io_size = 0
dev-prop: opt_io_size = 0
dev-prop: bootindex = -1
dev-prop: discard_granularity = 0
dev-prop: ver = "0.14.1"
dev-prop: serial = "0"
dev-prop: removable = off
bus-prop: scsi-id = 0
IF_VIRTIO
unit_idを指定する形ではなく、PCI addressの形で指定する。addr option。driveがPCI slot addressと1対応するため、slot address個数分までしか作ることができない。
0.14.0だとなぜかaddr=20 で固まり、addr=21-22ではエラーを出してくる。addr=23以上では起動してくるがdriveが存在しないためbootに失敗する。
readonly指定可。
hotplug可。
Bus driver: virtio-blk-pci
dev: virtio-blk-pci, id ""
dev-prop: class = 0x100
dev-prop: drive = virtio0
dev-prop: logical_block_size = 512
dev-prop: physical_block_size = 512
dev-prop: min_io_size = 0
dev-prop: opt_io_size = 0
dev-prop: bootindex = -1
dev-prop: discard_granularity = 0
dev-prop: ioeventfd = off
dev-prop: vectors = 2
dev-prop: indirect_desc = off
dev-prop: scsi = on
bus-prop: addr = 04.0
bus-prop: romfile =
bus-prop: rombar = 1
bus-prop: multifunction = off
bus-prop: command_serr_enable = on
class SCSI controller, addr 00:04.0, pci id 1af4:1001 (sub 1af4:0002)
bar 0: i/o at 0xc040 [0xc07f]
bar 1: mem at 0xe2021000 [0xe2021fff]
addrとindexの関係
indexとそれと関連するbus_idとunit_idは、virtioでは関係がなさそう。addrを00-1fの間で指定した場合には、その位置へdeviceが割り当てられる。
addrと/dev/
addr=0x8 と addr=0x4 のdriveをつけたVMを起動すると、/dev/vda(=0x4) /dev/vdb(0x8) となった。PCI addressの順番がそのままdevice nameになっている様子。飛び順のdevice nameを付けさせるのは、udevをいじったりする必要があるなど骨が折れそう。
2011/10/25
qemu ゆるふわリスト
qemu-kvmがいまだにゆるふわな作りなので、遭遇した問題を書いておく。
pci_delの入力値
v0.12.3 で遭遇。
qemu monitor shell(qemu shell)で、pci_add によるPCI device hotplugを行う。成功時には、以下のような内容になる。
(qemu) pci_add xxx .....
OK domain 0, bus 0, slot 4, function 0
戻り値として表示されているPCIのdevice addressはdecimal。例えば、17番目のslotにdeviceが挿入されるとすると、
(qemu) pci_add xxx .....
OK domain 0, bus 0, slot 17, function 0
になる。
問題は、pci表示系の出力は全部decimalになっているのに、pci_add/pci_delの変更系のコマンドに対してはhexで入力しないといけないこと。
-no-shutdown 問題(UNIX signal問題含む)
v0.14.0で確認。
-no-shutdown を入れると、guestからshutdownしてもqemuプロセスが死なないとmanには書いてあるが、2度目にqemuプロセスが死んでしまう。
または、UNIX signalを送っても終了しなくなる。
- guestからshtudown/poweroff等のコマンドを実行。
- qemu-kvmのstatusがrunning -> paused へ変化。
- qemu shellから "cont" コマンドで再始動させる。resetされ再起動開始。
- 2度目 guestからshutdown操作を実行。
- qemuプロセスがお亡くなりになる。
原因は、no_shutdownグローバル変数一個だけで制御を行おうとしていること。v0.15.0かそれを超えた辺りで、この問題の修正を見つけたので、v0.16.0が出れば修正されているはず。
2011/10/14
パッチを当てたdebパッケージを作る。
既存のdebを書き換えて自分用のパッケージを作ってみたかったのでやってみた。
まず、source packageを取ってくる必要がある。この他ににもpackage.ubuntu.comなどの一覧ページから手動で取ってくるとかもできる。というか、いつもだいたいそんな感じ。
% apt-get source qemu-kvm
% ls
qemu-kvm_0.14.1+noroms-0ubuntu6.diff.gz
qemu-kvm_0.14.1+noroms-0ubuntu6.dsc
qemu-kvm_0.14.1+noroms.orig.tar.gz
% dpkg-source -x qemu-kvm_0.14.1+noroms-0ubuntu6.dsc
% ls
qemu-kvm-0.14.1+noroms/
% cd qemu-kvm-0.14.1+noroms
% quilt new new-patch.patch
% quilt add vl.c
% vi vl.c
% quilt refresh
% quilt -e header
ここまでやると、debian/patches/new-patch.patch というファイルができて修正内容がpatchファイルとして保存される。
debian/changes へ変更内容の記録とパッケージ名の指定を行う。dch コマンドを使うと、エディタが起動する。
# -i (increment)で、新しいエントリとして追記。-a で既存の先頭のエントリへ追記する。
% dch -i
qemu-kvm (0.14.1+noroms-0ubuntu6backport1) lucid; urgency=low
* new change
-- Dev Thu, 13 Oct 2011 13:38:05 +0900
この作業する前に、環境変数をきちんと指定しておくと、メールアドレス等がきちんと自動で入力される様子。めんどくさいので手で入力した。
先頭行の () の中が結構重要で、この文字列がそのままパッケージファイル名の一部となる。表記の仕方が細かく決まっている様子だったけれど、細かいことは無視してすすめる。注意が必要なのは、"-"をこれ以上増やしてはいけないとか、最後は数字にしておくとか。この場合だと、元の内容が "0.14.1+noroms-0ubuntu6" だったものを "0.14.1+noroms-0ubuntu6backport1"に変更した。
debuild使ってみたけれど、signをしない設定がわからなかったので結局dpkg-buildpackageした。
% dpkg-buildpackage -us -uc -rfakeroot
問題なく進むと、
% ls ../
kvm_84+dfsg-0ubuntu16+0.14.1+noroms+0ubuntu6backport1_amd64.deb
qemu_0.14.1+noroms-0ubuntu6backport1_amd64.deb
qemu-common_0.14.1+noroms-0ubuntu6backport1_all.deb
qemu-kvm_0.14.1+noroms-0ubuntu6backport1_amd64.deb
qemu-kvm_0.14.1+noroms-0ubuntu6backport1.dsc
qemu-kvm_0.14.1+noroms-0ubuntu6backport1.diff.gz
の様なファイル群が増えているはず。
これらの.debをdpkg -i してやるとインストールできる。
qemu-kvm_0.14.1+noroms.orig.tar.gz
qemu-kvm_0.14.1+noroms-0ubuntu6backport1.diff.gz
qemu-kvm_0.14.1+noroms-0ubuntu6backport1.dsc
の組み合わせで、変更後のsource packageとしての配布も出来るはず。
他によく有りそうなケースとしては、debug symbol付きのバイナリが欲しいので自分でpackageをbuildするとかいうのがありそう。普通にdpkg-buildpackage してしまうと、dh_stripという処理が走るせいでdebug symbolが失われてしまう。
dpkg-buildpackageするまえに、debian/rulesからdh_stripコマンドが走るところをコメントにする必要がある。
% vi debian/rules
#dh_strip -s
この後buildpackageすると、debug symbol付きのバイナリが入ったpackageが出来上がる。release版を作るときにコメントを外すのを忘れそうなのが問題だけど。環境変数の指定で、dh_stripを一時的に動かなくする方法とかあるのかなぁ。
DEB_BUILD_OPTIONSを適切に設定すると、目的が達成できるそうだ。
DEB_BUILD_OPTIONS=nostrip,debug
http://www.netfort.gr.jp/~yabuki/diary/20040601.html
参考
2011/08/19
Rubyのメモリ利用
GCとcompactionについて色々理解が進んだのでメモ的に書いてみる。
Garbage collectionとは、参照されていないオブジェクトを解放する操作のことである。ここでいう解放とは、必ずしもCで言う所のfree()的な操作とは一致していない。まず、ここをよく理解していなかった。理解してないとどういうことになるかというと、例えばメモリリークについて調べようとしたときに、OSサイドから見える情報で問題が起きているだとかないだとか言ってしまう。
というか、そもそもGCとは逆の確保という操作についてもmalloc()的な操作が絡むとも言えない。これらは、GCがどういう実装になっているかによって、定義が変わってくる。
今回は、Rubyで長時間走るプロセスについてメモリの増加をできるだけ抑えたいという目的があった。ので、ここに書いてあることはRubyはこんな感じにメモリを使うものですよというだけのことである。ややこしいのは、Rubyにはいくつも異なる実装があり、それぞれが異なるGCを持っているということだ。同じ系統の実装でも、バージョンが変われば実装も変わっていることも考えられる。なので、この関係の話をするときはは、どの実装について話をしているのかはっきりさせてすすめるのが良さそうだ。
CRuby 1.8.7 と1.9.2で幾つかテストプログラムを書いて試したところ、こんな流れで動くことがわかった。
a=[]
99999.times { a << {} }
などどすると、Rubyのプロセスが膨れ上がる。
a.clear
とすると、Arrayオブジェクトがimmutableだったとしても、99999個分のHashオブジェクトは解放の対象となるはず。そこで
GC.start
として明示的にGCを走らせる。しかし、psなどから見えるOSプロセスとしてのメモリの利用量の変化はほとんどない。次に同じように、
99999.times { a << {} }
ともう一度やる。今度はOSプロセスとしてメモリの利用量はあまり増えない。
同じように、a.clearしても特に目立った変化はない。ここまでやってみてわかったことは、
- CRubyは、必要なメモリがないときはmalloc()的な動作を行いメモリの確保を行う。
- オブジェクトへの参照をなくして、明示的にGC.startして解放の処理を行っても、free()的な処理を行ってOSへメモリを返却しているわけではない。
- 一度確保されたメモリ領域を超えない範囲で新規オブジェクトの生成を行うと、確保済みの領域を再利用するようだ。
こんな状態なので、CRuby VMの外側からは細かくは何が起きているのかうかがい知ることはできない。
これ以上のことを知るためには、CRuby VMから必要な情報を取得するメモリプロファイラを使うしかない。1.9.2には、GC::Profilerという簡易プロファイラが内蔵されており、それを使っていろんな内容を試すことができる。1.8.7にはmemprof gemがあり、機能的にはこちらのほうが充実しているようだがx86_64環境でしか動かないという事が書いてあった。
もう眠たいので簡単に書くと、GC::Profilerを使うとGC.startする前と後とで大きく変化する値があることが分かる。結果、プロファイラを使うことで分かったことは、「3」で内部的に何が起きていたのかということだけであった。あとは、Rubyのプログラムとしてメモリリークが起こっていそうという時は、これらのツールを積極的に使わないと分からないということもある。
そろそろまとめに入ると、CRubyにとってのGCとは、参照のなくなったオブジェクトを解放することではあるが、確保したメモリの解放を行うという操作ではないということだ。このGCの目的は、メモリをOSに返すことではなく、確保済みのメモリをできるだけ他の新しいオブジェクトで再利用したい、という所にあるようだ。まぁ、こんなことはRubyの本などにはしっかり書いてありそうだけど、ようやく意味が理解できるところまで来たということで。
以上のことから、OSからみたCRubyのメモリ利用の傾向は、
- メモリをある程度のサイズずつ必要となるタイミングでmallocしていく。
- mallocした範囲はfreeしない。
であることがわかった。デーモンプロセスのような常時起動型のプログラムをRubyで書いているのに、なんて厳しい。
でも、よくよく考えてみると本当に厳しい内容なのかというと実はそうでもないかもしれない。という話を次回やってみたい。
ATX/EPS 12V 電源
PC自作の話。
自作はもうやらないと決めて早幾年。しかし、にわか自作好きに、訳もわからず買われた機械たちを何とか動かすため色々情報集めをした。
買われたマザーボードは、Supermicroの X7DAL-Eというモデル。対応しているCPUは、Xeonの5300-5400系列。2011年半ばにもなって、なんでこんな数年前の型落ちを買ってくるのか甚だセンスに疑問を感じるが、どうしてもDual CPUをやりたかったのが理由なようだ。今時一つのCPUに何個もCoreが入ってるんだから、Dual CPUにこだわるとか意味が分からない。
そして、電源をつないでいるのに電源が入らないとかいうどうしようもない状態に。一緒に買った電源は、Rosewillの
RG630-S12と言う奴。まず、マザーボード上の電源コネクタが合わない。RG630が持っているコネクタ(マザーボード用)は、24pin+8pin のみ。X7DAL-Eが必要とするコネクタは、24+8+4というタイプ。PCI-E用の別のコネクタを無理やり差してみたりしていたけれど、何も進展なし。
最近のよくわかってない状態で自作をやるのは嫌くさいという理由で放置していたが、やっぱり動かしたほうがいいということになって悪あがきを始めた。昔自作していた時も、電源のコネクタとか気にしたことがないので、こんなこともあるのかという感じ。
ちょっと調べて理解できたのは以下の範囲。
- ATX+12V という電源規格がある。
- それを拡張する形でEPS+12V っていう規格がある。
- 両方共24pinの電源コネクタがある。これはCPUの電源供給用ではないということが書いてあるページもあった。
- CPUは、別のコネクタ8pin(EPS)/4pin(ATX) から供給を受ける。
RG630はEPS対応電源でもあるので、4pin+4pinの形で8pinを構成できるようになっていた。しかし、マザーボード上には、24pin, 8pinとは別に、4pinの穴が残っている。
他の製品と比べてみたら、「+12V Rails」と書いてある項目に違いがあることに気がついた。Single, 2, 4 などが書いてあり、2と書いてあるタイプの電源を調べると、たしかに4pinの別のコネクタがついている。おそらくDual CPUのマザーボードにしたために8pinとは別に電源が必要で、それに対応した電源を合わせて買う必要があったということらしい。
RG630 はSingle Railの製品なので、間違った電源を買ってきたということになる。2 Rails 以上の製品を買ってきて動くかどうか試してみようと思う。
2011/08/06
A virgin shot
I have bought an entry level SLR camera so they are the first shot from it. Those pictures come from a dinner with friends at the restaurant provides good meal in this area.
2010/04/01
coLinuxのカーネルをrecompile
cn.ko が入ってなくてnetlinkのテストコードが動かんので、coLinuxのカーネルをrecompileした。以下のページを参考にした。
coLinuxのsrcアーカイブを落として、tar zxf したら、coLinux-0.7.6/conf/linux-2.6.22.18-configのようなkconfigファイルが置いてあるので、それを編集して./configure; make kernel するだけであった。
mingw32とか入ってないといけないのかとか心配したけれど、vmlinux とmoduleのバイナリは普通のelfみたいで普通にgccが入っていればいけた。簡単簡単。