未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

ラーニングカーブ

試行錯誤の数で人は学んでゆく。多くの失敗はその人の糧になる。プログラミングを学ぶ過程はまさに失敗の連続である。プログラムを書く。スペルミスをする。コンマとピリオドを間違える。大文字と小文字を間違える。0とOを間違える。コンパイルが通らない。いきなりクラッシュする。起動すらしない。なんてことを延々繰り返すのである。
ソフトウェアプロジェクトも同様である。スケジュール通り物事が進んだ例がない。問題はいたるところから発生する。要求仕様はころころかわる。プロジェクトメンバーがいきなり退職する。問題は山積しているが解決の糸口さえ掴めない。なんてことを延々と繰り返す。しかし、その繰り返しの中で人々は学んで行くのである。一つのプロジェクトが仮に1年かかるとすると3回くらいそれを経験すれば、まあ一人前である。そうすると一人前になるのに3年かかるということになる。大規模ソフトウェアでそれが仮に1バージョンの開発が3年かかるとすると、3バージョンは9年に相当する。うーん、ネット時代では太古の昔の話になってしまう。経験から得られる知恵はこのライフサイクルを何回まわすかにかかっているような気がする。
この手の知恵はなかなか文書では伝わらないような気もするし、その手の経験や知恵が明文化されていることは少ないような気もする。もちろん例外はあって、人月の神話―狼人間を撃つ銀の弾はない (Professional computing series (別巻3)) 人月の神話はまさにその手の知見を広く知らしめた書物である。
プログラマとしての成長はそのようなトライ&エラーまさに試行錯誤の連続をいかに積み重ねたか、いってみれば、ラーニングカーブをどう走り抜けたかである。
今回久々にカーネルビルドなんかをしちゃったのだが、カーネルプログラマの場合の進歩の度合と言うのはLL(Lightweight Language)系の進歩の度合と比べて、そーとー鈍いような気がする。LL系はほぼ垂直に立ち上がるような感じがするが、それに比べてのったりとしているような感じである。どーゆーことか?
プログラミングというのは試行錯誤である。エディタで何かを書く。コンパイルする(ビルドする)。試す。期待する結果か?期待する結果が得られるまで繰り返す。というループを延々繰り返す。この繰り返しが、スクリプト系言語だと、コンパイルの部分をすっとばして、即実行、即確認、即繰り返し、即即即である。
カーネル?ビルド、数分かかる。grubの設定やらなんやら微妙なパラメータの設定をし、リブート。PCサーバーで開発していた日にはリブートだけで数分かかる。大きなスループットのでかいマシンほど、メモリがいっぱいあって、BIOSのメモリチェックだRAIDカードのチェックだ、ハードウェアの認識だなんだでやたら時間がかかる。大きめのマシンでの開発だと、机の下にマシンを置くのではなく、コンピュータルームかなんかに置いてあるものだから、いろいろ微妙な設定をしたあと、何十歩か歩いてコンピュータルームまで行って当該マシンの前でリブートの画面を眺める事になる。微妙な設定を間違えるとマシンは立ち上がりません。カーネルパニックですから。長いBIOSのメモリチェックやらなんやらの後にgrubの画面が出てその後Linuxの起動の文字が流れてカーネルパニックですから。最後の一画面にでている情報をもとにカーネルパニックの原因究明と解決をはからないといけない。新カーネルを作った。だけどgrub.confの記述を間違えた。リブート。grub.confの記述は正しいが、ビルドしたカーネルを/bootディレクトリにコピーする時、ファイル名を間違えた。リブート。ビルドしたカーネルは正しく/bootにコピーしたが、initrdを正しく設定していなかった。リブート。initrdは正しく設定し、/bootに正しく(もちろんファイル名はちゃんと確認した)コピーしたが、modules_installしていなかった。リブート。えと、何回リブートしたっけ?この繰り返しの中で今作っているカーネルの機能のテストなんかには全然行きつかないところで、すなわち門前払いを何度もくっているのである。カーネルパニックの時はとりあえづ昔の動くカーネルで立ち上げ直して、それで原因究明をして解決しないといけない。たかだかファイル名を間違えた程度のトリビアの問題ですらリブートして解決するまで30分はかかるよな気がする。カーネルビルドプロセスはおおむね下記のようなものだ。

 # make oldconfig
 # make -j CPUの数
 # make modules
 # make modules_install
 # mkinitrd xxxx.img カーネルバージョン番号
 # ビルドしたものを/bootにコピーする
 # 必要であれば/etc/grub.confの設定
 # reboot

