Ubuntu 18.04.1 LTSでやる 30日OS本 〜13日目〜

Ubuntu 18.04.1 LTSでやる 30日OS本、13日目です。 他の章へのリンクはここにあります。

今回は久しぶりにハマったので内容多めです。

1. 文字列表示を簡単に

文字の描画の際、背景色での塗りつぶし・文字書き込み・画面再描画がワンセットとなるので、これをまとめてしまおうというものです。 文字を表示する部分はほとんどこれで書き換えました。

しかし、文字を重ねて書きたい場合はこれを利用することはできません。たとえば、画像の右下の「Haribote OS」の文字は 重ねることで立体感を出しています。この部分は従来の方法で描画することにしました。

f:id:wisteria0410ss:20190210203938p:plain
右下の文字は以前の表示方法のままにしておく

2. FIFOバッファを見直す(1)

はい。

3. 性能を測定してみる

ここで詰まりました。main関数内のループ冒頭で、文字列表示部分を消してcount++;のみにするとQEMUで動かしたときに反応がなくなってしまいました。 点滅カーソルも出てこなければ、キーボードやマウスを動かしても画面に変化が現れないという状態です。 (正確には、反応がものすごく遅くなっていると言ったほうが良いのかも(たまに数十秒後にキーボードやマウスを動かしたのが反映される))

プログラム上の誤りを疑って付録CD-ROMのコードと比較しましたが、原因となりそうな箇所は発見できませんでした。 その後、実機で動かしたりvirtual boxを利用したりしてみたところ問題なく動作したので、QEMUまわりの何かが悪そうです。

結論を言えば、なぜこのような症状が出たのか、原因についてはまだ理解できていません。 ただ、適切に準備した上でqemu-system-i386にオプション-enable-kvmをつけて実行するようにすると 想定通りの動作をするようになりました。以下、この解決に至るまでの流れなどを述べていきます。興味のない方は次の節へ進んでください。

なお、解決後の測定結果はQEMU上のものが {7.097(2)\times 10^8}カウント、実機が  {6.9598(4)\times 10^8}カウントとなりました。 QEMU上では10回、実機では5回測定を行い、ここでは平均値と標準誤差を示しました。 実機のほうが誤差が小さいものの、本に書いてあるよりは大きい気がします。また、以前のタイマーを組み込んだ測定は変更箇所が多く面倒だったので省略しました。

解決に至るまでの試行錯誤の記録

動かない

本文のとおりにプログラムを変更してmake runしたところ、画面が動かない。 問題の箇所を絞り込むと、ループ冒頭の文字列描画の命令を消したあたりが怪しいとわかる。 ここにputfonts8_ascをおいて1文字でも描画することにすれば以前と同様にちゃんと動作する。 また、キューが空のときのio_sti();io_stihlt();に変更しても動くようになる。

原因の特定に行き詰まったので実機で動かしてみたところ、ちゃんと動作した。 QEMU以外のツールとしてvirtualboxで試したところ、これも問題なく動く。

KVM

QEMU 遅い」のように雑にググるKVMという単語がかなりヒットする。 なので、これをインストールする方法を調べてやっていくことにする。(参考: Ubuntu 16.04: KVMをインストールして仮想マシンを起動する - Narrow Escape

インストールは

$ sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager libguestfs-tools

でOK。ここではこれを全部入れる必要はないかも知れない。 とりあえずvirt-managerを起動して、「新しい仮想マシンの作成」から画面に従って Haribote OSを動かしてみたところ問題なく動作した。しかも、動いているウィンドウのタイトルバーには QEMUの文字がある。

少し工夫すれば今までに近い方法で動かせそうという気持ちになる。

コマンドでHaribote OS起動

なぜかharibote.imgがroot所有になって書き込めなくなっていたのでchownして取り戻した。

さて、ターミナルから直接Haribote OSを起動してやりたいが、調べてみるとkvmで行けるらしい。まず引数なしでやる。

$ kvm
qemu-system-x86_64: warning: host doesn't support requested feature: CPUID.80000001H:ECX.svm [bit 2]

本体は今まで使っていたQEMUに過ぎないらしい。とするとkvm -fda haribote.imgを試したくなるが、 Could not access KVM kernel module: Permission deniedと怒られる。sudoすればいけた。

cat /etc/groupしてみるとそれっぽいグループがあるので自分を追加。 sudo gpasswd libvirt -a ユーザー名とかsudo gpasswd kvm -a ユーザー名を してやればいいみたい。要再起動。 これでsudoなしでもできるようになる。

解決へ

kvmと打ち込んだとき、どうQEMUが絡んでくるのかを探る。

$ which kvm
/usr/bin/kvm
$ cat /usr/bin/kvm
#!/bin/sh
exec qemu-system-x86_64 -enable-kvm "$@"

予想以上に単純だった。

というわけで、Makefileを次のように変更すれば良さそうだとわかる。

run: haribote.img
    qemu-system-i386 -m 32 -fda haribote.img -enable-kvm

-enable-kvmを追記しただけ。make run。うごいた……

これは1日目での準備が適切でなかったということなんでしょうか。

4. FIFOバッファを見直す(2)

unsigned charで持っていたFIFOバッファをintで持つようにします。これで各キューを一本化しました。

この変更を行った後の測定結果は、QEMU上のものが {1.2045(5)\times 10^9}カウント、実機が  {1.17693481(8)\times 10^9}カウントとなりました。 3. と同様、QEMU上では10回、実機では5回測定を行いました。有意な改善がみられ、さらに実機でのばらつきがかなり小さくなっています。

5. 割り込み処理は短く(4)

タイマの情報の管理を単純な配列から線形リストに変更することで挿入・削除を簡単に行えるようにしました。

ここでの測定結果はQEMU {1.2075(7)\times 10^9}カウント、実機で  {1.17693383(9)\times 10^9}カウントとなりました。 確かに実機では若干悪くなっているようです(エミュレータ上では逆に良くなっています)。

6. 番兵を使ってプログラムを短くしてみる

一番後ろに番兵をおいてやることで挿入・削除の処理を簡単にしました。

ここでの測定結果はQEMU {1.209(1)\times 10^9}カウント、実機で  {1.1769334(2)\times 10^9}カウントとなりました。