このプロセスのうち一つでも間違った日にはPC立ち上がりませんから。リブート。まあ、ちゃんとブートするようになればもう半分終ったようなものである。ここまでスクリプト言語ではれば即即即30秒だったのが、良くて半日、ひどい時になるともう3日もlogin画面を見てませんから。ということになる。
さてやっと立ち上がってから今度は機能的なテストにはいる。期待する機能を実装できているかどうか?ユーザーアプリと違ってデバッガなどないから、致命的なバク即カーネルパニックである。リブート。どうにか問題を修正して上記ビルドプロセスを繰り返して(もちろんファイル名を間違えたりするのであるが)、徐々に安定して動くようになる。時間感覚で言うと日の単位である。時とか分の単位ではない。良い感じにベンチマーク結果なんか出る日には心はウキウキ、体は軽い。自然と鼻歌か何か歌っていたりする。通常は思った通りに性能が出なかったり、なんだか良くわからない条件でカーネルパニックしたりする。なかなか心が晴れない日々を過ごしたりする。まあ、そーゆー辛いトンネルをくぐってどうにか安定して来たのでLKML (Linux Kernel Mailing List)にでもパッチを出すか?というところまで、週の単位の時間がかかる。
今回のパッチの例で言うとこんな感じだ。8月6日、ウエンディーズでコーヒーを飲んでいる時に読んでいた本に触発されて、ロックの競合から攻めるのではなくキャッシュの方から攻めたらどうだろうか?と思い立つ。7日にほんじゃま、どのくらいたちの悪いキャッシュミスが発生しているかoprofileで調べてみようと。8日に開発基盤WGのOS層のミーティングがあったので週末に思い付いたアイデアをいろいろ話して自分なりの考えを述べる。9日はYLUGカーネル読書会の「小ネタ」のコーナーで世間(?)に披露する。この時点で実装はまったくない。いろいろするどい突っ込みをいただく。10日からパッチを作りはじめるが、カーネルパニックで立ち上がりすらしない。11日になってやっと立ち上がる。でいろいろベンチマークをして基礎的なデータをとって、LKMLにデビューしたのが14日。http://marc.theaimsgroup.com/?l=linux-kernel&m=112401103800730&w=2いろいろLKMLやらYLUGで議論をしてほぼ最終系がまとまるのが9月1日である。http://marc.theaimsgroup.com/?l=linux-kernel&m=112556596103063&w=2そしてAndrew Mortonさんの-mm patchにいれてもらったのが9月4日だった。ちなみに9月4日はわたしの誕生日でもあるから、バースデープレゼントみたいなものである。(2.6.13-mm2にわたしのパッチがはいっているhttp://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.13/2.6.13-mm2/2.6.13-mm2.bz2)
一つのパッチを作るのに一月かかっている。LLなら30分か?メーリングリストで議論しても1日の単位だろう。LL系の若者があっと言うまに先を走り抜けて行く。わたしはのったりのったり亀の歩みである。
高速道路が整備されている世界と獣道しかない世界の差である。道は険しいが一歩一歩先人の歩いた道を歯をくいしばって歩いて行くしかない。この経験をいろいろな人と共有しながら獣道を進んで行くというのも悪くはないと思う。それがオープンソースの醍醐味でもあるしね。