MIRACLE
メールサービス申込 ユーザー登録 パートナー情報
お問い合わせ FAQ サイトマップ
MIRACLE LINUXの特長 製品紹介 サービス案内 購入 サポート 技術フォーラム

プロフィール

吉岡 弘隆 - よしおか ひろたか

日本OSS推進フォーラム ステアリングコミッティ委員
OSDL Board of Directorsを歴任
カーネル読書会主宰

2000年6月、ミラクル・リナックスの創業に参加。
95年~98年、米国OracleにてOracle RDBMSの開発をおこなっていた。
98年にNetscapeのソースコード公開(Mozilla)に衝撃をうけ、オープンソースの世界に飛びこみ、ついには会社も立ち上げてしまう。
2008年6月取締役CTOを退任し一プログラマとなった。

ミラクル関連リンク

なかのひと

サイト検索

2010年8月

1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

memcached Night in Tokyo #1

先日開催された memcached Night in Tokyo #1 というのに参加してきた。

http://groups.google.com/group/memcached-ja/web/memcached-night-in-tokyo-1

夕方6時開催という昨今の勉強会としては早めの開始時刻なので、あたふたと会社を出た。場所は原宿である。おされな場所である。浮足立つ。ということはどうでも良くて会場であるmixiに初めていったのだが綺麗なオフィスであった。

memcachedというのは、データベースに対する分散メモリキャッシュ技術みたいなもので昨今のWebではよく利用されている。国内ではmixiでの事例がよく知られている。

http://ja.wikipedia.org/wiki/Memcached

この話を初めて聞いたとき、うーん随分乱暴な話だな、RDBMSでやるべき仕事だろ、そーゆーことはと思った。由緒正しいRDBMSではこーゆーのはいかんだろう的なことを思った。しかし発想の転換というかちょっとしたハックというか、実際memcachedのソースコードは6千行位のきわめてシンプルな実装になっていて、MySQLとかスケールしねーよなあとか思っていたハッカーが自分の問題を素早く解決するために作ちゃったという感じなんだろうな、などとも思う。作ってみたら思いのほかいい感じで使いやすくて、どんどん適用事例も生まれ、ソースコードもオープンなので、米国あたりのWeb2.0系企業でがしがし使われるようになったと。

昨今OSやらRDBMSやらアプリケーションサーバやらWebサーバやらありとあらゆるものがオープンソースなので、どこで問題を最適化してもよくてRDBMSの上にちょっとしたキャッシュをおいて擬似的に高速化をはかってみたというのがmemcachedなのだろうなと思う。

mixiでは135台のmemcachedサーバを利用していて(この数もすごいな、国内最大級かな)、メモリを3GBほどわりあてているらしい。マシンはPentium 4との事なので発熱とかもすごそうな気がする。

KLABの安井さんのお話はmemcachedのreplicationだった。memcachedはシステムが死ぬとデータが消失するので、リプリケートをして永続性を持たせたいなあというお話である。永続性とかフェールオーバーとか信頼性とか、そーゆー事を言いだすと、話がどんどん複雑になるのでmemcachedとは相性が悪いのではないだろうかと思うのだけど、どうなんだろう。この手の話も昔からあって、本当の信頼性を求めるなら完全二重化とか、そーゆー話になるのだけど、コストと拡張性のバランスも必要で、さらにはスケーラビリティをどうするかという問題もあって難しい。また非同期の更新だとどうしても原子性をどう担保するかという問題もある。いっそのこと楽観的にやっちゃて、矛盾が発生したらリトライという感じでもいいのかもしれない。

すずききよたか(kiyotaka)さんのお話はmemcachedの利用をいろいろな角度からしていた。まあ、消える可能性のある汎用DBというのは言いえて妙である。Solarisで運用しているので、Solarisのお友達を募集していた。困っている事を自分から晒すというのは勉強会メソッドとしては黄金のパターンかと思う。そして同志と出あう。memcachedを使っているだけではなくSolarisで使っているという同志の結束は固そうに見えた。

mixiの長野(kazeburo)さんは大規模事例で、特にがりがりチューニングをしているという感じではなかった。

はてなの田中(stanaka)さん、30台のcore2 quad メモリ8GBで運用している。それぞれにはXenでmemcachedサーバとアプリケーションサーバを起動しているらしい。こちらも特にチューニングしているという感じではなかった。

mixiの前坂(tmaesaka)さんはmemcached Binary Protocolの解説である。こーゆープロトコルの設計の話は好きだ。速度命だし。テキストのプロトコルだとパースデコードのコストがかかるのであらかじめ定義したバイナリのプロトコルで高速化をはかろうというお話である。バイナリプロトコルであればインジェクションは簡単ではないのでセキュリティ向上にもつながるよ。

固定長のヘッダ(16バイト)+可変長のオマケのフィールドというデータ構造になっている。

http://code.sixapart.com/svn/memcached/branches/binary/server/doc/protocol-binary.txt

opcodeが1バイトなので要素256個の配列で命令実行ルーチンが書ける。デコードのコストは表引きだ。これがASCIIテキストだとstrcmp(command,"hogehoge")みたいなものを延々コマンドの数だけ書くはめになって、コマンドの数に比例したデコードコストがかかったりする。(まあパーフェクトハッシュ関数とか書けばいいのだがカジュアルに命令を追加したりとかはいろいろ面倒なので、結局はstrcmpで延々比較という泥仕事になる)

opcodeを固定長にするというのは王道中の王道のテクニックである。CISCに対するRISC的なアプローチと言ってもさしつかえない。

まあ、そんなことを思ったのだが、この手の古典的な高速化のテクニックというのは昔からずうっと変化していなくて、再発見、再発明が延々繰替えされているような気もする。

温故知新なのである。

でもって現在の実装についてちゃんとoprofileとかでミクロのプロファイリングを取って、チューニングをはじめたという事ではなく、なんとなく直観でぐわっとやっているらしい。まあ、それでもいいっちゃいいのだけど、ちゃんとベンチマークを定義して、oprofileなどでプロファイリングをして、ボトルネックを数字で示し、チューニング大会をするというのが正しい大人の姿である。

いろいろ設定準備とか大変だとは思うが、一度そのような環境を構築してしまえば、開発の最中、運用時等々貴重なデータを入手でき、パフォーマンスデバッグ(チューニング)のインフラになる。開発のプロセスに組込むというお作法は重要だ。なかなか実践するのは難しいが。

プロファイリングしてチューニングをする。王道中の王道だ。

まあ、こーゆーことをお酒を飲みながら、わいわいがやがや語るというのも勉強会の醍醐味でもある。

おまけ:

ソースコードはgithubで公開されているのでためしにゲットしてみた。

$ time git-clone git://github.com/tmaesaka/memcached.git
Initialized empty Git repository in /proj/memcached/.git/
remote: Counting objects: 1602, done.
remote: Compressing objects: 100% (472/472), done.
remote: Total 1602 (delta 1161), reused 1537 (delta 1108)
Receiving objects: 100% (1602/1602), 592.77 KiB | 237 KiB/s, done.
Resolving deltas: 100% (1161/1161), done.

real    0m4.901s
user    0m0.612s
sys    0m0.084s

memcached.c の dispatch_bin_command() はバイナリプロトコルのディスパッチルーチンであるが、だめじゃん。

switch(c->cmd) {
    case PROTOCOL_BINARY_CMD_VERSION:

とかしている。ここは表引きだろう。しかもc->cmdの定義はuint8_tではない。だめじゃん。深入りしないことにした。

プログラマ35歳定年(停年)説

わたしに不用意にふってはいけないネタとして、プログラマ35歳定年(停年)説というのがある。飲み会かなにかの席でなにげなく、そのような話題を出し、延々聞きたくもない話を聞かされた被害者の方も少なくない。

血圧があがるネタである。

誰がいつごろからそんな事を言ったのだろう。

まあ、それはともかく、プログラマといってもいろいろあるわけで情報技術(IT)という分野も話している人によって全然違う話しをしているのに、双方とも気がついていなくて延々すれ違いの議論をするということも多い。

例えば、ITについても、(1)OSとかコンパイラとかRDBMSとかいわゆる基盤系技術、(2)エンタープライズ系(企業の情報システムとか)、(3)ミッションクリティカル系(勘定系、社会基盤系(電力送電網)とか)、(4)Webサービス系(Web2.0?)、(5)組込系(いろいろ)、などなど種々雑多ある。

またビジネス形態としても、(a)ソフトウェア製品開発、販売、(b)SI(受託開発)、(c)コンサルティング、(d)運用サービス、サポート、(e)Webサービス(Web2.0?)等々これまたいろいろある。

日本にはマイクロソフトとかOracleみたいな基盤系のソフトウェア製品開発販売の専業ベンダーというのはほとんどなくて、大手ハードウェアメーカがハードウェア販売のおまけ(?)みたいな感じで細々と商売をしていたりする。

そーするとだ、RDBMSを作りたいとかOSを作りたいと思った若者は、当該製品を作っている主に外資系に就職するくらいしか選択肢がなかったわけだ。大手ハードウェアメーカに就職しても商品としてのOSとかRDBMSの開発はほとんどやっていないので自分のやりたいことはできない。

昨今だとLinuxやMySQL/PostgreSQLなどオープンソースソフトウェアのおかげで別に大手ベンダーなり外資系ベンダーなりに就職しなくても、意欲さえあれば自分でがんがんコードを書くことは可能になった。

わたしのキャリアは1-aのパターンで、それ以外のところには正直土地勘がない。デスマーチの大規模エンタープライズ案件の修羅場とかはくぐったことがないので実状はどうなのかよくわからない。

最近はmixi、モバゲー、ニコ動などWebサービス系の開発現場のお話を聞く機会が多いのだが、その開発スタイルというのはウォーターフォールモデルとは全くことなる原理原則で開発されていて、それはそれで大変興味深い。

SIなんかは多重下請け構造みたいなのに組みこまれてしまうと単価勝負の世界になって人月いくらという話になるというのは理屈ではわかる。でもそれって経営者が、そーゆー判断したんじゃね?経営の問題じゃね?とか思う。

そーするとやはり案件ごとの受託開発よりも自社開発のソフトウェア製品開発とかWebサービス、あるいは運営サービス、サポートなんかの方が自社の強み特長をいかせておもしろいような気がする。

技術についても基盤系であればかなり蓄積が効くし、経験のつみかさねが強みになる。

そんでもって35歳停年説にもどるのだが、わたしがシリコンバレーに行ったのは36歳で、コードを書きまくったのが30代後半だった。未踏ソフトウェアは44歳、Cache Pollution Aware Patchは46歳、取締役退任。生涯一プログラマ宣言は49歳。そしてこの9月4日で50歳だ。

年齢は関係ない。限界を決めるのは自分だ。

Do not limit your self.

注記:定年の表記に関しては当初は停年と記していましたが、定年の方が一般的なようなので、そのようにしました。

未踏ソフトウェア奮闘記
http://itpro.nikkeibp.co.jp/members/NSW/ITARTICLE/20030619/1/
http://itpro.nikkeibp.co.jp/members/NSW/ITARTICLE/20030619/2/
http://itpro.nikkeibp.co.jp/members/NSW/ITARTICLE/20030709/1/
http://itpro.nikkeibp.co.jp/members/NSW/ITARTICLE/20030709/2/

Linux Kernel 2.6.18とCache Pollution Aware Patch/ユメのチカラ
http://blog.miraclelinux.com/yume/2006/09/linux_kernel_26_2c2c.html

エンジニアの未来サミット
http://gihyo.jp/news/report/01/engineer
http://gihyo.jp/event/2008/engineer
パネリストとして参加します。

創刊号巻頭座談会「エンジニアのマインドとは」~ボーナストラック
#3 座談会「エンジニアのマインドとは」
http://gihyo.jp/dev/serial/01/talks-bt/0003?page=2

プログラミングはパッションだ

この夏、セキュリティ&プログラミングキャンプU-20プログラミングコンテストの実行委員、審査委員をした。若い人達のプログラムに対する姿勢を身近に接っする機会があった。

キャンプは4泊5日の長丁場だし、U-20プログラミングコンテストの審査は一次審査、最終審査それぞれ丸々一日、ずっぽり若者のプログラムにひたりっぱなしであった。体力勝負の感もなくはないが彼等の発想を真のあたりにする大変貴重な機会となった。

プログラミングの技能(テクニック)はおそらく座学でも伝達できる。細い技術的な事は授業することができる。だけど、プログラミングの楽しさや面白さをどう伝えたらばいいのだろう。プログラミング言語の文法を教えることがプログラミングの楽しさを伝えることになるのか、デバッガのコマンドを教えることがプログラミングの面白さを伝えることになるのか。

コンピュータの仕組をしらなければ、プログラミング言語の文法をしらなければプログラミングはできない。最低限の事は知っている必要がある。その上で何を教えるのか。何を共有するのか。

彼等は生まれたときからコンピュータが身近にあった。物心ついたときにはインターネットがあたりまえであった。ディジタル・ネイティブである。空気のようにネットやコンピュータをあやつる。

彼等にわれわれは何を伝えるのか。どのような言葉をわれわれは持っているのだろう。そんなことを考えた。

U-20 プログラミングコンテストに応募された様々な作品を審査したときに考えた。

プログラムは自己表現だ。自分が何かをしたいと強く思うことによって、ハッカーはなにがしかのものを作る。その強い意思、強い思いがあってこその技術力であり表現力である。

確かに中学生(!)、高校生のプログラミングテクニックは、プロの目から見ればまだまだ未熟なものかもしれない。だけど、何物かを作りたいというパッションは誰にも負けない。そのパッションがわれわれの心を揺振る。

技術は教育できるかもしれなが、パッションは教育できない。それは一人一人が自分で獲得していくしかない。

われわれにできることがあるとしたら、そのようなパッションを持っている若いプログラマを発見し、彼等彼女等が思う存分活躍できる場を提供することぐらいだろう。一緒になって、そのフィールドを作っていくことぐらいだ。

技術はコピーできても、パッションはコピーできない。

そのような、あたりまえな事に気がつかせてくれた若いプログラマ志願者に感謝をしたいと思う。

LL Future

週末LL Futureに行ってきた。朝の10時から夜9時まで11時間の長丁場である。参加するだけでもヘロヘロなのだから裏方の実行委員や発表者の皆様のご苦労は大変なものだろう。感謝。

わたしがこの夏のLLイベントにはじめて参加したのはLL Ring (2006)からで、昨年のLL Sprits(2007)、そして今回のLL Future (2008)というような感じである。

基調講演はPerlのLarry Wallである。Perl 6のお話をするのだけど、言語そのものの拡張機能をビルトインするらしい。うは、Lisp的な。しかし、ふつーの利用者は、言語の文法を拡張したいのだろうか?シンタックスをばりばり変更拡張して、俺様言語を作るというのをふつーの利用者は望んでいるのだろうか。

うーむ。よくわからない。むしろ言語設計者の役割は、様々なプログラミング言語のアイデアを絶妙なバランスで取捨選択して、デフォルトとしてふつーの利用者に提供するのがお仕事なのではないだろうか。

昔のプログラミング言語は会議室で設計された。FORTRANもCOBOLもAdaもLispですら標準化委員会で設計された。LLの場合は、そうではなくて一人あるいは少数のハッカーによってコアが設計された。PythonもPerlもRubyもそうである。

Perlの力はCPANのようなコミュニティが開発した豊富なライブラリにある。言語は、それらの膨大なライブラリによってささえられている。であるとするならば、文法の独自拡張は、そのコミュニティを分断することになるのではないかと思ったりする。つまりXXの機能を利用するためにYYという文法定義が必要で、それが従来のZZとコンフリクトするので素直には利用できない。ライブラリやパッケージでも同様な問題はおきなくはないが、文法は通常一緒なので最悪コピペ的に回避することは不可能ではないが、文法をいじってしまうと、それも簡単ではない。

言語の拡張可能性というのは昔からとりざたされている機能ではあるが、実用的な観点からは大きな?マークである。

動的言語はおおかれすくなかれeval的ななにがしかを持っているので拡張可能性を持っているのだが言語要素そのものを自由に追加、変更できるというのは、バザールモデル的にはあんまりお得ではないような感じがする。

最近は言語仕様についてもバザール的にわいわい開発するモデルが主流になりつつあるので、特にそう思ったりする。

「LLで未来を発明する」パネルディスカッション。参加者はLarry Wall、まつもとゆきひろ、藤田善勝、住井英二郎、ひげぽん。

未来の話はほとんどでてこなくて、かと言って何かびっくりするくらいクレージーな話でもなく凡庸(?)なお話になっていた。問題設定が100年後の未来という事であったので、そんなのわかんねーよというのが普通の感覚なので、10年後の未来とかあるいは6分後の未来とかの方が話が盛り上ったのではないかと思った。

それこそコンピュータアーキテクチャがノイマン型(プログラム内蔵方式のコンピュータ)であるならば、どっかのレベルではメモリという概念が必要になってきて、関数型のOSやらshellを用意したところで、どうしてもC的なレイヤがでてくる。

ふつーの人がプログラミングしないなんていうのは昔から言われているわけで、いまだってふつーの人はプログラミングしない社会である。

そうではなくて今後のコンピュータを作る人がどのようなプログラミングモデルを必要としているのか、ぐらいのことは語ってほしかったぞと強く思ったパネルディスカッションである。

その後、いろいろと興味深いパネルが続くのであるがまじめなセッションよりもコードゴルフとかおなじみのライトニングトークとかの方が楽しめた。

しかし、プログラミング言語のイベントに1000人も集まってしまうなんて異常だ。いったいどーゆー事だ。しかも朝から晩まで11時間も数百人の人達がわいわいがやがや楽しげにやっているなんて、すごいすごい。

日本はじまったな。

11時間にわたる長丁場お疲れさまでした、そしてありがとうございました>参加者の皆さん

WEB+DB PRESS Vol.46

WEB+DB PRESSの人気インタビュー「小飼弾のALPHA GEEKに逢いたい」にインタビューされる側として登場した。詳細は本誌にゆずるとして、その時のお話をいくつか。

6月末の取締役CTO退任のブログをうけて、いろいろな方にインタビューを申しこまれて、弾さんのインタビューもその一つなのであるが、一番最初にじっくり話したのが、このインタビューである。

通常は弾さんのマシンガントークにインタビューイーが答えるという形式になるかと思うのだが、今回は、どちらと言うと、わたしがガンガンしゃべるまくるという感じになった。プログラマとしていろいろ思うところを語ったので、ぜひ読んでほしい。

インタビューはテープ起しで40頁分になって、そのうち4頁を掲載している。さらに場所をうつして居酒屋で40頁分を語りに語った。あーー楽しかった。すっきり。掲載されているのはしゃべった分の10%なので、濃縮還元ジュースみたいな感じになっている。

削りに削っての構成インタビューなので密度は濃い。

弾さん、編集の細谷さん、ありがとうございました。

404 Blog Not Found 予約開始 - WEB+DB PRESS Vol.46
http://blog.livedoor.jp/dankogai/archives/51098820.html

プログラミングキャンプ

この夏、8月13日から17日まで、セキュリティ&プログラミングキャンプ2008というの企画した。わたしも講師の一人として、プログラミングキャンプに参加する。

セキュリティ&プログラミングキャンプ2008 http://www.jipdec.jp/camp/
セキュリティ&プログラミングキャンプ2008/ユメのチカラ http://blog.miraclelinux.com/yume/2008/06/2008-7e81.html

わたしのやりたい事。プログラムの楽しさを少しでも若い世代に伝え、仲間を少しでも増し、プログラマがプログラマとしての専門性をいかし生き生きと豊かにおくれる社会をつくること。

高度ICTリーダー論/shi3mの日記http://d.hatena.ne.jp/shi3z/20080807/1218068383

もっと若い相手、たとえば高校生や大学1,2年生などを対象に、もっと幅広い講師を呼んで講演会を開き、刺激を与えた方が「真のトップノッチ」育成には役立つのではないか。

まさにプログラミングキャンプはそのような明確な意図のもと合宿形式でトップノッチの発掘、養成をめざしている。

それにはどのようなカリキュラム(プログラム)がよいのか、今年は初めてなので文字通り試行錯誤の連続である。

わたしは、デバッグの方法、コードリーディング、プログラミング入門をうけもつが、シラバスを作り、プレゼン資料、実習問題、デモの準備など、正直いってへろへろである。はたしてこのような問題設定でよいのか、はたしてこのような教材でいいのか、そもそも、このカリキュラムでいいのか、そのようなことを自問自答しながら七転八倒し教材を作成した。

まだ実際の講義をしていないので、何とも言えないのだが、講義という学生とのコラボレーションでわたしも多くのことを学ぶだろうし、多くのことを経験するだろう。そしてそのフィードバックは次に生かしていくつもりである。

単にプログラマとしてひいでているだけではなく、コミュニティのリーダとして人々に信頼され、尊敬されるような人材と巡り会いたい。養成とか育成とか、そのような上から目線ではなく、可能性を持つ人々を発掘し、生き生きとその才能を開花させるような環境を作りたい。

そのためにはその中間地点として、彼らがその才能を十二分に発揮できる環境を作るのがわれわれ大人の仕事で、それは具体的には、彼等を雇用できるようなビジネスを創出することが最ももとめられていることである。

Googleに多くの若い才能が結集しているのは、それは我々が十分彼らの才能を生かす仕事場を提供していないからである。日本のタレントを流出させているのは、我々がそのプレイグラウンドを提供していないからである。

その意味で、id:mkusunok の指摘は正しいと思うが、
geek虎の穴をつくろう/雑種路線でいこう http://d.hatena.ne.jp/mkusunok/20080807/ito

恐らく優秀なプログラマーなら日本にも少なからずいる訳で、私塾ではgeekに対してグローバルな視座や搾取されないだけのビジネススキルを獲得できる機会を提供し、geekだけでなく、彼らが活躍できる環境を整えることのできるようなサポーター、具体的には優れたビジネスマネージャやマーケティング、政策立案者も育てる必要がある。手をつけられそうなところから具体的なカタチにしていきたい。

育てるだけではなく、そのような社会環境を作るのが我々の仕事である。今まさに楠さんや清水さんにはそのような役割が求められているのである。

先行評価(Eager Evaluation)勉強法とトラブルシューティング

新人プログラマのよしおかです。どうぞ、よろしくお願いいたします(ぺこり)。という日々を送っている。日々のトラブルシューティングの話なんかをここに記したい。

そもそもAsianux Mobile Midinux 2.5Jというのは、Intel Moblin(http://www.moblin.org)準拠なのでいろいろお作法が違う。

debianのパッケージング方法なんかも一から勉強である。最近はインターネットのおかげで高速道路が整備されているので、必要なマニュアルは全てオンラインで入手できる。debianのドキュメントの充実度は目をみはるものがある。一見遠回りのようでいても、ドキュメントをひととおりざっと眺めてみることは、重要である。何か問題にぶちあたったときにググって断片的な回答を発見するのではなく、まづマニュアルにあたってじっくり仕組から理解をする。すぐに回答にたどりつかないように見えてもそれは自分に対する投資なのであせらない。習熟曲線というのは最初はなだらかで、ある程度いくとぐぐっと立ち上がる。そのぐぐっと立ち上がるところまでは自分に対する投資である。

まわりにいる、debian使いの人のお世話になって、最初の道案内をおねがいし、読むべきドキュメント、マニュアル類をおさえる。これ非常に重要である。必要になるかならないかわからないけどドキュメントをちゃんと読む。Eager Evaluation(先行評価)勉強法である。で、わたしは、その投資のリターンが非常に高いことを経験則として知っている。ドキュメントを読む時間(投資コスト)は低いので、ローリスク、ハイリターンな投資となる。

日記界隈のハッカーは遅延評価勉強法をとっているようである。何か問題にぶつかったら、それについて調べるというスタイルである。こちらの方が、一見レスポンスタイムが短かくお手軽ですぐれているように思えなくもない。しかし、一つのことを極めようと思ったら初期投資をおそれてはいけない。結局はマニュアルなど原典にあたることになる。

まあ、こーゆースタイルは誰かに強制するつもりもないし、強制できるものでもない。遅延評価で場当たり的にやっていても結局いつの日かマニュアルを読むことになって実はああ何か遠回りをしたなあと気がつく。マニュアルをはじから読むなんていうことは、自分にはなかなかモチベーションをキープするのが難しい。どうしてもつまみぐいになってしまう。という声も聞くが、人それぞれなので、もちろん強制はしない。

わたしなんかは、何度も言っているようにIntel Software Developer's Manualを読むのが趣味という芸風なので特殊例だとは思うが。

で、トラブルシューティングのお話なのであるが、最初はその問題について初心者で動作原理を十分理解していないから、現象を見ただけでは、なんでそのような現象が発生するかチンプンカンプンの状態からはじまる。これが、その問題についてのいろいろ経験して理解がすすんでいけば、現象を見ただけで、ある程度原因がわかっちゃったりするのであるが、そこにいくまでは、いろいろな試行錯誤の連続になる。プログラマはその経験のつみかさねで自分の適応可能領域をどんどん広げていくことになる。

初心者の場合、毎回毎回初めてみる現象に遭遇し、そのたびに、わけがわからなくて、どこからあたりをつけていいかわからないので、試行錯誤をくりかえす。初めての問題なので、そもそも簡単な問題なのか難しい問題なのかすらわからない。ひょっとしたらとんでもない超難問にぶつかってしまったのではないだろうかとか不安になったりもする。解決するには何日も何日もかかるような問題なのではなんて思ったりもする。

第一歩は問題を正しく理解することである。何がおこっているか正しく理解することである。安易な解決策に飛びつこうとしない。先入観をすててありのままに現象を観測する。それが第一歩である。

先日遭遇した問題はこんな問題であった。

ソースコード管理システム(git)からソース一式を持ってきて(git-clone)してビルドする。問題なくビルドできる。いろいろ変更して再度ビルドすると、ビルドできない。Makefile他ビルドシステムそれ自身は一切変更していないので何がなんだかわからない。こーゆー状況に遭遇した。

問題を切りわけるために、原点にもどってみる。git-cloneしてビルドする。問題なくビルドできる。いろいろ変更したのが問題かもしれないので、何も変更しないでビルドしてみる。ここが最初のチェックポイントだ。ビルドが失敗する。ここからトラブルシューティングの旅がはじまるのである。

何がなんだかわからない事は、その通りなのである。解決できるかできないかも、その時点では見通しすらたっていない。どういう戦略でトラブルシューティングをしていくか。

ビルドのログをじっくりながめてみる。エラーがないのか、あるのか。ビルドができないのは結果であって何でビルドができないのかを理解することが必要になる。そうすると、パッチをあてることを失敗している。なぜなんだろうか?debianパッケージの場合オリジナルのソースに独自パッチをあて、その後ビルドをするというプロセスになる。

なぜパッチをあてることを失敗しているのだろうか。

ビルドする前に前回あてたパッチをとりのぞいて真っ新な状態にする。そして、今回ビルドするにあたって再度パッチをあてビルドする。ログを見てみると、前回あてたパッチをとりのぞくことに失敗している。そのために同じファイルに2度目のパッチをあてることをこころみ結果としてそのビルドに失敗している。

なぜパッチをとりのぞくことに失敗しているのだろうか。

問題のパッチのコードを眺めてみることにする。失敗したパッチには.rejというファイルができているので、それもあわせて読む。

パッチのコンフリクトしている部分がrejファイルには記述されているので、それを見た。

そうすると、ある行についてパッチがあたらない。なぜか。

パッチファイルにはTABで書かれていたが、それが空白に変換されて適用されていた。そのためパッチをとりのぞく時に、とりのぞけなかった。

さて原因がわかった。現象を分析し正しく理解すれば原因がわかる。原因がわかれば解決策を作るのは簡単である。パッチファイルのTABを空白にした。再度ビルドしてみてビルドできることを確認した。

理解してみれば他愛のないことである。しかし現象をみた段階で、何がなんだかわからなかったことも事実である。問題を一歩一歩理解していくといくプロセスがトラブルシューティングの王道である。

その道標としてマニュアルをきちんと理解しておくことが重要である。



ハッカーと遅延評価勉強法/Slow Dance
http://d.hatena.ne.jp/LukeSilvia/20080402/1207149044

私の言語遅延学習法 - 三つのルール+1/404 Blog Not Found
http://blog.livedoor.jp/dankogai/archives/50999338.html

遅延評価的勉強法/IT戦記
http://d.hatena.ne.jp/amachang/20080204/1202104260

初めてのRuby

「初めてのRuby」は、他のプログラミング言語の経験があるプログラマ向けのRuby入門書である。プログラミングの入門書ではない。この明確なターゲット読者の設定がこの本の特長であり成功の要因である。

すくなくともわたしにとって、他言語(C言語)でのプログラミング経験があるものにとって、これほどまでにコンパクトかつ明解にRubyの真髄を語っている本書ほど、ありがたいものはない。

わたしはかねてからプログラミング言語の文法書は50ページ以内であるべきだと思っている。プログラミング言語の構文はシンプルであればあるほどいい。道具はシンプルな方が応用が効く。

それはともかく、プログラミング経験者にとって、第二、第三のプログラミング言語を学習するということは、計算機の入門、例えば計算機はどう動くかとか、メインメモリ、CPU、外部記憶の機能はどうだという事を学んだり、プログラミングの入門、アルゴリズムとか、計算量、データ構造、例えば、表、ハッシュ、N分木等々について学ぶのではなくて、そのプログラミング言語の文法や意味論を、そしてそのプログラミング言語の背景にあるプラグマティズムを学ぶことである。

つまり第二第三のプログラミング言語を学ぶということは、その言語が持つ哲学、思想、あるいは開発コミュニティのお作法までも含めた何がしかを学ぶことである。例えば、Perlという奇妙なプログラミング言語を学ぶということは、CPANというPerlハッカー達がよってたかって作ったライブラリのレポジトリについての何がしかを学ぶということで、そのような事を含めて理解してはじめてPerlという言語を学んだということになる。

なぜわざわざそのようなプラグマティズムを貴重な時間コストをかけてまでプログラマが学ぼうとするのか。そこにはそのコミュニティがはぐくんでいるベストプラクティスがあって、それは言語の壁をこえた普遍性があり、それを学ぶことの意義というのは強調されても強調されすぎることはないと考えている。

「初めてのRuby」はRubyを愛してやまないYuguiさんが、Ruby初学者に向けてRubyを学ぶ道標をあたえている。

他言語を使いこなすプログラマに向けて極めてコンパクトかつ明瞭にRubyのプラグマティズムを紹介している。言語の文法書にはでてこないRubyの考えかたを紹介している。

なぜRubyではforで繰り替えしを書かないのか。C言語族に属するわたしにとってYuguiさんの説明は明瞭でかつ説得力がある。なるほどなるほど。

先日、tokyo-emacsというemacs利用者(初心者からハッカーまで)の集りで、いろいろなelispのコードをながめたのだが、そのコードのスタイルが、なにかCを感じさせるものが多く、皆で「これってCだよなあ」というような事を言っていた。関数型と呼ばれる言語(elisp)ですらCの影響を受けたプログラマが書けばCの匂いのするプログラムになってしまうのである。

プログラミング言語がノイマン型コンピュータを抽象化し動作可能なものとしたのなら、そのプログラミングパラダイムはおおかれすくなかれ似たようなものになる。変数という概念があり、メモリはアドレスというもので識別され、そこには状態を保持するので、代入という概念を持つ。手続型としてくくれるものは、ほとんど似たようなものだと言える。このプログラミングパラダイムの中で様々な文法的な選択肢を絶妙なバランスで取捨選択したのがRubyであり、その取捨選択の思想をわかりやすく説明しているのが、本書である。

プログラミング経験者が第二、第三のプログラミング言語を学ぶ意義はなにか。プログラミング言語の瑣末な文法上の差異を学ぶことが重要なわけではない。プログラミング入門的な知識を得るために行なうのではなくて、言語設計の思想、ライブラリや、それを作りあげている開発者の思い、考え、ひいてはそのプログラミング哲学について学ぶというところにある。その言語コミュニティが持つ暗黙の哲学、価値観を学ぶプロセスにある。

しかしながら、そのような暗黙の哲学、価値観は究極にはそのプログラミングコミュニティに属し当事者にならないと容易には獲得できない。

本書は、そのコミュニティの入口まで初学者を連れてきてくれる。

Ruby初心者も中級者もばりばりのRubyハッカーも本書から得られるものは大きい。初心者にとっては、Ruby言語のみならずその思想にふれられるところ、中級者にとっては、そのRubyらしさという必ずしも明確になっていなかったものに対する指針がえられるところ、ばりばりのRubyハッカーにとっては、今まで空気のように感じていたRubyらしさというものを明示的に表現するというのはどのような事かということを整理、理解するつてとして本書の意義は大きい。

Rubyコミュニティの豊かな土壌からRubyKaigi(本当に素晴しい会議だ)があり、本書のような良書が生れ、多くのrubyistを拡大再生産している。持続可能なコミュニティはその文化を明示的に外に示し新人をリクルートする。素晴しいことである。

本書はRubyコミュニティの豊かさの象徴であると言っても過言ではないと思う。皆様にお勧めする。

-------------------------------
読んでいて気がついた誤殖など。
p53
誤:a >> 1  #=> 0b100
正:a >> 1  #=> 0b110
誤:a << -1 #=> 0b100
正:a << -1 #=> 0b110

p71
誤:p story[8, 7]     #=> "Grundy"
正:p story[8, 7]     #=> "Grundy,"
誤:p story[8...15]   #=> "Grundy"
正:p story[8...15]   #=> "Grundy,"

-------------------------------
索引について。

宇宙船演算子(p52)という見出しはあるが、"<=>"での見出しはない。ところがp36で<=>が初出するが何の解説もないので読者はp52を読むまで理解できない。索引で<=>の見出しがあれば、とりあえづそれを引いて疑問は解決する。

後方参照について

後に説明する項目については、多くの場合、明確にどこどこで説明すると明示してあるので安心して読みすすめる。下記は、いくつかの例外。

p112
def some_method(param = nil)
この構文(デフォルト値をあたえる)についていきなり解説なしで登場し、とまどった。

-------------------------------
p124
本章で扱っていないこと
イテレータとでているが、p119 6.3.6 イテレータを解説しているのではと思う。

p130
階乗の定義で、わたしなら再帰で書くなあと思った。
def fact(n); if n==0 then 1 else n*fact(n-1) end end

vi はじめに
File.chmodとFile#chmodの違いというのが結局どこらへんにあるのか良くわからなかった。

-------------------------------
本書を越える範囲のことについて

続編があるとしたら(勝手に期待するところであるが)、以下についてRuby風のお作法をぜひ読みたい。

テストの仕方
デバッグの仕方
性能のチューニング方法

-------------------------------
『初めてのRuby』サポートページ
http://yugui.jp/wiki/hiki.cgi?LearningRuby
『初めてのRuby』正誤表
http://yugui.jp/wiki/LearningRuby-Errata

プログラマ一年生のパッチと大物ハッカーのコード

取締役退任。生涯一プログラマ宣言。」には大変な反響をいただいた。ここに記して御礼の気持ちとさせて頂く。トラックバック、ブックマークコメントなど可能な限り読んだ。過分のおほめ、励ましの言葉にあずかり、大変光栄に思う一方で厳しいお言葉も頂戴し皆様のご期待にそうよう一層精進していきたいと思った。

さて、プログラマ一年生である。最近では、MID (Mobile Internet Device)の開発にいそしんでいる。CPUもIntel Centrino Atomプロセッサだ。

ソフィアシステムズ Peartree用OS Asianux Mobile Midinux 2.5Jである。
http://www.sophia-systems.co.jp/ice/intel/Atom/PEARTREE/

インストーラを作っているのだが、先日ブートローダ(syslinux/extlinux)のバグに遭遇しそれを直すパッチを作成した。メーリングリストに報告したのが、7/2 18:35:14 PDT(米国西海岸夏時間)である。それに対する返事が、同日19:57:02 PDT(米国西海岸夏時間)、一時間ちょっとで、さっそく取り込んでくれた。その返事も素早いが、それだけではなく、リファクタリング(コードの改良)もしてくれた。

So it does (although the *real* problem is the lack of the stat and
device number comparison.)  I just applied a (slightly different) patch
to this and pushed it out as 3.71-pre3; could you try it out?

よしおかの超訳:バグだね(本当の問題はstatと装置番号の比較がなかった事だけど)。この問題に対するパッチ(ちょっと変更したコード)を適用し、それを3.71-pre3にいれておいた。試してみてくれる?

バグのあったコードは下記の部分である。細かい理解は必要ない。単にパターンマッチをして、上のif文と下のif文が対称じゃないことがわかればいい。

  if ( (mtab = setmntent("/proc/mounts", "r")) ) {
    while ( (mnt = getmntent(mtab)) ) {
      if ( (!strcmp(mnt->mnt_type, "ext2") ||
            !strcmp(mnt->mnt_type, "ext3")) &&
           !stat(mnt->mnt_fsname, &dst) &&
           dst.st_rdev == st.st_dev ) {
        devname = mnt->mnt_fsname;
        break;
      }
    }
  }

  if ( !devname ) {
    /* Didn't find it in /proc/mounts, try /etc/mtab */
    if ( (mtab = setmntent("/etc/mtab", "r")) ) {
      while ( (mnt = getmntent(mtab)) ) {
        devname = mnt->mnt_fsname;
        break;
      }
    }
  }

マウントされているファイルシステムのうち、ext2/ext3ファイルシステムを検索しているのであるが、上の部分は/proc/mountsで検索し、それがみつからなければ/etc/mtabで検索している。コードをじっくり眺めてみれば、下の部分のwhile(){...}で

      if ( (!strcmp(mnt->mnt_type, "ext2") ||
            !strcmp(mnt->mnt_type, "ext3")) &&
           !stat(mnt->mnt_fsname, &dst) &&
           dst.st_rdev == st.st_dev ) {

という比較がすっぽり抜けおちている。まあ、わかってしまえばトリビアなバグなのであるが現象としては謎であった。

なので、さっそくquick and dirty hackで下記のパッチを先のメーリングリストに投げたのである。

--- extlinux.c.orig    2007-02-10 20:47:08.000000000 +0000
+++ extlinux.c    2008-07-02 15:20:20.000000000 +0000
@@ -708,8 +708,13 @@
     /* Didn't find it in /proc/mounts, try /etc/mtab */
     if ( (mtab = setmntent("/etc/mtab", "r")) ) {
       while ( (mnt = getmntent(mtab)) ) {
-    devname = mnt->mnt_fsname;
-    break;
+        if ( (!strcmp(mnt->mnt_type, "ext2") ||
+              !strcmp(mnt->mnt_type, "ext3")) &&
+             !stat(mnt->mnt_fsname, &dst) &&
+             dst.st_rdev == st.st_dev ) {
+       devname = mnt->mnt_fsname;
+      break;
+    }
       }
     }
   }

7行追加のパッチである。まあ、素人目にはこれで一件落着である。

個人的には、ソフトウェア変更における、修正量最小化の法則、修正個所局所化の法則にのっとっているので、美しくはないかもいれないが、quick and dirty hackとしては合格点かと思った。

メンテナのちょっと変更したパッチというのが下記だ。

diff --git a/extlinux/main.c b/extlinux/main.c
index 0edce5a..819f74b 100644 (file)
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -801,6 +801,32 @@ static int validate_device(const char *path, int devfd)
   return (pst.st_dev == dst.st_rdev) ? 0 : -1;
}

+#ifndef __KLIBC__
+static const char *find_device(const char *mtab_file, dev_t dev)
+{
+  struct mntent *mnt;
+  struct stat dst;
+  FILE *mtab;
+  const char *devname = NULL;
+
+  mtab = setmntent(mtab_file, "r");
+  if (!mtab)
+    return NULL;
+
+  while ( (mnt = getmntent(mtab)) ) {
+    if ( (!strcmp(mnt->mnt_type, "ext2") ||
+         !strcmp(mnt->mnt_type, "ext3")) &&
+        !stat(mnt->mnt_fsname, &dst) && dst.st_rdev == dev ) {
+      devname = strdup(mnt->mnt_fsname);
+      break;
+    }
+  }
+  endmntent(mtab);
+
+  return devname;
+}
+#endif
+
int
install_loader(const char *path, int update_only)
{
@@ -808,11 +834,6 @@ install_loader(const char *path, int update_only)
   int devfd, rv;
   const char *devname = NULL;
   struct statfs sfs;
-#ifndef __KLIBC__
-  struct mntent *mnt = NULL;
-  struct stat dst;
-  FILE *mtab;
-#endif

   if ( stat(path, &st) || !S_ISDIR(st.st_mode) ) {
     fprintf(stderr, "%s: Not a directory: %s\n", program, path);
@@ -848,35 +869,17 @@ install_loader(const char *path, int update_only)

#else

-  if ( (mtab = setmntent("/proc/mounts", "r")) ) {
-    while ( (mnt = getmntent(mtab)) ) {
-      if ( (!strcmp(mnt->mnt_type, "ext2") ||
-           !strcmp(mnt->mnt_type, "ext3")) &&
-          !stat(mnt->mnt_fsname, &dst) &&
-          dst.st_rdev == st.st_dev ) {
-       devname = mnt->mnt_fsname;
-       break;
-      }
-    }
-  }
-
-  if ( !devname ) {
+  devname = find_device("/proc/mounts", st.st_dev);
+  if (!devname) {
     /* Didn't find it in /proc/mounts, try /etc/mtab */
-    if ( (mtab = setmntent("/etc/mtab", "r")) ) {
-      while ( (mnt = getmntent(mtab)) ) {
-       devname = mnt->mnt_fsname;
-       break;
-      }
-    }
+    devname = find_device("/etc/mtab", st.st_dev);
   }
-
-  if ( !devname ) {
+  if (!devname) {
     fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
     return 1;
   }

   fprintf(stderr, "%s is device %s\n", path, devname);
-
#endif

   if ( (devfd = open(devname, O_RDWR|O_SYNC)) < 0 ) {

ちょっとどころの騒ぎではない。全面改訂。随分コード量が増えている。

元のコードでは、if文でext2/ext3の比較をくりかえしていたのを、ばっさりカットして、find_device()という関数にまとめた。

そのおかげで、下記のように本体はすっきりした。

  devname = find_device("/proc/mounts", st.st_dev);
  if (!devname) {
    /* Didn't find it in /proc/mounts, try /etc/mtab */
    devname = find_device("/etc/mtab", st.st_dev);
  }

繰り返しをまとめるという基本中の基本である。ext2/ext3への比較などはfind_device()という新規に作った関数に閉じこめている。すっきりリファクタリングである。

syslinux一年生のコードをリファクタリングまでしてとりこんでくれたのである。

わたしは、著者のH. Peter Anvin (超大物カーネルハッカー)に会ったことも話したこともない。彼は、見ず知らずのどこの馬の骨ともわからない人間のパッチを軽やかに咀嚼して取り込んだのである。

ここまで一時間ちょっと。

オープンソースそしてバザールモデルというのはとてつもないソフトウェア開発方法論である。

まだまだ学ぶ機会に満ちている。素晴しいではないか。愉快ではないか。

gitによるコード。http://git.kernel.org/?p=boot/syslinux/syslinux.git;a=blobdiff;f=extlinux/main.c;h=819f74b5308bac7540fcdb580f94f93cde28d82e;hp=0edce5a597b65dfeb04764aa84582ce1e18dcfd7;hb=537164d509a4227416f6ac5b44c0030d6c79cb41;hpb=2b7251b3905e58ef5c34bb4b009ae537eb1b9333

メーリングリストでのやりとり。http://syslinux.zytor.com/archives/2008-July/010245.html
http://syslinux.zytor.com/archives/2008-July/010247.html

Emacs勉強会 - tokyo-emacs

Emacs勉強会に参加した。なんやかんやで30人を越える参加登録である。

自分は随分昔からEmacsを利用しているのだが、全然使いこなしている感じがしない。最近、Emacsを勉強しなおそうと思っていたので、早速参加することにした。

http://wiki.livedoor.jp/harg/d/FrontPage

Emacsの基本を勉強しなおそう市民連合(笑)の代表として一言挨拶をした。今回は同市民連合の決起集会(嘘)なので、大いにアジったのであるが、みんなでEmacsの基本を勉強しなおしたいと思った。

早水さんのEmacs Lisp講座は初心者に向けての優しい講座であった。

メモをはりつけておくが、これだけじゃあ、何が何だかわからないなあ。

Emacs Lispは怖くない
括弧は空気
EmacsのことはEmacsに聞け
  ヘルプの使い方
Lispは単純
リストが全て
  ドット対
関数名と変数名の名前空間は別

実践編
.emacsを眺める
  (server-start)
  ansi-term
入門書
  もうひとつのScheme入門
  独習Scheme三週間
  プログラミングGauche
---------------------

files.el

K1LoW
  moz.el
  pabbrev.el
  dabbrev.el

  drill-instructor.el

yuki_neko_nyan
  yasnippet

jj1bdx
  face
  color-theme

IMAKADO
  anything
  補完が凄い

Misho
  Emacs for Latex

naoya_t

.emacs
  IMAKADO

Emacsについて語り合う人が自分のまわりにいない人達にとってtokyo-emacsはとてもいいところだ。大変勉強になった。懇親会で、メモ用紙にマクロの解説をしている早水さんや、それを囲んでわいわいがやがや議論している。楽しかった。またやりたいと思った。

早水さん、参加の皆さんお疲れさまでした。ありがとうございました。

追記:資料を公開した。tokyo-emacs-080628.pdfをダウンロード

Googleを支える技術

Googleという不思議なサービスを提供するそのコンピュータシステムの内側に公開された資料だけを利用して迫った良書である。

Internetの向う側のGoogleというシステムについて、われわれは日々利用しているにもかかわらず殆ど何も知らない。少なくともわたしは技術的な側面について殆ど何も知らない。神秘的な、都市伝説的なもの、例えば、20%ルールとか、そんなことぐらいしか寡聞にして知らない。

本書はGoogleの分散ストレージ(GFS/BigTable/Chubby)、分散データ処理(MapReduce/Sawzall)、運用コスト、開発体制などについて公開された論文などを引きながら解説している。

コンピュータシステムというのは極論すれば、いかに速くするか、いかに安くするかという2軸で発展してきたようなものだから、Googleという巨大システムをどのようにエンジニアリングするかという観点からもこの速くすること、安くすることの実務的な教訓というのは大変興味深い。

RDBMS(関係データベース管理システム)というソフトウェアは多量なデータをいかに格納し、検索するかという観点から開発発展してきたものだが、Googleは、それを地球規模の巨大システムに実装したものと言える。

わたしが本書で最も興味を引かれたものは、分散ストレージや分散データ処理の話ではなく、運用コストの章であった。そしてわたしはこの章が本書の最もユニークなところでしかも最も重要なところかと思う。

フツーのプログラマが計算コストと言うときアルゴリズムの計算量の事を指す場合がおおいと思うが、計算にいくらかかっているかという観点から議論するということは、あまりないと思う。

ムーアの法則のすごいところは、18ヶ月で半導体の集積度は倍になる、すなわちコストが半分になると言い切って、フツーのプログラマにそれを意識させたことである。コストが半分になるのだから、それを意識したプログラミング、すなわちメモリがどんどん増えていく、あるいはメモリがどんどん安くなることを前提としたプログラミングが正しいこととされた。そのようなパラダイムでソフトウェアサイエンスは進化していったようなものである。

コンピュータの高速化の流れも、ムーアの法則にのとって、クロックを高速化する事によって、命令セットアーキテクチャを変更する事なく、様々な実装上の工夫によって、高速化していった。ソフトウェアにとっては、ほとんど何もしないで高速化していったわけであるから楽な時代であったと言える。

ところがクロックをどんどん上げて行くことによって、電力消費量もそれに比例してどんどん増加していって、発熱の問題などが顕在化してきた。そこで、クロックを上げることによる高速化ではなく、マルチコア化等による高速化などが必要になってきた。同様に消費電力あたりの性能を上げるための様々な工夫が必要になってきた(←今ここ)

計算機の消費電力は電気代というお金になる。Googleが利用している計算機は、2000ドル〜3000ドル程度の普通のIAマシンのようであるが、その消費電力が増加の一途をたどり、年間運用コストがそれを上まわるかどうかという事である。

電気代だけではなくてデータセンターの建設費、効率的な電力消費設計などがコスト負担にどんどかかってくる。プログラマは昔はムーアの法則をメモリ空間の増大などと一次元的に考えていればよかったが、今後はメモリ空間はまあそこそこあるとして、消費電力をどう効率的に利用するか、省電力プログラミングが求められてきているような気がする。

消費電力を半分にできれば運用コスト(電気代)は半分になるし、ばかでかいデータセンターの建設も先送りにできる。サーバー機の重要なコストファクタが電気代というのが常識になってくるとプログラマのプログラミングパラダイムも随分変化してくる。

速くするだけではなく、電気代を節約する速さが求められるのである。

モバイル機器なんかは電池の持ちが商品価値そのものを決めたりするので、もっと重要である。バッテリーのサイズが半分になればデザインの自由度も随分増すだろうし、なにより軽くできるし、ハードウェアコストも安くできる。プログラムが物理的なデザインに影響を与えるのである。

プログラマがもっとコストなどの側面に意識を持つべきだと思うのだが、その意味で本書の第5章などは大変興味深くかつ意義深いと思う。

省電力プログラミングというパラダイムをそろそろ真面目に考えないといけない時期である。

Googleを支える技術 ……巨大システムの内側の世界
サポートページ
http://gihyo.jp/book/2008/978-4-7741-3432-1/support

Happy Hacking Diary(著者:西田圭介氏の日記)
http://d.hatena.ne.jp/nishidakeisuke/20080428

Papers Written by Googlers
http://research.google.com/pubs/papers.html

未来のいつか/hyoshiokの日記(電気代)
http://d.hatena.ne.jp/hyoshiok/searchdiary?word=%c5%c5%b5%a4%c2%e5

未来のいつか/hyoshiokの日記(省電力)
http://d.hatena.ne.jp/hyoshiok/searchdiary?word=%be%ca%c5%c5%ce%cf


セキュリティ&プログラミングキャンプ2008

ソフトウェアは人が作る。人がすべてだ。

若い人が魅力を感じなければその産業は衰退する。若い人にとってソフトウェア産業が魅力的なものだということを我々はもっと伝えないといけない。ビジョンを示し、その魅力を伝える努力をしないといけない。

一方で少しでも興味を持ってくれた人にソフトウェアを作ることの楽しさおもしろさ難しさを伝えることも必要だ。

人材育成だなんだと大げさにとらえるのではなく一緒にプログラミングの楽しさを経験したい。初心に戻ってプログラムを初めて作ったころの感動を体験したい。

22歳以下の皆さん。

あなたたちのために、そのような合宿を企画した。

セキュリティ&プログラミングキャンプ2008 http://www.jipdec.jp/camp/

『若年層のセキュリティ意識の向上と優秀なセキュリティ人材の早期発掘・育成』という目的で2004年からやっているセキュリティキャンプがきっかけだ。合宿形式で行うセキュリティ人材育成のイベントのプログラミング版だ。

U-20プログラミングコンテストで若い人たち(中学、高校生)のプログラムを読む機会があるが、やはり回りに相談する人がいないのか、プログラムの基礎的なことなどの理解が足りていない。例えばif文を延々と重ねて処理をするとか、いたるところに数字(定数)が書かれていたりとか、そーゆー力ずくのコードを目の当たりにみて、コードを書くにしても基礎的なイロハの伝授が必要であるということを痛感していた。

コードの書き方だけではなく、デバッグの仕方とか、gitをはじめとする分散バージョン管理システムあるいはOSSを前提としたコラボレーションのちょっとしたコツとか、必ずしも明文化されていないがとっても重要なことについて学ぶきっかけを作りたかった。

もちろん、その先にあるプログラムを作ることの楽しさ、達成感、充実感なども共有したい。

わたしのミッションステートメントをここに記す。プログラミングキャンプ宣言だ。

    *  オープンソースソフトウェアを開発する元気のいい若手プログラマを輩出したい。
    * 単にプログラミングテクニックが凄いというだけではなく、コミュニティのリーダとして、人々の話をよく聞き(コミュニケーション能力)、信頼されるようなプログラマを輩出したい。
    * 彼等が今後の核になってさらに新しい人材を発見発掘するというエコシステムを作りたい。
    * 彼等が新しい価値を創造し、世界から尊敬されるような人々になって、日本という地域が、そのような人々が集まるような場所にしたい。

10年で200人。

これが、わたしのユメだ。

そのような若者を雇用するビジネスを作るのが大人の役目である。

多くの若者の応募を待つ。

git入門

社内勉強会でgit入門をやった。(参考資料をダウンロード )。

最近の開発でgitを使っているので、そのファーストインプレッションみたいなものである。マニュアルについては、日本語訳もあるので参考にしてほしい。

分散コード管理システムということで従来の集中コード管理システムとその使い勝手が相当違うように感じる。

基本的な使い方は、リモートにあるリポジトリをローカルにコピーして、そのコマンドをgit cloneというのだが、そのレポジトリに対してチェックアウト、チェックインを繰り返し最後にリモートのリポジトリにコミットするという感じである。

基本的には、集中型とそう違わないのであるが、精神的には随分違うという感じがする。

まず、変更はローカルのリポジトリにずんずん行なうという点。ローカルのレポジトリにずんずん行なうので、その時点でリモートにアクセスできなくてもいい。ノートパソコンにレポジトリを用意して、電車の中や街中でちょっとした変更をして、それをノートパソコンのローカルなレポジトリにずんずんコミットする、なんていう使い方ができる。

そこまでモバイルな使い方ではなくても、通常だったら、次のような感じかと思う。まづプロジェクト用リポジトリを準備して、各自は自分の開発マシンにリポジトリを置く。そして、個々の担当は自分のリポジトリにどんどんコミットする。テストが終った変更(コミット)に関しては自分のリポジトリからプロジェクトのリポジトリへpushする。

そんな感じである。

まだ、ありがたみが伝わらない?うーむ、説明が下手ですいません(ぺこり)

基本的には変更はブランチで行なう。ブランチが原則、前提。Linux Kernelの開発のように多数のプログラマによって独立に開発がおこなわれているというプロジェクトの場合、このブランチが原則というのは大変理にかなっているように思う。

また管理の対象もコミット単位(ファイル単位というよりも)というのも理にかなっている。

また各オブジェクトはSHA1のハッシュ値(16進40桁)で管理されているので、同じSHA1値であれば同じオブジェクトであるということがグローバルで担保されている。

ということは、例えばgitの開発ヒストリのログなんかも、本家をコピーしたリポジトリ全てで同一性が保証されている。Linusが最初にコミットしたオブジェクトは、世界中のどんなコピーでもe83c5163316f89bfbde7d9ab23ca2e25604af290という事が保証されている。通常は40桁のハッシュ値の最初の数桁を利用すれば参照できるので、例えば、

$ git-log e83c5163

とすればLinusが開発したgitの最初のコミットのログを見ることができる。すごいすごい。

$ git clone git://git.kernel.org/pub/scm/git/git.git

でソースも読めるのでいろいろ楽しめる。gitを利用したプロジェクトのヒストリの眺め方などという時間軸にそった楽しみ方もあるのではないかと妄想した次第である。

Rebase Early, Rebase Oftenという話をしたかったのであるが、紙面がつきたのでいつの日にか。

カーネルにおけるリグレッションの特定/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/10/post_d748.html

Git ユーザマニュアル (バージョン 1.5.3 以降用)
http://www8.atwiki.jp/git_jp/pub/Documentation.ja/user-manual.html

勉強をしなおす

いくつになっても勉強だ。昔とった杵柄。錆びたナイフを研ぐ。

という事で日頃なにげなく使っているEmacsのマニュアルを再読する事にした。会社の机の上にO'reillyの Learning GNU Emacs、Writing GNU Emacs Extensionsそして竹内監訳のGNU Emacsマニュアルがある。竹内監訳のGNU Emacsマニュアルの初版は1988年2月である。20年前である。いくら何でも日進月歩、秒進分歩のIT業界の時間感覚でなくても古すぎるだろうと思わなくもないが、機能がテンコ盛のEmacsにはversion 18ころの古典的な、基本機能をおさらいするには、サイズ的にも丁度いい感じである。

正直に告白すると、Emacsを日々使っているが自分で拡張を書いたりelispで手間仕事をちゃかちゃか片付けるという事はほとんどしていない。何かのきっかけでもないとマニュアルを読みかえすということもほとんどしない。ぐぐればどーにかなる。だけど、一見時間がかかると思えても基本にたちかえってみることは悪い事ではない。

今使っているEmacsは22.1.1だ。Ubuntu 8.04にデフォルトでついてくるやつである。10数年Emacsを使っているけど全然使いこなしている感じがしない。ちゃんと基本にもどって勉強しなおしてみよう。きっと新しい地平線が見てくるに違いない。

セキュリティ・キャンプ・キャラバンwithプログラミング沖縄

080126_13140001 若年層の情報セキュリティ意識の向上と優れたセキュリティ人材の発掘と育成を目的として、毎年開催しているセキュリティキャンプの成果とその蓄積されたノウハウを広く一般の方々にも公開すること、これからキャンプに参加していただきたい若い方々に正しい情報セキュリティの理解と意識の向上を図ってもらうこと、また、オープンソースソフトウェア(OSS)を中心としてプログラミングやアプリケーション開発について興味を持っていただくことを目的として、「セキュリティキャンプ・キャラバン with プログラミング -沖縄-」を開催します。
http://www.jipdec.or.jp/camp/caravan/caravan_okinawa.html


080126_13140002

ということで沖縄にきている。わたしは大阪、筑波、そして沖縄と三ヶ所キャラバンした。

来週は横浜で開催するので東京近郊の皆様はぜひ参加してほしい。
http://www.jipdec.or.jp/camp/caravan/caravan_yokohama.html

セキュリティキャンプ・キャラバンwith プログラミング 2007
集まれ“若い力”
http://www.jipdec.or.jp/camp/caravan/caravan.html

未踏オフ会

古川享PM(プログラム・マネージャ)の未踏ソフトウェア創造事業(長いな、以下未踏と称す)のオフ会に参加した。

古川さんの事は30年くらい前から、わたしは一方的に名前を存じあげていたのだけど、直接名刺交換をするのは初めてである。それはともかく、1970年代のマイコン世代の懐しいお話満載で、ASCII出版のころとか、マイクロソフト株式会社設立のころのエピソードなど興味がつきなかった。

最初にパワーポイントのちょっとしたTipsを延々話していたのは笑った。YouTubeのCTOは、パワーポイントも上手に使えないとか、どーでもいい(失礼)エピソードが面白い。

古川亨略歴ということで、ASCII時代の話から入った。

79年11月のASCIIにパーソナルコンピュータはメディアになるというコラムを書いてそれが自分のビジネス、生き方の指針になった。その後、ASCIIでInformixの日本語化、BSD Unixの日本語化、これはのちにSONY NewsとかUltrixで使われた。86年マイクロソフト日本法人設立。

当時Apple/Sun Micorsystems/Microsoftの三社から社長のオファーがあったが、マイクロソフトの社長になったのは皆さんご存知のとおり。人事権に関しては誰がなんと言おうとも、米国本社ではなく自分が持つというのを条件に社長になった。

人とぶつかった時に、相手の正しさを認めること、自分の非を認めること、それが重要で、Bill Gatesは人の話を聞く(リスニングスキル)がすばらしい。そしてそれを自分の力にする。

ソフトウェア事業は核となるところ、目標となるところを持っていないといけない。YouTubeは自分の母親にも使ってもらいたかった。そーゆーしっかりとした軸が必要。

天才プログラマを生かすプロダクションが必要。宣伝をして、マーケティングをして、営業をして、箱をつくって、権利関係を確認して、商標をとって、というような様々な事をやってくれる、アーティストに対するプロダクション事務所みたいなものが必要で、プログラマはその重要性を理解する必要がある。いいマネージャーに出逢う必要がある。

というようなお話をプレゼン資料2枚で延々1時間以上独演会をしている。古川節炸裂である。これはわたしの文章では伝えられない。ライブの醍醐味である。

その後、ユルユルの形でパネルディスカッションがはじまって、古川さんの熱気で竹内さんたじたじである。

いろいろ興味深いエピソードを聞きながら、結局のところ、日本という地域に圧倒的に足りないのは、やはり、ソフトウェア製品を作ってそれをビジネスにした経験者であり、その経験者を拡大再生産する土壌であると思った。古川さんのような「経験豊かなおじさん」が圧倒的に足りない。

足りないならば、もっともっと「古川さん」を利用させてもらおう。古川さん的な人達と交流を持ち、すこしずつ成功体験を拡大再生産していく。そのきっかけの一つとして未踏というプラットフォームを利用する。

優れたプログラマは沢山いる。彼ら彼女らの活躍するフィールドを作るために、ビジネスとして成立させるためのイロハを知っている古川さんのようなベテランをひっぱりだして、プログラマと同じ坩堝につっこんで、核融合を発生させる。

そんな期待感があった未踏オフ会であった。


古川 亨 ブログ
未踏ソフトウェア創造事業のオフ会に参加、その1
http://furukawablog.spaces.live.com/blog/cns!156823E649BD3714!8461.entry

Exciting BEAT「未踏ソフトウエア創造事業オフ会 & Venture BEAT Project」
http://v.japan.cnet.com/beatproject/blog/story/0,2000071498,000241c-0000021424o,00.htm

nobilog2
未踏ソフト第1回オフ会に行ってきました!
http://nobi.cocolog-nifty.com/nobilog2/2007/12/post_5ac0.html

Drift Diary12
未踏オフ会に参加してきました。
http://blog.drikin.com/article/73528036.html

nishimotzの日記
未踏オフ会
http://d.hatena.ne.jp/nishimotz/20071218

未来のいつか/hyoshiokの日記
未踏オフ会
http://d.hatena.ne.jp/hyoshiok/20071218

ソースコードの読み方(ニコニコ動画(RC2)で公開)

Asianux Road Showで行なった、わたしの講演「Linuxトラブルシューティング、ソースコードの読み方」をニコニコ動画(RC2)で公開します。

まあ、言ってみれば入門編というか基礎編みたいなものです。実践編、実際にコードを見ながら、あれやこれやするようなワークショップが必要かと思うのですが、今回はそこまでは行っていません。

お楽しみください。

まつもとゆきひろさんの講演(ニコニコ動画(RC2)で公開) -- ユメのチカラ
http://blog.miraclelinux.com/yume/2007/10/post_3663.html

Rubyのまつもとさんの講演をニコニコ動画(RC2)で公開するまで -- ユメのチカラ
http://blog.miraclelinux.com/yume/2007/11/rubyrc2_8c2c.html

イベント:トラブルシューティングの手法、ソースコードの読み方 Asianux Road Show  -- ユメのチカラ
http://blog.miraclelinux.com/yume/2007/10/asianux_road_sh_6cff.html

ソースコードの読み方 -- ユメのチカラ
http://blog.miraclelinux.com/yume/2007/08/post_d6bd.html

自分が何をできるか

対案のない批判は単なる床屋談義であり、新橋の飲み屋でやってくれという空気を感じたので、自分のできる事を考えた。

実のところ、新橋の飲み屋で楽しく飲むのは大好きである。飲めば飲むほど饒舌になる。単なるヨッパライのおやじである。ブログなんていうのは所詮世界規模のヨタ話である。閑話休題

まあ、偉い人を批判するのは簡単である。大企業を批判するのも簡単である。あー、すっきりした、という感じである。じゃあ、おまえは、どれだけエライのか。そーゆー感じである。ご説ごもっとも、おっしゃるとおりである。

わたしはコンピュータが好きだ。プログラムを読んだり作ったりすることが好きだ。こーゆー事を書くと、おめー頭おかしいんじゃないか、と思われたりするのだが、昔はそれを口外するのがはばかられた雰囲気があったのかもしれないが、この年になると憶面もなく、そーゆー事を声を大にして言う。別にそーゆーことを声を大にして言っても、誰の迷惑になるわけでもないので、言ってもいいのである。人と違ってもいいのである。

ソースコードを読むのが趣味ですなんていう奴は世界広しと言えど、そうはいないと思っていたら、意外と同好の士は少なくなくて、インターネットのおかげで簡単に、そーゆー人と出逢う事ができてカーネル読書会などという変な会合も80回を数えることができている。

別に産業構造として日本のIT産業に国際競争力がなくてもいいという立場の人もいなくはないが、もちろんわたしはそのような立場をとらない。

なぜか。

日本から、そーゆー産業がなくなってしまうと、わたしの好きなプログラムをする人達がいなくなっちゃって(ここは極論だよ)、カーネル読書会みたいな変な会合が益々ニッチになってしまって、つまらないからだ。

もっと言えば、わたしはカーネル読書会で、OSの話だけではなくて、CPUプロセッサの話とか、キャッシュの話とか、IOバンド幅がどうだとか、RDBMSの上半分と下半分の実装がどうだとか、様々なある意味多くの人にとってどうでもいい、だけどそれを実装している人にとっては非常に重要な文字どおり命を削ってでも一生懸命作るなにものか、そしてそれを作ったその人達と語りあいたい。喜気として技術を技術として語りあいたい。

そのような場を日本という地域で持てれば幸せだと思っている。東京はおかげさまで人口密度も高いので、そーゆー変な人達がいっぱいいて、夜な夜ないろいろな勉強会だかヨタ話だかわからない会合が開催されている。楽しいではないか。

技術を大事にする会社もあれば大事にしない会社もある。それはそれ、これはこれ。

人は食うために仕事をする。これも事実である。

自分がやりたい仕事例えば開発の仕事が、その会社でなければ、どうするか。選択肢は二つ。会社に残って別の仕事をする。もう一つは、その仕事がある会社を探して転職する。

大きな会社ほど、社内にいろいろな機会がある。これも事実である。

小さな会社は、あれもこれもできないから、あれ専門か、これ専門かである。

わたしは、大学を卒業して、米国のハードウェアベンダーの日本法人の研究開発部門に就職した。80年代の前半である。IBMに次ぐ世界第二位の規模の会社であったが今はその会社はない。(20代のころ

ソフトウェア製品を作るのは大変の事はもちろんいっぱいあるけど、それ以上に製品を作るという喜びがあった。ソフトウェアエンジニアリングのイロハを教えてもらった。

その後、いろいろあって日本オラクルに転職し、縁あって米国Oracleへの出向し気がついたら30代後半はせっせとコードを書いていた。

シリコンバレーのソフトウェア企業は間違いなく技術者を大切にする。そのような会社が競争力がある。もちろん、技術にあかるくない、とんがった頭のマネージャもいなくはないが、おたくはおたくとして心地良く生きられる空気がある。

ソフトウェアによって世界を変えてやろうという夢を持ったハッカーがいる。それで一山あててやろうという山師もいる。

で、自分にできることといえば、ソフトウェアの開発が面白い、楽しい、一生の仕事にたる価値のあることだと言うことを地道に伝える努力をすることだと思う。

エライ人に会う機会があったら直接言ってみる。若い人にあったら直接言ってみる。リアルでの機会を見つけて言ってみる。それを愚直に続けることぐらいしかわたしにはできないだろうけど、それをやる。

IPAのエライ人やNTTデータのエライ人に直接会う機会がある僥倖を利用して直接言ってみたいと思う。

IPAフォーラムって実はそーゆー機会を提供してくれたんだよね。実は午後からのセッションに参加して、午前中にそんなセッションがあったということを露知らず、エライ人に、コミュニティーがどうだとか個人を主体とした開発がどうだなんてなんて、ヨタ話を懇親会の場でかましていたのだ。そして、若い人に、あなた達の話をエライ人たちがメモを取りながら聞いていたよ、世の中変わるよ、君たちのコードでという話をしたいたりしたのだ。

エンジニアは文鎮に敬意を - Blog-side

業界の重鎮に対して、我々エンジニアは、敬意を示すべきなんじゃないか。

もちろん、おっしゃるとおりだと思う。そして、あなたの言うとおり、機会をみつけてお話をする努力もしている。

イメージを形にできない人は減衰する - 404 Blog Not Found

ビジョンを語るのは文鎮の仕事じゃない。あなたの仕事である。

ありがとう。精進したいと思う。


 

若い人に人気のない産業は衰退する     http://blog.miraclelinux.com/yume/2007/11/post_1ab2.html

20代のころ -未来のいつか/hyoshiokの日記
http://d.hatena.ne.jp/hyoshiok/20040909

まつもとゆきひろさんの講演(ニコニコ動画(RC2)で公開)

Asianux Road Show in Tokyo (10/16開催)での講演のビデオです。どうぞ、お楽しみ下さい。まつもとさん、ご講演ありがとうございました。

「まつもとゆきひろはなぜプログラミング言語をつくったのだろう」もあわせて読みたい。

ソフトウェアの作り方を考える

開発工程を別々に担当してはいけない」は思いのほか多数のブックマークを頂いた。コメントやブックマークを拝見しながらあれやこれや考えた。わたしの飛躍する思考というか雑な議論で辟易している方もいらっしゃるかとは思うがもう少しお付き合いいただければ幸いである。

わたしの経験は、このブログの読者の皆さんはご存知かもしれないが、ソフトウェア製品の開発経験に偏っている。米国系ハードウェアベンダーでコンパイラやRDBMS製品を開発していた。その後西海岸のソフトウェアベンダーに転職してそこでRDBMS製品の開発に従事した。そしてOSSの可能性を信じてミラクル・リナックスの設立に参加したのが約7年前である。顧客向けアプリケーション、例えば社内システム構築(人事、財務、購買などなど)の経験はない。

さて先の「開発工程を別々に担当してはいけない」ではいろいろな論点をごった煮風に突っ込んだものだから分かりにくくなったので、いくつか細かく分けて考えてみる。

人月のワナ。

多くの人が指摘しているようにソフトウェアの価値をかかった工数(人月)で評価するというのはまるっきりナンセンスである。熟練者が一ヶ月で作成できるものを初心者が6ヶ月かかったとすると、後者に6倍お金が払われるか、それだけの価値があるか。もちろんない。

この場合の正しくは、ある実装した価値、通常は機能で近似するかと思うのだけど、それに見合った価格が支払われるべきである。単位機能を実装する工数が少なければ少ないほど、利益があがるので、ソフトウェア開発における生産性向上のインセンティブが発生する。人がソフトウェアを作る以上、一人一人の専門性、技術を向上させることに高いインセンティブが発生する。企業にとっても、未経験者(安い人材)を雇用し、その利ざやで稼ぐのではなく、より専門性の高い人間を雇用し、その生産性の高さで利益をあげることに、そして教育やトレーニングに投資すること(生産性や品質の向上に繋がる)に合理性が発生する。

ソフトウェアである機能を実装するために、設計、プログラミング、テストという工程があったとして、それを工程ごとに分離して、それぞれを単能化することによって生産性を向上するという、古典的な工場モデルがソフトウェア生産に適用可能なのか。ひたすらネジを取り付けるだけの自動車工場なんていうのがいまどきありうるのか。ソフトウェアの設計とプログラミングそしてテストというのがそもそも分離可能な工程なのか?

わたしは、そのような工程を単純に分離することは難しいし、分離することは専門性を高めることには繋がらないと思っている。分離することによって、生産性が向上するという証拠もほとんどみたことがない。ソフトウェアを実装する能力を高めるためには、渾然一体のプロセスである、設計、プログラミング、テストを等しく経験しなければならないと考えている。その経験を積むことによって一人一人の専門性すなわち生産性が向上していくと考えている。

テストとプログラミングをするものは分けるべきだと言う議論ももちろんあるが、ここでいうテストは実装の妥当性を評価するいわゆる内部テストに相当する部分で、仕様の妥当性を検証する統合テストあるいは受け入れテストのところではない。昨今ではテスト駆動型開発という手法で広く取り入れられている方式である。

ということで、工程分離することによって生産性が向上するという可能性が少ない、むしろ悪化すると考えている。一方で機能による分離では生産性向上がみこめると考えている。

ITゼネコンうんぬんかんぬんはまた別のお話なのでいつの日か別にお話することにしたい。

開発工程を別々に担当してはいけない

古典的なウォータフォールモデルでは、ソフトウェア開発を要求仕様分析、概要設計、詳細設計、実装(コーディング)、内部テスト、統合テスト、運用、保守みたいな工程にわけ、通常は各工程を別々の人が担当するというような方法がよくおこなわれている。

特に、要求仕様の分析、概要設計などは上流工程などとよばれていて、詳細設計、実装とは別の人ないしは組織が担当する。実装とかテストは下流工程などとよばれている。

よくあるパターンとしては元請けが上流工程を、下請け、孫請けが実装やテストなどを担当し、人月単価も下流の方が安い。

ウォーターフォールモデルでは各工程毎に成果物(仕様書や各種ドキュメント、プログラム)が大量に生産される。各フェーズ毎に定義された成果物がそろってから次のフェーズに移行するというのが建前なので、各フェーズでのドキュメントはどうしても冗長になりがちである。

一度固定した文書は次のフェーズで変更するとなると、手戻り工数が莫大になってしまうので、通常は、前工程で決めたことは、後工程で変更はしない。後工程で変更しないという前提で文書を作るので、いろいろ長期間にわたって検討などをするのであるが、実装してみないとわからない事などもいっぱいあるので、なかなかそうは上手くいかない。

実装してみて、できたものは最終ユーザからみると使えないものでも、仕様書に明記されていたものをその通りつくっている限り実装者(製造)の責任ではない。

大量な文書を作るし、各フェーズのレビューの工数も重いので開発スピードは遅くなりがちで、当初予定していた利用環境やユーザの要求というのも時間とともに変化するので、実装が終了した時点では仕様そのものが陳腐化するという事もすくなくない。ひらたく言うと、一生懸命つくっていたのに使えないものができてしまったということである。

ユーザアプリ開発、SI(System Integration)の現場では、おおかれすくなかれ上記のようなパターンがあって、それに元請け、下請けという産業構図がはめこまれていて、元請けが大手ベンダー、下請け、孫請けが中小ベンダーという風になっていたりする。大手がゼネコンの立場になって、多くの下請け、孫請けを使って大規模システムを構築する場合、いろいろな意味あいを含めてITゼネコンといったりする。

工程を別々に担当することによって、数々の問題が発生する。

通常は上流の方が単価が高く、下流の方が単価が安いので、だれも下流をやりたがらない。下流工程は結果として単価の安い経験の浅いエンジニアをつけることになる。工程は通常、組織によってわぎりにされているので、下流工程の作業をやる人がノウハウをためて上流作業をになうという機会がない。元請けはいつまでたっても元請けだし、孫請けはいつまでたっても孫請けである。孫請けの経営者も経営者で、単価は安くても、とりあえず人の分だけ売上があがるので、大手にぶらさがっていれば食いっぱぐれない。そのため経営の緊張感はない。利益率は低いがどうにか食っていける。というような構造がある。

下流にいけばいくほど単価のたたきあいになるので経験豊富なベテランを配置することが難しくなり、若年層エンジニアを使いすてることにならざるをえない。いわゆる35歳停年説である。

業界全体としてエンジニアを使い捨てにすることには百害あって一利もない。にもかかわらず、抜本的な対策、方策がとられているようには見えない。

なぜなんだろう。

わたしには、この工程によって作業を分担するという方法が諸悪の根源であるように思えてならない。小さい会社が何十人もエンジニアを集められないので元請けになれないという事情があるというのは百歩譲ってあるとしよう。大規模な開発をするため何社かで共同作業が必要だったとしよう。その場合の分担を工程ごとに輪切りにするのではなく、機能ごとに縦に切る事を提案したい。

つまり、ある機能について、一社ないしは一人が仕様の決定から設計、実装、内部テストまで担当するのである。キモは設計者と実装者は同一人物とするのである。これを分離しない。

なんでこんなことを言うかというと、実装と設計は不可分で、実装をしてみて初めて気がつくこと、設計をしてみて初めて気がつくことなどがあり、実際の設計と実装というのはいきつもどりつのプロセスである。このいきつもどりつがない限り、いい実装などはできはしない。設計と実装を分断している限り、しょぼい設計としょぼい実装にしかならない。初めから完璧な設計などはないのである。完璧な設計でない以上、しょぼい実装しかうまれてこないのである。

工程を分離するのは悪なのである。

工程を分離するために専門性が蓄積されない。より高度な実装を作成するインセンティブも発生しない。

「渡された仕様書を実装するサラリーマンプログラマ」の悲哀』にあるのは工程を分離されたプロジェクトの悲哀であって、サラリーマンかどうかは無関係である。

わたしはソフトウェア工場というコンセプトそのものを否定するつもりは毛頭ない。工学的なアプローチによってより品質の高い(バグ密度の低い)ソフトウェアをより少ない工数で生産するということは可能であると思う。QC活動のような方法論ですら有効な場面は少なくないと思う。

しかしXPで実践されているようなベストプラクティスの多くは工程の分離ではなく設計と実装の渾然一体となったプロセスである。

日本のソフトウェア開発の現場の国際競争力のなさというのがあるとしたら、ITゼネコンをよしとした、上流下流工程を是認したソフトウェア生産方法論にあるのではないか。そこに構造的な問題があるのではないかと思うのである。人月で工数をはかる事がやりだまにあがっているが、根本的な問題は、工程を分離して、下請けにだすというソフトウェア生産方法であると思う。

ちなみに、米国のソフトウェア製造業では(マイクロソフトもオラクルも)、設計する人がコードも書くのである。それが一般的な姿である。わたしの場合(DEC時代もオラクルの時)も、そうであった。

プログラマの仕事はプログラムを読むことである/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/10/post_9db7.html

まつもとゆきひろはなぜプログラミング言語をつくったのだろう

先日のAsianux Road Show (東京)は大盛況だった。参加いただいた皆さんどうもありがとうございました。(ぺこり)

大阪、福岡もまだまだ会場に余裕がありますので、ふるってご参加ください。

さて、特別講演でRubyのまつもとゆきひろさんにお話をいただいた。この講演に関しては、自分が聞きたい人にお話してもらうというカーネル読書会メソッドとも言うべきもので、まつもとさんには無理を言ってお願いした。(まつもとさんには「よしおかさんの頼みを断れなかったからだ。人脈というのはこのように活用するのね」といわれてしまった(笑))

それはともかく、弊社営業も、すごいということがよくわかりました、と感動していた。しかし技術者(プログラマ)でない人達にまつもとゆきひろの凄みを説明するのはなかなか難しい。

社内反省会(懇親会のあとの飲み会とも言う)で、その営業がわたしに「なんでプログラミング言語なんて作ったんでしょうね」と聞いてきた。一見簡単そうなこの問い。なんでなんだろう。哲学的な問いである。

なんでだろう。

ふつーだったら、プログラミング言語を新規に作ろうなんて事は思わない。わたしは高校、大学時代、ちょっとは思ったが、そーゆー人間は、そんなにはいない。30年以上前にBASICを作った大学生はいまや世界一の大金持だが、そーゆー人間はふつーいない。わたしは昔昔、BYTE magazineだったか何だったかにAPLのインタプリタが載っていて、当時パソコンなんてものは持っていなかったので、その記事を穴があくほど読んだ記憶がある。(http://www.vintage-computer.com/byte.shtmlによれば1977年8月号だったようだ)

わたし自身、言語オタクの片鱗はあったかもしれないが、プログラミング言語を新規に作った経験はもちろんない。

まつもとさんはプログラミング言語を作っただけではなく、それを10年以上コツコツ拡張し続けている。

これは驚異である。奇跡(?)である。

いまでこそまつもとさんの背中を見てプログラミング言語を作ってしまおうなどという蛮勇を持った若者が出てきているが、ふつーはそんなことは考えもしなかった。

しかし、よく考えてみるとLinusも自分でOSを作りたかったから作ったわけで、それがいつのまにかにIBMだOracleだIntelだがが勝手に注目して勝手にエンタープライズだなんだとよってたかって改良に従事しはじめたわけで、その中で、ビジネスだなんだとネクタイを締めているオトナが大挙してきた歴史があって、それと昨今のRubyにまつわるビジネスシーン(?)も似ている。

ハッカーがプログラムを作る。誰かが使う。誰かが改良する。どんどん利用者が増えてくる。どんどん開発者が増えてくる。改良の速度が加速して、ますます適用範囲が拡大する。それでビジネスをする人も増えてくる。益々適用範囲が拡大する。

凡人は、新しいプログラミング言語を作ろうなんて思わない。偉大なハッカーは、それを実装するだけではなく10年以上それを続ける。そして人々から尊敬をあつめる。

プログラミングを続ける情熱は一体どこから来るのであろう。

おおきな謎は謎としてとっておきたいと思った。

プログラマの仕事はプログラムを読むことである

ソフトウェア開発コストのほとんどは保守のコストだと言われている。各種統計がそれを示しているわけだけど、自分の実感とも合う。

古典的なウォータフォールモデルでは保守というのが意識されないか、あっても一番下流なので、その重要性に対する認識が非常に薄い。

保守という言葉は若干大げさな響きを持つが、プログラムの不具合の修正や、ちょっとした機能変更、機能追加などなど、運用していけば、つまりそのソフトウェアが利用されていれば必ず必要なものである。保守されていないソフトウェアは早晩利用されなくなるか、既に利用されていないかである。

Unixの哲学を持ち出すまでもなく、優れたプログラマはプログラムを書くのではなく、再利用する。いかにしてプログラムを書く機会を減らすか虎視眈々としている。可能な限り再利用して、どうしても書かざるを得ない場合はリサイクルをしちゃったりする。(プログラマにとってのReduce/Reuse/Recycleってか。閑話休題)

このプログラムの保守のコストというのはプログラムの規模に比例する。大規模なソフトウェアであればあるほど保守コストの比重が高まっていく。新機能を追加するとしても、既にあるアーキテクチャにすり合わせるために、それを詳細に精密に理解する必要がある。

優れたプログラマはコードを書きっぱなしにしない。そのソフトウェアが使われている限り常にコードを読み改良していく。自分のコードであれ誰かが書いたコードであり、それを読み理解し改良する。

商用ソフトウェアの開発現場のベストプラクティスでは、コードはチームによって常にレビューされる。開発プロセスの中にしっかりレビューが組み込まれている。シニアプログラマの主な仕事はジュニアプログラマや同僚のコードをひたすらレビューすることである。書きっぱなしというのはありえない。もちろんOSSの世界では優しい独裁者の主な仕事はコードを書くことではなくレビューして、そのコードを受け入れるかリジェクトするか決定することである。

プログラマの基礎体力に対するコメントで

プログラマはプログラムを書くのが直接的な作業であって、
読む作業は、役に立つとはいえ、本業に対して間接的なものになります。
「基礎体力」のような大仰な物言いをして、直接関わりのない作業の能力を挙げられても、違和感を感じるだけです。

というのをいただいた。コメントありがとうございます。

もし、「プログラマを書くのが直接的な作業であって」と認識しているのであれば、それは、そーゆースタイルの現場というのがないとは言わないが、ベストプラクティスから程遠いと断言したい。わたしはそのようなスタイルは、古典的なウォーターフォールモデルで、要求定義、外部設計、詳細設計、コーディング、テスト、統合テスト、運用、保守、みたいな各フェーズを別々の人たちがやっているイメージをする。つまり、コーディングをするいわゆるプログラマと詳細設計、外部設計、要求定義をする人たちが見事なまでにばらばらというプロセスである。

「渡された仕様書を実装するサラリーマンプログラマ」の悲哀 にあるイメージである。優れたプログラマというのは要求定義から設計、コーディング、テストまでのプロセスに主体的に関わるのである。優れたソフトウェアはそのように作られるとわたしは思う。

プログラマとして生きて行くつもりなら、「渡された仕様書を実装するだけのサラリーマンプログラマ」よりは遥か上を目指すべき。そうでないなら、他の仕事を探した方が良い。自分のキャリアパスを見つけ出す責任を持つのは、会社でも上司でもなく、自分自身なのだから。(上述

まあ、わたしの世界が狭いのかもしれないが、わたしの直接間接に出会った優れたプログラマは皆コードを良く読むプログラマであった。そしてコードを読むことによってどんどん成長している。

プログラマの基礎体力

そもそも、プログラマの基礎体力ってなんだろう。学校でアルゴリズムの基礎を習うとか、プログラミング言語を習うとか、あるいはコンピュータの基礎を習うとかそういうことなのだろうか。

断片的な情報を獲得するのなら確かにインターネットや書籍でどうにかなる。しかし、職業プログラマとして一目置かれる存在になるための基礎体力ってなんだろう。

高校や大学などでプログラマの基礎体力は身につくのだろうか。

プログラムと言っても、ゲームのプログラムから、顧客の要求に従ったアプリケーションプログラム、組み込み機器の制御プログラム、あるいはOSやら、コンパイラやら、RDBMSやらの基盤ソフトウェアなど様々ある。

わたしの場合、子供の頃、初めてコンピュータに触る機会があって、その時のなにやら得体の知れない興奮みたいなものが結局のところコンピュータ関連の職業につくことになったのだが、知識0から鍛えるべきプログラマの基礎体力ってなんだろう。

野球少年だったら、親父とキャッチボールすることで、あるいはプロ野球を見につれてってもらうことで自然と野球に対するスタイルみたいなものが確立していく。三角ベースで放課後遊ぶのでも部活にはいるのでも、上手い下手あったとしても野球をやる基礎体力を得るためのパターンは確立されているように思う。

プログラマにとってのキャッチボールみたいなものは、いったい何なんだろう。

例えば、プログラミング言語の授業でHello Worldからというのは正しいトレーニングなんだろうか?

わたしが子供のころに比べれば今は一人一台PCを持っていて、フリー(この場合は自由というよりも無料という意味の方が近い)でソフトウェアが利用できる。知識を獲得する環境は圧倒的に今のほうがよい。よいはづなのであるが、プログラマとしての基礎体力をつける環境は整備されているのか?基礎的なトレーニング方法は確立したのか?

そこでプログラマの基礎体力をつけるためのよしおか試案である。

まづ、プログラマになりたいと思うモチベーションを与えるためにのきっかけ作り。ロールモデルの提示、コンピュータで凄いことができる、世の中を変えてしまったというようなわくわくする事例の提示。ハッカー魂をくすぐる。興味を持ってもらわなければ話にならないので非常に重要だと思う。

次に、プログラムを0から書くのではなく、動いているプログラムのコードを見せる、読ませる。ある機能を実装する時の表現方法を示すのがプログラミング言語の学習になる。先にプログラミング言語の文法を教えるのではなく、おもちゃでもいいので何かを実装するプログラムがあって、それを実装するためにこのようなシンタックスで表現するということを教える。その意味で、HTMLのようなものはいいかもしれない。

コードを書く力ではなく読む力を重視する。コードを読むことがプログラマにとってのキャッチボールになる。

教材はオープンソースソフトウェアにある。

コードの中に、配列や、リストや、ツリーや。グラフや、スタックや、その他もろもろのデータ構造があるが、それがどのように利用されていて、なぜそのようなデータ構造を利用すると嬉しいのかを解説する。同様にデータ構造をあれやこれやするアルゴリズムがある。それについても批評的に読解していく。

コードを読むことによってプログラムの構造や先人の知恵や失敗を学んでいく。

コードを読むという観点からのプログラミング言語入門書というのは面白いかと思う。

プログラマにとっての基礎体力はコードの読解力でそれを強化するのが重要であるというのが、本日のわたしの結論である。

トラブルシューティングのいろは

トラブルシューティングの第一歩は問題を正しく認識することである。そのために、問題を再現する必要がある。問題を再現するために、どのような条件でその問題が発生しているかの情報を収集しないといけない。

OSのバージョン、ハードウェアの構成からはじまって、問題を発生させているソフトウェアの構成などなどを特定する。

問題が再現できれば、トラブルシューティングの八合目まで登ったも同然である。

次にやるべきことは、問題の切り分けである。問題が起こる条件を局所化、最小化して特定する。

例えばLinux Kernelの場合は「カーネルにおけるリグレッションの特定」で紹介したような方法を使う。2.6.17では問題がなかったが、2.6.18で問題があったとすると、その間にあてた修正がなんらかの問題を発生させているとして、問題を発生させた修正を特定する作業になる。gitによれば、3399件の修正があるので、一個一個それを試していては日が暮れてしまうので、2分検索をして12回ほどの試行で問題を特定する。(すごいすごい)

同様に問題の起こっているシステムと、起こっていないシステムの差異を抽出して、問題を発生させているパラメータを特定する作業が重要である。この場合、いかに問題が起こる局所化あるいは最小化した条件を素早く見つけるかが鍵になる。ある意味、このプロセスに長けたプログラマをハッカーと呼びたい。素人は一個一個のたのたやるわけだけど、達人は目にもとまらぬ速さで再現ケースに到着している。

これには、対象となるソフトウェア依存の知識が必要なのは当然である。例えばMySQLのトラブルシューティングをしているのに、MySQLのことを全く知らなければお話にならない。とはいうもののソフトウェア固有の知識ではなくトラブルシューティング一般のパターンも存在する。

先の例でいえば、あるバージョンで問題が発生したとしたら、とりあえづ最新版でその問題が発生しないか確認するというのは、王道中の王道である。その問題が未知な問題なのか既知の問題なのかの調査の一環として試行する。仮に最新版で直っていた(現象が再現しない)のなら、2分検索をして問題が起こる個所を局所化する。

問題が起こる個所が局所化できれば、あとはソースを読むなり、ワークアラウンドを提示するなりして問題を回避すればいい。

この場合、ソースコードを読む時点では、もはや問題をかなり正しく認識しているので、コードを読まずしてほぼ正解にたどり着いているようなものである。

コードを読むな、理解しろ」でも、紹介したように、問題を局所化できれば解決までは高速道路で一気にいっちゃうのである。

カーネルにおけるリグレッションの特定

例えば、2.6.17では問題ないのに、2.6.18だとなぜか問題が発生するとする。linux kernel は git というソースコード管理システムによって、全ての変更が管理されているので、その機能を利用して問題を発生させたパッチを特定する事ができる。

基本的な考え方は、コミットしたパッチを問題を発生させた組と、発生しない組にわけていって、問題を絞り込む。2分検索だ。

例えば、1000個分の変更がコミットされていたとする。これを問題が発生しない状況から一個一個順ぐりにあてていき、問題が発生したら、最後にあてたパッチが原因だということがわかる。この順ぐりにあてていく場合、最悪1000回試行錯誤しなくてはいけない。

2分検索の場合、まづ、500個分あてた状態で(gitで簡単にそのような状況をつくれる)試験をし、仮に問題が発生しなければ、残りの500個に問題があるので、さらに、その半分250個をあて(最初から見ると750個のところ)試験をする。仮に問題が発生したとしたら、最初の500個分のなかに問題を発生させるパッチがあるので、さらにその半分の地点の250個分をあてた時点で試験をする。その結果によって、さらに問題を絞りこむ。

git bisectというコマンドがそれを簡単にやってくれる。手始めにOKのバージョンとNGのバージョンを設定し、その後、テストを繰り返し、テスト結果にしたがって、もし、問題が発生したら(bad)、OKであれば(good)。
git bisect bad
ないし
git bisect good
として問題をしぼりこむ。

以下実例。


# git bisect start
# git bisect good v2.6.17
# git bisect bad v2.6.18
Bisecting: 3399 revisions left to test after this
[2a2ed2db353d949c06b6ef8b6913f65b39111eab] Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild
# git bisect bad
Bisecting: 1699 revisions left to test after this
[8d3c138b77f195ca0eee6fb639ae73f5ea9edb6b] page migration: Update documentation
# git bisect good
Bisecting: 849 revisions left to test after this
[88ca8ed0b7f2f04a055ff3c389f398ba3ad3d27d] V4L/DVB (4048): Add support for the Texas Instruments TLV320AIC23B audio codec
... (中略)
# git bisect good
Bisecting: 3 revisions left to test after this
[c22ce143d15eb288543fe9873e1c5ac1c01b69a1] x86: cache pollution aware __copy_from_user_ll()
# git bisect bad
Bisecting: 1 revisions left to test after this
[f2c780c1fdbe5008c902c2d7e37242ac5e60f0b9] Au1550/1200: add missing PSC #define's, make OSS driver use the proper ones
# git bisect good
Bisecting: 0 revisions left to test after this
[7dbdf43cfa635ddc3701cc8d1eab07597cd731c0] mips: fix number of mremap arguments
# git bisect good
c22ce143d15eb288543fe9873e1c5ac1c01b69a1 is first bad commit
commit c22ce143d15eb288543fe9873e1c5ac1c01b69a1
Author: Hiro Yoshioka

Date:   Fri Jun 23 02:04:16 2006 -0700     [PATCH] x86: cache pollution aware __copy_from_user_ll()     Use the x86 cache-bypassing copy instructions for copy_from_user(). ...     Signed-off-by: Hiro Yoshioka

    Signed-off-by: Andrew Morton

    Signed-off-by: Linus Torvalds

:040000 040000 73b282577d95f4b69f046f715ac6a5a4694ba758 a2b88cac24b674c0519352c3f74a122ed6e46e7a M      arch :040000 040000 e15615138743db3d63ba41ca2c0cf00854e601eb e1d7a032e27ab3cb0bbe6df743d1ae644bd8a999 M      include :040000 040000 8361e3dcee117b08ccce5ccc9d451d84b07edfad 847b80b43154037f25781dda0e059df7e94c1ff8 M      mm

ふんぎゃーー。わたしのパッチで何か問題があるらしい。
という感じになる。

今回このブログを書くきっかけは、下記のスレッドにある問題。2.6.18にしたらなぜかファイルがcorruptionした。
http://marc.info/?t=119116762100001&r=1&w=2

上記のようにbisectしてみたら、どうもcache pollution aware patchがなにやらやっているらしい。
http://marc.info/?l=linux-kernel&m=119135926624999&w=2

gitのログでわたしのメールアドレスが明記されているので、メールをCCされてしまって気がついた。

それにしても3399もあるコミットからいとも簡単に問題となるパッチを特定しちゃうんだからgitというツールはすごい。

さらに言うとLinusは何千もあるパッチのうち、当該パッチはmovntiを利用していて、キャッシュをバイパスしてデータをストアしているということを正確に理解している。

http://marc.info/?l=linux-kernel&m=119144213218621&w=2
http://marc.info/?l=linux-kernel&m=119146929402139&w=2

Linusってやっぱり神だよ。


git bisectのマニュアル
http://www.kernel.org/pub/software/scm/git/docs/git-bisect.html

Git を使ってソース・コードを管理する
http://www-06.ibm.com/jp/developerworks/linux/060809/j_l-git.shtml

Real-life kernel debugging scenario
http://kernel.org/pub/software/scm/git/docs/v1.3.3/howto/isolate-bugs-with-bisect.txt

Bisection searches/みたのブログ
http://blog.miraclelinux.com/mita/2006/06/bisection_searc.html

ロックのいろは

ロックと言うのはプログラミング上のコンベンション、慣用句みたいなもので、共有資源へのアクセスに対する同期のメカニズムとして利用される。

ある共有資源を複数のプロセッサ(あるいはプロセスでもいいけど)から同時に利用したいとする。変数に1を加えるという単純な動作ですら同期をとらないと正しい結果を得られない。

ロックはそのような同期を必要とする場面でよく利用される。ロックを取得したただ一つのプロセスのみその共有資源にアクセスできるようにするのである。

アトミックに値をセットしてテストする命令(test and set)を利用しロックが取得できるまでひたすらループして待つ、いわゆるスピンロックという単純素朴な方法がある。IA-32だとxchgという命令があって、あるメモリとレジスタの値をアトミックに(他のプロセッサに邪魔されることなく)行うことができて、それを利用する。例えば、0がロックされていない状態、1がロックされている状態とすると、下記のコードがそれをナイーブに実装したものである。

Spin_Lock:
Get_Lock:
    MOV EAX, 1;
    XCHG EAX, lockvar; // Try to get lock.
   CMP EAX, 0; // Test if successful.
   JNE Spin_Lock;
//
Critical_Section:
       MOV lockvar, 0; // Release lock.

lockvarとEAXレジスタの値を交換して、lockvarの値が0であったら誰もロックを取得していないので下に行く。誰かがロックを取得していたら1が入っているので、Spin_Lockにジャンプして繰り返す。ロックを取得できたら、共有資源にアクセスするなりなんなりをして最後にlockvarに0を代入しロックを解放する。そうすると同じロックを取得するために待っていた誰かがロックを獲得できるようになる。

上記の実装は間違いではないのだけど、実装上性能に多くの問題がある。毎回、xchg命令でメインメモリにアクセスに行くのだがアトミック性を保証するため、つまり値を交換しているとき、他の誰かが別の値に交換しないようにバスをロックし、単一のプロセッサだけが当該メモリにアクセスできるようにする。そうするとxchg命令実行中は他のプロセッサはバスがロックされているのでメインメモリにアクセスできない。プロセッサの数が増えれば増えるほどバスの競合が発生しスケールしない。またメモリアクセスは遅いでも書いたが、メモリアクセスはキャッシュアクセスに比べ100倍は遅いので毎回毎回のたのた動き回ることになる。まあ、スピンロックで持っているわけだから別に他に仕事がないので遅くてもいいっちゃいいのだが、先のバスロックはいただけない。

でもって、通常はどうするかと言うと、もう少しリラックスした方法になる。
先の実装のSpin_LockとGet_Lockの間に下記のコードを埋める。何をしているかというと、cmp命令でlockvarが0かどうか最初にチェックしている。つまり、ロックされているかチェックして、仮にロックされていなかったら、Get_Lockにジャンプしてロックの確保を試みる。

Spin_Lock:
   CMP lockvar, 0 ; // Check if lock is free.
   JE Get_lock
   PAUSE; // Short delay.
   JMP Spin_Lock;
Get_Lock:

cmp命令を実行してから、次のxchg命令まではアトミックではないので、他のプロセッサがその間にロックを取得してしまう可能性があるので、xchg命令で再度ロックが確保できるか確認している。cmp命令でlockvarを確認するのは、それがキャッシュに載っていればキャッシュアクセスなので高速に判定できる。ロックが取得できないときのループもキャッシュへのアクセスを延々と続けるので、メインメモリにアクセスしないので、他のプロセッサの邪魔をしないためスケーラビリティがある。メインメモリへのアクセスは他のプロセッサとの調停が必要なのでプロセッサの数が増えれば増えるほどコストが増大するので、できれば避けたいのある。

またスピンループ中にpause命令を入れているがこれはnopで、プロセッサに対しフルスピードでループしているけど他に有益な仕事があるんだったらそれを先にやってもいいよ、あるいは消費電力を落としてもいいよ、みたいなヒントになっている。IA-32の慣用句である。(蛇足)

スピンロックを実装するときに上記のように二重ループにするのはロックのいろはなのであるが、ユーザーランドで実装するときも注意したい。

また上記のようなアプローチはTest and Test-and-setとしても知られている。

上記の例はIntel 64 and IA-32 Architectures Optimization Reference Manualの8.4.2からの引用である。http://www.intel.com/products/processor/manuals/index.htm

メモリアクセスは遅い/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/09/post_b3bc.html

Latencyの隠蔽

プログラマたるものコンピュータの基礎的な知識は必要だと多くの人は言うのだけど、じゃあどこまでが必須でどこまでがオプション(?)なのかというと明確な線引きがあるわけではない。まあ、Kernelとかコンパイラとかをゴニョゴニョする人はCPUのキャッシュがなんたるかくらいは理解していないといろいろ大変かと思う。

時間と空間を交換するというのはコンピュータだけの世界ではない。街のコンビニだって、店頭に並んでいるものはすぐにアクセスできるけど、店頭にないものはすぐにアクセスできないので、在庫量がある一定水準を下回ったら発注のトリガーがかかる。コンビニはその発注サイクルがデパートとかに比べれば異様に多いので、クロックを上げて性能を出すPentium4みたいなものである。発注単位も非常に小さくて、それこそ弁当一個でも平気で発注しちゃうという感じである。在庫をほとんど持たないので、キャッシュミスした時のペナルティは、そのまま機会損失である。倉庫のようなディスカウントストアもあるが、そちらの発注単位はでかくて、大きな空間が必要なので土地のコストが安い郊外に立地している。

アクセスコストとメモリコストの差に注目して記憶領域を階層化するのは、CPUキャッシュだけではなく、メインメモリとディスクキャッシュなどでも行われている。

CPUのレジスタとメインメモリアクセスの速度は100倍くらい違うので、性能を意識する場合CPUキャッシュがどのようなメカニズムで働いているかを十分理解しないといけない。

メモリアクセスは遅い(ユメのチカラ)で指摘したとおり、メモリアクセスが遅いことを前提にいろいろなチューニング方式が考えられるが、一番単純なのは、プリフェッチである。

順アクセスの場合、次にアクセスされる番地が予想できるので、その番地にあらかじめアクセスしておく。そうすれば実際にそのデータが必要になったときにはキャッシュでのアクセスになるので、メモリアクセスを待つと言うことはない。例えばメモリアクセスに200クロックかかっていて、L1キャッシュのアクセスが2クロックだったとすると、L1キャッシュヒットだと残りの198クロックを無駄に待つ必要がないのでより高速な処理ができる。

あるメモリにどのようにアクセスするかはプログラムを書いた人が知っているはずなので、プログラマが陽にヒントとして与えてもいいし、コンパイラがそれを何らかの方法で認識し、積極的にプリフェッチをかけるというのもある。

最近のプロセッサだとメモリアクセスのパターンを見て、順アクセスを検知すると自動的にプリフェッチをする場合もある。投機的なメモリアクセスである。

あらかじめ準備をしておくというのがlatency隠蔽の基本的な考え方である。

もう一つの方法は、時間がかかる処理と並行して、別の処理を実行するというもので、直列に処理をすすめると、長いlatencyを持つものを待たないといけないので、スループットが上がらない。そこで並列に処理できるものをどんどん処理していくという考え方である。

入出力もlatencyが大きいので、入出力と並行して別の処理をするというものである。

スーパースカラなプロセッサは同時に複数の命令を処理するので、そーやって、スループットを向上させたり、latencyを隠蔽したりする。

Computer Architecture: A Quantitative Approach(David A. Patterson, John L. Hennessy )を読んで、基本的な概念をおさらいしたいところである。(下記)

機械語ではマシンの挙動は理解できない。(未来のいつか/hyoshiokの日記)
http://d.hatena.ne.jp/hyoshiok/20070916#p1

山勘で分岐先を実行することを投機的実行と呼ぶ(ユメのチカラ)
http://blog.miraclelinux.com/yume/2007/09/post_6814.html

U-20プログラミング・コンテスト

今年もU-20プログラミング・コンテストの審査員を勤めさせていただいた。既に経済産業省から個人、団体部門の入賞作が発表されている。(別紙2) http://www.meti.go.jp/press/20070914003/20070914003.html

特に団体部門の最優秀作品の完成度は高く、審査員一同う~んとうなってしまった。

ゲーム関係の作品は正直わたしがゲームをやらないので、作品性とプログラミングからの観点からの評価とが難しいところであるが、どれも力作ぞろいであった。

若者のプログラムを見るのは楽しい。

10月1日の授賞式で再会するのが楽しみである。

U20プロコン最終審査会/Matzにっき
http://www.rubyist.net/~matz/20070901.html#p01

メモリアクセスは遅い

多くのプログラマにとってメモリアクセスの速度を気しなければならない状況というのはめったに無いが、OS、ライブラリ、コンパイラ、RDBMSなどの実装をする時には意識をしなければならない場合がある。

IA-32 Intel Architecture Optimization Reference Manual (order number 248966) をひもとくと6章にOptimizing Cache Usageというのがある。

マイクロベンマークの定番 lmbench http://www.bitmover.com/lmbench/ では、一次キャッシュ(L1)や二次キャッシュ(L2)を測定してくれる。例えば、わたしが利用しているノートだと、L1が1.776nsでL2が5.3490ns、メインメモリアクセスが139.4nsである。

Memory latencies in nanoseconds - smaller is better
    (WARNING - may not be correct, check graphs)
---------------------------------------------------
Host                 OS   Mhz  L1 $   L2 $    Main mem    Guesses
--------- -------------  ---- ----- ------    --------    -------
asianux2. Linux 2.6.9-3  1700 1.776 5.3490  139.4

クロック数でいうと、L1が3クロック、L2が9クロック、メインメモリが237クロックくらいになる。

L1とメインメモリでは2桁のアクセス速度の差がある。CPUのクロックはムーアの法則によって18ヶ月で倍になると言われていたが、その間のメモリ速度の向上は数%で、年々そのギャップは広がる傾向にある。

近年、性能向上のためのクロック数の向上は消費電力の上昇をまねいたため、性能向上のためにはクロック向上ではなくコア数の増加という傾向になりつつある。それにしても、CPUの速度向上にくらべてメモリ速度の向上ペースは低いので、そのギャップの拡大はおわっていない。

昔はCPUのクロックと同じ速度でメモリにアクセスできたが、現状では100倍程度遅いことを覚悟しないといけない。

性能を極限まで追及する時には、そのキャッシュの振舞いを理解する必要がある。リストをたぐるような操作はアドレスが連続していないので最悪毎回キャッシュミスをひきおこし、メインメモリにアクセスする必要が生じる。従って速度が2桁遅くなる。一方配列を順アクセスする場合は最初の一回はキャッシュミスをおこすがその後はキャッシュにデータがあるのでメインメモリにアクセスしなくてすむので高速な実行が可能になる。

リストやハッシュはキャッシュに厳しいが配列はキャッシュに優しい。

リスト処理の場合は次にアクセスするところ(nextポインタの指しているところ)が分るので、あらかじめプリフェッチをしておけばlatencyを隠蔽できる。

Rubyの RejectKaiji2007で発表したRubyのキャッシュミスを削減した話はキャッシュミスをプリフェッチで削減するというアイデアを実装したものである。

RejectKaigi2007
http://blog.miraclelinux.com/yume/2007/06/rejectkaigi2007.html

一方プリフェッチというのは今あるデータを追い出して新しいデータをキャッシュに置くという事であるから、追い出されたデータがすぐに必要になるとキャッシュミスを発生させる場合がある。これをcache pollution(キャシュ汚染)という。ページのスラッシングみたいなものである。なんでもかんでもプリフェッチをしてキャッシュにのせればいいというものでもない。

そのアイデアを元に作ったのがcache pollution aware patchである。

Linux Kernel 2.6.18とCache Pollution Aware Patch
http://blog.miraclelinux.com/yume/2006/09/linux_kernel_26_2c2c.html

CPUのクロック数の上昇は消費電力の増加をまねくのでマルチコア化が進展しているという事は先に記した。マルチコア化が進展するとプロセッサ間の同期をどうとるかがますます重要になってくる。その実装としてスピンロックがある。スピンロックはメインメモリにフラグを用意して、そのフラグをセットできたものがロックを取得でき、セットできなかったものはセットできるまでループで待つという単純な同期方式である。

あるフラグがセットされているかを毎回メインメモリに見にいくという処理は、バスをロックして、アトミックにそのフラグをセットできるかを確認することだから非常にコストがかかる。バスをロックするので他のCPUは別の場所にアクセスしようとしてもアクセクを待たされるのでスケーラビリティもでない。(100nsから200ns位メインメモリアクセスにはコストがかかることを思い出してほしい)

マルチコアになってキャッシュに優しいロック方式あるいはロックなしの同期方法が求められている所以である。

メモリアクセスにまつわるバイナリハックの場所はまだまだいっぱいある。

ムリ、ムダ、ムラ

製造業なんかでは無理(ムリ)、無駄(ムダ)、むらを無くせなんてことがよく言われている。工程を分析して、無理な作業を無くし安全性をたかめたり、無駄な在庫を持たないようにしたり、作業を平準化してむらをなくしたりする。ソフトウェアの開発でも、ムリなスケジュールとか、ムダな作業とか、ムラとかが見られる。

作業を単純化、標準化して無理なくこなせるようにすれば、無駄な作業やむらが減って手戻りも少なくなり品質も向上する。言うのは簡単なのだけど行なうのは難しい。

しかし、プログラマの美徳として言われる楽をするために工夫をするというのは、まさに無理や無駄、むらを無くす作業に他ならない。

mixiのスケーラビリティ

mixiの生みの親“バタラ氏”が語るMySQLの意外な利用法

サービス開始から3年余りで会員数が1000万人を超えたSNSの「mixi」。そのシステムはOSSで構築されており、データベース管理システム(DBMS)には「MySQL」を使う。急増するトラフィックをさばくために負荷分散を重ねた結果、現在ではサーバ1000台以上が連なる超分散システムへ。その中でMySQLが果たす役割とは。http://techtarget.itmedia.co.jp/tt/news/0709/12/news01.html

という記事があった。

日記だけで4億件。サーバは1000台以上。アクティブユーザは6割を超える。すさまじい規模のサービスである。すべてOSSで構成されていて、自社開発のコードでサービスをささえる。

当初一人のユーザから始まったサービスも2ヵ月後には1万人を超え、さらに半年ほどでデータベースをサービスごとに分割(水平分割と呼んでいる)し負荷対策した。しかし1年4ヶ月で100万人を超える会員数の増加は、それだけでは持たず各種IDごとにテーブルを分割している。これを垂直分割と呼んでいるが、DBMS的にはテーブルを水平方向に切っているので水平分割と呼ぶのが正しい。垂直分割というのは通常は列を縦に切ることをいう。例えばあるテーブルに(ID、A、B、C)列があったとして、それをテーブル1(ID、A、B)、テーブル2(ID、C)などと分割することを垂直分割という。

それはさておき、ユメのチカラでもmixiのスケーラビリティは何度か取り上げた。昨年の7月第65回のカーネル読書会でバタラさんに発表してもらったときのレポートである。下記二つをあわせてお読みいただきたい。

500万倍のスケーラビリティ
http://blog.miraclelinux.com/yume/2006/07/post_7ad0.html

システムを1ユーザから500万ユーザまで約2年半でスケールアップしたというお話で、苦労話満載の非常に興味深いものであった。様様な試行錯誤をへて現在のシステムにいたっているが、1ユーザから500万ものユーザをサポートするなどというスケーラビリティはあらかじめ設計されていたものではない。問題にぶつかるたびに一つ一つ問題を解決していって今に至るということである。この500万倍のスケールアップと言うのは本当にとてつもないことである。そのとてつもないことを飄々とこなしているバタラさんのお話が興味深かった。

LiveJournalのアーキテクチャ
http://blog.miraclelinux.com/yume/2006/07/livejournal_a718.html
こちらはmixiが利用している、mod_perlやmemcachedなどのコンポーネントの話で、それはLiveJournalと同様のアプローチである。

大規模Webサービスを提供するためには、様々なレイヤーでの経験が必要になって、ネットワーク、データベース、OSなどなどどんどん深堀をしていく必要がある。OSSの場合はすべてホワイトボックスなので、やろうと思えばいくらでも深堀をすることができる。それはサービス提供者にとっては価値を生み出す源泉となる。

ノルマ

99年にシリコンバレーから戻ってきてミラクル・リナックスを創業するまでは日本オラクルのサポート部隊にいた。

日本オラクルのサポート部隊にはDDR(Defect Detection and Resolution)という米国直下の部隊があってそこに所属していた。DDRというのはOracleデータベースのバグの修正を行う部隊で、パッチを作成したり、ワークアラウンドを提示したりする。

外資系なのでバグの修正は米国本社がやるだろうと多くの人達は思うかもしれないが、どうしてどうして、日本オラクルの中にはパッチまで作ってしまう専門家部隊があるのである。

わたしの担当はSQLとNLS(National Language Support)なのでbugデータベースの中でSQLおよびNLSと分類されたOracle RDBMSのバグについて日々問題解決をしていた。オラクルのDDRチームは米国本社以外にも日本、インド、英国などにあるので24時間体制で地球のどこかで問題解決にあたっている。わたしがとりあげるバグも日本だけではなく世界中の顧客で発生したSQLのバグで、常に何件も同時並行処理していた。

SQLのバグというのは、それこそ言語シンタックスに対する質問から、コンパイルしようとしたらクラッシュしたとか、ありとあらゆる問題があがってくるのであるが、基本的にはコンパイラのバグなので、タイミングに依存するバグとか規模に依存するバグとかはないので、再現が比較的簡単な問題が多い。トランザクションに関連するバグとかはタイミングがからんできて再現するだけで大変な工数がかかるという問題も少なくはないがコンパイラの場合は、そのような事は少ない。

バグ修正の場合、再現ケースがみつかればほぼ道程の8割から9割は来てしまったも同然である。しかもコンパイラの不具合の場合、プログラム作成時にいろいろ問題が出るが、運用時にはあんまり出ないので、重大なバグ(クラッシュするとか)だとしても優先順位(今すぐ直せ)はそれほど高くない。一方、ストレージ系とかメモリ管理とかだと運用時にその問題が出れば、それこそ、今すぐに直せという眠れない系の対応が必要になってきて大変である。

まあ、とは言うもののSQLのバグでも単なる問合せではなく修正も必要な障害になると、再現確認するのに半日から一日、パッチを作るのに1日〜2日、リグレッションテストでの確認に一日、コードレビューに一日ということで最低でも一週間くらいはどうしてもかかってしまう。コードレビューは基本的には主要担当者および専門家という複数のレビューが必要である。

週一個のバグ修正というのが個人的なノルマで並行して何本もバグを見ていないとなかなか達成できないのが実状であった。

当時、日本オラクルにDDRのエンジニアが何人いたか正確には記憶していないが、わたしが一番年寄であった。わたしの担当がSQLというRDBMSの上半分なので、火事場の現場に放りこまれる事は少なかったが、それでも、若いエンジニアの精神的よりどころとして、いざとなったらよしおかさんという重しの役割ははたしていたかもしれない。

コードさえあれば、どんな問題でも、どうにかあたりはつけられる。そーゆー空気だけは醸しだしていたと思う。それが若手エンジニアや現場の営業、お客様に伝われば信頼感が出てくるのである。

専門家としてアベレージをキープしつつ安打を製造する。イチローのようなプログラマであったと思う。

デバッグ方法論

実践的なデバッグ方法論(デバッグの仕方、事例研究)も強く求められている。デバッガーというツール依存のTipsではなく、ソフトウェアのデバッグというプロセスそのものの形式化である。

人々は誰に教わるでもなく自分のデバッグのスタイルを持っている。自分なりな定石を獲得している。しかしそれを明示化して人に伝えようと試みる人は少ない。伝承がまったく不可能なような議論も少なくない。

わたしはオープンソースの時代こそデバッグの方法論を広く共有できるチャンスに満ちた時代だと考えている。いくつか事例を紹介しつつ解説する。

優れたプログラマは優れたデバッグ方法論を持つ。そのデバッグ方法論をぜひ共有化したい。そのためには情報公開が要である。

デバッグとはプログラムの不具合を修正するプロセスである。テストなどによって発見された何らかの不具合を期待する結果に修正する作業である。テストとデバッグの区別が十分ついていない初心者プログラマもいるが、これは明確に異なるプロセスである。テストは不具合を見つけるプロセス。デバッグはその不具合を直すプロセスである。

生産性の高いテストというのは単位時間あたりたくさんのバグ(不具合)を発見したテストであり、バグを発見したテストについては、テストに成功したというべきである。

一方生産性の高いデバッグというのは単位時間あたりたくさんのバグを修正したものである。

デバッグのプロセスというのは、不具合を認識(それは仕様だという場合もある)、現象を確認(再現方法の確認)、問題の理解、修正、直っていることの確認みたいな感じになる。

問題修正の部分だけをデバッグと狭義に捉える人もいるが、問題を理解しない限り問題は修正できないし、問題を理解するためには現象を再現し確認する必要もあるので、それらも含めたプロセスと認識するのが正しいと思う。

不具合というのは、ある入力に対して期待する出力(状態変移)と異なる出力という風に考えられる。期待する出力というのは、仕様を定義した人によって定義されるので必ずしも利用者のそれではないので、悪名高き「それは仕様です」ということが起こる。

それはともかく、ユメのチカラからデバッグ方法論についてのエントリをみてみよう。

プロセスプログラミングの実践方法
http://blog.miraclelinux.com/yume/2006/07/post_93da.html
デバッグのプロセスを記述することによって、デバッグのプロセスそのものをデバッグしようと言うことを提案している。プログラマとしての技量を向上させるにはデバッグ力(リョク)を向上させなければいけないが、その方法論としてデバッグのプロセスを記述し公開し共有することによって世界の誰かの目にふれさせバザール的に進化させようという試みである。

デバッグの話(昔の日記から)
http://blog.miraclelinux.com/yume/2006/07/post_b753.html
昔の日記(シリコンバレー日記)から引用している。

「ソフトウェア開発の非常に人間的な部分であるデバッグのプロセスをもっともっと深く理解したい。その思いは10年位前と変わらない。しかしながらこの10年で自分がどれほど進歩したかと言うと正直言って忸怩たるものがある。商用ソフトウェアを作っていた当時と比べて自分の専門性がどれだけ研ぎ澄まされたかと言うとほとんど進歩していないのではないだろうか。そう考えると道はとてつもなく長く険しい。

しかし10年前と現在で大きく変わったことがある。OSSとインターネットである。

10年前わたしが記述したバグ情報はすべてプロプライエタリな情報として企業の壁の中にあり同僚以外と共有することができなかった。わたしの書いたコードは門外不出だし、変更記録も、バグデータベースの記述ももちろん知的所有権の名の元に幽閉されている。

10年前はわたしとあなたは微視的なデバッグの記述を共有できなかった。

ところが10年たってわれわれはオープンソースと出会い、わたしはわたしのコードだけではなく、わたしのつたないデバッグのプロセスをあなたや世界中の誰かと自由に分かち合うことができるようになった。

なんていうことだ。

[中略]

OSSとインターネットというのはすごい環境である。」

本当にすごいことである。これを使わない手はない。自らのプログラマとしてのプロフェッショナルな価値を向上させるためにもデバッグ方法論・事例を公開し共有したいものである。

gdbの実践的使い方
http://blog.miraclelinux.com/yume/2006/09/post_fa59.html
「ソースコードの読み方」でも紹介したが、OSS定番のgdbの実践的使い方である。

トラブルシューティングの実際
http://blog.miraclelinux.com/yume/2006/10/post_5353.html
これも「ソースコードの読み方」で紹介したが、MySQLで\(半角)→\(全角)に化けるという問題(円マークが全角の\に化ける)についてどのように問題を分析していったかという事例である。問題領域の知識というのは必要であるが、そのトラブルシューティングの足跡というのは参考になると思う。

大規模ソフトウェアをgdbを利用して微視的視点から理解をする
http://blog.miraclelinux.com/yume/2006/09/post_8096.html
こんどはPHPでの問題である。同様に問題をどう認識して、ソースコードレベルで理解するかというプロセスを書いている。

コードを読むな、理解しろ
http://blog.miraclelinux.com/yume/2006/10/post_e3d6.html
rubyの実装をCPUキャッシュミスの観点からデバッグ(?)した事例を示している。oprofileを利用してL1キャッシュミスを計測しそれをチューニングしたというお話である。rubyの実装への実用的な価値はないのであるが、キャッシュミスをどう削減するかという事例にはなっているので参考になると思う。

PHPだろうがMySQLだろうがrubyだろうが、その構造の全般的な理解は必要ではあるが、ソースコードがあるんだから時間をかければ(早いか遅いか、上手か下手かはあるとしても)だれでも再現可能なプロセスである。

わたしはPHPやMySQLあるいは題材にしたrubyの実装についてはほとんど知らない。しかしC言語が読めて各種ソフトウェアツール(gdb/find/grep/xemacs/cscopeなどなど)が使えれば特に難しいことをするわけでもなく大抵のことができる。

コードを読むチカラ、コードを理解するチカラ。デバッグするチカラ。

OSSの時代にはそれらが強く求められている。

そしてインターネットとOSSのおかげでデバッグの方法論は世界中で共有できるようになったのである。素晴らしい世の中になったものである。

上で紹介した事例についてじっくり読んで自分自身のデバッグ事例についてぜひトラックバックで教えてほしい。世界はあなたのデバッグ事例を待っている。

チューニング

パフォーマンスチューニングというのも非常に重要な問題だ。黒魔術のようなかんじもしなくもないが、ヨタ話をいろいろ書いてみる。

性能の問題が表面化した場合、やみくもにパラメータをいじくりまわして問題を悪化させてしまう場合があるが、そーゆーことは避けたい。

何が問題なのか、定量的なゴールを明確化しないと、単なる感覚論になってしまって不毛な時間をついやすことになるので注意が必要である。

パフォーマンスチューニングの参考書はいろいろあると思うので適宜みつけだしてほしいが定番のこれはというのは、あるようでいてよくわからない。データベースのチューニングという題材での書籍はいろいろあるがいかんせん製品特有のTipsにかたよったものが多くてあまり汎用性がなかったりする。Oracleのパラメータを勉強するというのはそれはそれで必要なのだけど、わたしが目指しているものとちょっと違う。

ここでは一般的なアプリケーションのチューニングくらいの軽いノリのお話をする。

チューニングするくらいだから性能に満足していないという前提であるが、性能に特に不満がないのなら無理をしてチューニングする必要はない(当たり前だけど)。

性能とはここでは速度の事を言うことにするが、それ以外でもメモリ消費量だとか、ディスク消費量だとか別の次元でのチューニングというのもありえる。

CPU、IO、メモリなどはCPU時間、IO時間などを計測すれば、どこがボトルネックになっているかわかる。ロック競合の場合、CPUやIOはまだまだ余裕があるのにスループットが出ないなどの現象がでたりする。

いずれにせよ現状を正確に理解することが第一歩になる。

CPUボトルネックの場合、アルゴリズム、データ構造の改良などが必要になるが、そのまえに定量的な測定がかかせない。

速度を計測する基本は、時計である。実行にどれだけかかったかを計測する。それこそストップウオッチからはじまって、Linuxでは time コマンドを利用したりする。アプリケーションからであればgettimeofday()なんかを利用する。もっと精度をほしければTSC(time stamp counter)を利用するとよい。

実行プロファイルをとる。

linuxの場合oprofileが利用できるので、それを使おう。

ユメのチカラでは下記のエントリーが参考になる。

Rubyのプロファイリング
http://blog.miraclelinux.com/yume/2006/10/ruby_0b0e.html

実際にrubyの実装を題材にoprofileで計測し、ボトルネックを発見した事例を示している。

コードを読むな、理解しろ
http://blog.miraclelinux.com/yume/2006/10/post_e3d6.html

上記の性能チューニングのお話のまとめである。パッチの作り方も含めて事例を示している。ボトルネックを発見できれば、比較的簡単に解決策は見つかる。

もうすこし本格的なカーネルチューニングは以下である。

Linux Kernel 2.6.18とCache Pollution Aware Patch
http://blog.miraclelinux.com/yume/2006/09/linux_kernel_26_2c2c.html

2.6.18に採用されたカーネルパッチは下記のプロジェクトで作ったのだが、iozoneというベンチマークを実施し、oprofileでCPUキャッシュミスを計測した。そのボトルネックの部分についてカーネルパッチを作成し、効果を検証した。

キャッシュミスを発見するのはoprofileを利用すれば簡単にできる。ただ、その現象を解決するカーネルパッチの実装は(自分にとっては)簡単ではなかったが、パターンを発見したので今後同様の現象であれば、同じ方式で解決できる。

詳細については下記の報告書を参照されたい。

2005年度オープンソースソフトウェア活用基盤整備事業
「OSS性能・信頼性評価/障害解析ツール開発」
OS層
〜CPUスケーラビリティ評価編〜OS-cpu.pdfをダウンロード

ソースコードの読み方

ソフトウェア工学の標準的なカリキュラムにソースコードの読み方というのがあるのかないのか知らないが、プログラマとして最も重要な資質の一つにコードの読解力というのがある。

ついでに言えば、大学や専門学校であまり教えられているとはいえないけど、実践では常に必要とされているものとして、テストの方法論、デバッグの方法論、性能向上の方法論、メモリなど各種資源の削減方法論などなどがある。国際化、移植性なども重要な単元であるがソフトウェア工学の中で教授されていると言う話はあまり聞かない。コードのハック一般についてどこかで議論されているのだろうか。経団連あたりで議論しているのだろうか?

閑話休題。

ソースコードの読み方ということで、最近では「コード・リーディング」というそのものずばりの教科書も出ているので状況は好転しつつある。コードの読み方はオープンソースの時代になり、間違いなく広く情報を共有できるようになった。これはいいことである。時代の進歩といっても差し支えない。

カーネル読書会ではその道の優れたプログラマにお話を聞くが、わたしは時々、どうやってデバッグをしているかとか、どうやってコードを読むかというような質問をする。暗黙知としてハッカーがもっているものを言語化してもらってどうにか形式知にしたいと思っている。

しかし、そうは言ってもまだまだ職人芸の世界で、なかなか優れたプログラマの技法というのが形式知化されているとは言いがたい。定石を集めたいところである。

ユメのチカラでは下記のエントリを記した。

コードを読むな、理解しろ
http://blog.miraclelinux.com/yume/2006/10/post_e3d6.html

これはoprofileを利用してrubyをハックした事例である。コードを読むのは端から端まで直列で読んでいたらいくら時間があっても読みきれない。コードを読むには、コードを読まないテクニックが必要でそれを紹介した。ブックマークやトラックバックもいっぱいいただいた。

トラブルシューティングの実際
http://blog.miraclelinux.com/yume/2006/10/post_5353.html
実際にあった問題を、ソースコードの観点から理解するという事例である。使っている道具立てはgrep/findなどなど標準的なものばかりだ。別段トリッキーなことをしているわけではない。包丁とフライパンだけで料理を作るようなものである。職人は道具を使いこなす。その技を見てほしい。

なぜソースコードを読むのか?
http://blog.miraclelinux.com/yume/2006/08/post_3771.html
そのものずばりの話題について記した1999年ころの記事である。大聖堂のプログラマであったわたしがオープンソースの潮流に触れその可能性にわくわくしていた感覚がある。「ソースコードを読む。その基礎的な技術がオープン・ソースの時代には最も必要とされているのである。」と断言しているが、その確信は今でもゆるぎない。

下記は大規模ソフトウェアの効率的な理解という観点で記した。ざっくり通しで読んでいただければ幸いである。

大規模ソフトウェアの効率的な理解
http://blog.miraclelinux.com/yume/2006/08/post_cae5.html
「OSSの時代こそ大規模ソフトウェアの実装の効率的な理解の方法論が求められている。企業が自分が作ったソフトウェアを自社のエンジニアに教育(OJT)するのと違って、OSSはそのような内部構造の教育コースがない。自分のすぐそばにコア開発者がいないので簡単に聞くことが難しい。
中略
その実践的な方法論についていろいろ議論していきたいと思う。」

大規模ソフトウェアの効率的な理解(その2)
http://blog.miraclelinux.com/yume/2006/08/2_2d39.html
ソフトウェアの規模を下記のように定義した。
    規模         行数
    小規模       10万行以内
    中規模       10万〜100万行程度
    大規模       100万行以上
ソフトウェアを構成する行数でおおざっぱにくくっている。あるいは開発に関与する人数によっても同様にくくれる。
    規模         人数
    小規模       10人以内
    中規模       10人〜100人程度
    大規模       100人以上

大規模ソフトウェアの効率的な理解(その3)
http://blog.miraclelinux.com/yume/2006/08/3_dc26.html
規模の把握。

大規模ソフトウェアの効率的な理解(その4)
http://blog.miraclelinux.com/yume/2006/08/4_4b7e.html
巨視的、微視的な理解という観点を提示している。

大規模ソフトウェアの効率的な理解(その5)
http://blog.miraclelinux.com/yume/2006/08/5_de60.html
「動的というのはソフトウェアを実行した時の挙動のことをさし、静的というのはソフトウェア(プログラム)の字面をさす。」
動的理解、静的理解という側面から解説した。

大規模ソフトウェアの効率的な理解(その6)、リグレッションテスト
http://blog.miraclelinux.com/yume/2006/08/6_570e.html
「OSSの実装も単にソースコードやドキュメントを整備するだけではなく、リグレッションテストをどれだけ充実するかという視点で議論、評価される時が来ているように感じる。よりOSSが大規模になり、修正が頻繁に求められるようになるとリグレッションテストが整備されているかいないかで、その変化に対する対応力が全然かわってくるのである。」

gdbの実践的使い方
http://blog.miraclelinux.com/yume/2006/09/post_fa59.html
gdbをデバッガとしてしか利用していないとしたらその威力の10%も利用していない。gdbはソースコードを読むためのツールである。「gdbはソースコードの理解を助ける偉大なツールなのである。」

gdb/xemacs/cscopeの使い方
http://blog.miraclelinux.com/yume/2006/09/gdbxemacscscope_e0da.html
「プログラムの状態は変数の値の変化によって変化していくわけだが、変数は、宣言され、値を代入され、参照されるなどして利用される。」

おまけ:
カーネル読書会とよしおかの野望
http://blog.miraclelinux.com/yume/2006/07/post_69b1.html
「ソースコードを読むことは楽しい。そういうと、多くの人は怪訝な顔をする。無理強いはしないしするつもりもないし、もちろんできないのであるが、ソースコードを読むことが楽しいということを少しでも多くの人に伝えたくて、あるいはそのような同好の士を発掘したく、ぼそぼそと続けている。」

本日のエントリーはソースコードの読み方という観点からまとめてみたが、テストの仕方、デバッグの仕方、性能問題の発見とチューニングなどなどについてもいつかは記していきたいと思う。コメント、トラックバックなどをお待ちする。


追記:
はてなブックマークを多数の方に付けていただいている。(これを書いている時点で100を越えている。)どうもありがとうございます。下記も参考になると思う。
大規模ソフトウェアをgdbを利用して微視的視点から理解をする
http://blog.miraclelinux.com/yume/2006/09/post_8096.html
gdbを利用して、どのようにソースコードを理解するか事例を紹介している。実際にあった事例なので、瑣末なめんどくさい事も含めて参考になると思う。現場はそのような瑣末なことがらにみちみちているのである。

カーネル読書会のおしらせ(第79回)

日時:8月23日、18時半開場、19時ころ開始
会場:ミラクル・リナックス、セミナールーム

お題:Fault Injectionについて
発表者:美田さん
Fault Injection はエラーをわざと起こし、通常テストすることが難しいエラー処理の部分をテストするためのフレームワークです。このしくみや使い方の説明、これまでにこれを使って検出したバグなどについて話す予定です。

18:30頃、開場
         Lightning Talks
19:00頃、お題開始
20:30頃、懇親会開始

場所はいつもの、ミラクル・リナックス社セミナー会場地図
http://www.miraclelinux.com/corp/about/maps_google.html

今回は一人5分の LT (lightning talks) も募集します。
LT発表希望の人は直接わたしまでメールでお題をください。

開場した後は、だらだらと自己紹介やらLTやらをやりますので、時間の許す限り早めに来た方が面白いお話をきけるかもしれません。

会場で、ピザとビールの懇親会つき。(予定価格1000円)
懇親会参加希望の方は、懇親会参加と明記してください。

登録はいつもの宴会君
http://utage.org/enkai/
宴会コード kernel070823

会場の都合で35名で締切ます。

LL魂

夏の祭典。LL Spirit (LL魂)  に行ってきた。

個人的な感想など。

昨年のLLゴングのパイプ椅子は、おじさんには拷問に近いものがあったが、今年のホールの椅子は適度に座り心地もよく快適であった。実行委員会の皆様、ご苦労様でした(ぺこり)。

和田先生は、あいかわらづお元気そうでなによりだった。ステーブンレビーのハッカーズの話からはじまって(この本はハッカー倫理を知るうえで重要なテキストなのである)、ハッカーズ大辞典などを紹介しつつ、ハードウェアハック(微分機械(?)って何みたいな)のお話など、大変楽しい講演であった。帰宅してから先の2冊を本棚からとりだしパラパラめくったのは言うまでもない。



しかし、オレ様言語の作り方でパネルディスカッションができちゃうほど日本という地域にはオレ様言語をつくっている人がいっぱいいるのね。すげーな、本音できたよ。という感じである。

学校でコンパイラの作り方とかは習うけど、オレ様言語を作ってしまえというような危険思想をうえつけられるということはまあない。オトナの事情というやつで、研究職に進む人には、言語では論文とおらないよ(これが殺し文句)、企業に行く人には、言語では食えないよ(これも殺し文句)。大抵はそれであきらめるのが良い子の姿である。

それにもかかわらづ、わらわらとオレ様言語一派が勃興しているのは、やはりRubyのまつもとさんの影響に違いない。諸悪の根源はまつもとである。

オレ様言語どころかハリボテOSと称してオレ様OSまで作ってしまう輩もわらわら居て、日本という地域の将来を深く憂えるものである。(これはまた別の話)

人の話を聞いていると、なかなか楽しそうである。オレ様言語という自分が神の立場になって、すべてを決定する世界観こそプログラミングの醍醐味のような気がしなくもない。(いかんいかん、だんだん危険思想にそまりつつある)。しかし寝る間もおしんでそんなことをしたら、体に悪そうだ。睡眠不足におちいりそうだ。仕事にも影響があるかもしれない。と考えるのがフツーのオトナである。

自分の世界観をオレ様言語に投影するというのは、これはやってみたものだけしかわからない快感があるらしい(伝聞)。危険な世界だ。麻薬みたいなものである。(とは言っても麻薬をやったことがないので、よくわからないのだけど)

自分も高校生くらいのときに、なんの役にたつのかわからないただプログラミングが楽しいというだけのプログラムを作っていたわけだが、モノ作りの原点というか何かを作りたいという欲求に素直になればオレ様言語作りというのも究極の趣味のような気がしないでもない。プログラミングを目的にしちゃいかんと、一方のオトナのわたしが囁くのであるが、一方のチョイワルオヤジ(死語)のわたしが気持ちイイことして何が悪いと囁くのである。和田先生なんて、一生(?)好きなことをやっていて世間から後指をさされていないではないか、そんな生き方もあるではないか、などと思ってしまう。

しかし、ただでさえ時間がないのに、人生のプライオリティのなかで、こーゆー無限地獄の趣味を持ってしまっていいのだろうか(オトナの判断)。しかし、金はかからないし、ギャンブルにあけくれて家庭崩壊ということではないし、まあいいんではないだろうか(悪魔のササヤキ)。と揺れ動くオヤジ心なのである。

LL魂というのは人の魂をわし把みにしてぐわんぐわん揺振るイベントなのであった。

恐しいイベントである。

(通勤電車の中でニヤニヤしながらオレ様言語を妄想していたというのはナイショである。)

LL Spirit 感想。トラックバックリスト
http://karetta.jp/article/blog/ll-spirit/132858/trackbackList#trackbackList

The Practice of Programming (プログラミング作法)

先日、K&RのThe C Programming Language (プログラミング言語C)は初心者が読む教科書としてはいただけないと紹介した。では、お勧めは何か。

ずばり、The Practice of Programming (Addison-Wesley Professional Computing Series)を推薦したい。(日本語訳はプログラミング作法である)

テスト、デバッグ、移植性、性能、設計の選択、スタイルなどのテーマ(プログラミングの実践(Practice of Programming))という計算機科学の授業でまともに取り上げられなかったものを取り扱っている。

移植性の解説で、国際性(Internationalization)の項目を発見したとき、ああやっとK&Rの呪縛から逃れられるかもしれないと思ったものである。

If one lives in the United States, it's easy to forget that English is not the only language. ASCII is not the only character set, $ is not the only currency symbol, dates can be written with the day first, times can be based on a 24-hour clock, and so on.

(米国に住んでいる人は、英語が唯一の言語ではなく、ASCIIだけが文字セットではなく、$だけが通貨記号ではなく、日付は日から記述できるし、時刻は24時間でも表現できるということを忘れがちだ。)

一般的な入門書に国際化についての記述を発見し、ああ、国際化というのがプログラムが持たなければいけないいろいろな性質のうちの一つになったんだなあと感慨深く思ったものである。

まあ、それはともかく、デバッグ、テスト、性能、移植性などプログラミング言語の教科書ではなかなかお目にかかれない項目でありながらとっても重要な事柄について真正面から取り組んでいるこの本はお勧めである。

The C Programming Language

プログラミング言語Cの教科書の定番と言えば、カーニハンとリッチーによるものが有名だ。K&Rと呼ばれていて、今だにそれを推薦する人もあとをたたない。

わたしの本棚にも2nd editionがある。黄ばんだ表紙の奥付を見ると95/8/12とメモしてある。渡米してすぐリファレンスとして購入したものだ。

プログラミング言語の入門書で最初の例がなにがなんでもhello, worldというもの、K&Rからの悪しき慣習である。

プログラミングの初心者が、プログラムをどう書くかという事を習う教科書として使うにはいただけない。いただけない理由は多分いくつもあるかと思うのだけど、プロフェッショナルから見てもいただけない記述がいっぱいある。

例えば if (c >= '0' && c <= '9') ... とかいうイディオムとか、 c - '0' なんていうイディオムがいたるところ(?)にでてくるのであるが、この手の文字コード(ASCII)に依存したソースというのが、後にソフトウェアの国際化という観点から否定されていったという歴史を知るものにとって、諸悪の根源は、ここにあったのかという思いである。

最初に習ったソースコードにそのようなイディオムがあれば何の疑問もなくそれを繰り返す。それを後から泣きながら直していくというのが国際化の歴史だったような気がする。

プログラムから文字コードの仮定をとりのぞく。文字コードが7ビットであるという仮定をとりのぞく。文字コードが一バイトであるという仮定をとりのぞく。言語(英語)や文化にまつわる様々な仮定をとりのぞく。

プログラムから文字集合に関する情報をとりのぞくのが文字集合独立(Character Set Independent)なプログラムなわけであるが、そのような概念が成熟していなかった時代の歴史的な著書として歴史学者的な観点から読みとくのが正しい読み方かと思うのである。


下記はお薦めである。

昔の日記にも似たようなことを書いていた。(10年以上前のお話)

96/02/20 シリコンバレー日記 ソースコードを読む程忙しい
http://web.archive.org/web/19991005060157/http://www.best.com/~yoshioka/d/96/02/i960220.html

(文字コードをshift JISにして読んでください)

人月の神話と大聖堂とバザール

人月の神話を先日読みかえしたので、今度は「大聖堂とバザール」を読みたくなる。「大聖堂」で自分のはてな日記を検索してみると

蕎麦屋
http://d.hatena.ne.jp/hyoshiok/20060808#p1

大聖堂とバザール
http://d.hatena.ne.jp/hyoshiok/20040622#p2

というのを発見する。前者はどうでもいいよた話であるが、後者はそのものズバリという感じのものである。

山形浩生のCathedralを伽藍と訳すのは、どう考えても誤訳に近いと思う。世間では「伽藍とバザール」でとおっているが、わたしはあくまで「大聖堂とバザール」というタイトルにこだわる。人月の神話での挿絵は伽藍ではなく大聖堂だと思う。「大聖堂とバザール」に対するわたしのコメントを書く前に紙面が尽きてしまった。(うそうそ)

なぜソースコードを読むのか?/ユメのチカラ
http://blog.miraclelinux.com/yume/2006/08/post_3771.html

人月の神話

Frederick Phillips Brooks Jr., "The Mythical man-manth: essays on software engineering", Anniversary edition. フレデリック・P・ブルックス Jr.「人月の神話」新装版、狼人間を撃つ銀の弾はない。滝沢徹他訳

わたしが紹介するまでもなくソフトウェア開発の古典中の古典である。先日の「情報システム学会(ISSJ)、情報システムのありかたを考える会」での発表のために、久し振りに読みかえしてみた。

原書は1975年に出て、長いこと読み継がれてきて、今だにその指摘は古びていない事に驚かされる。16章からは、初版以降に書かれた論文、評論になるが、やはりこの書の本質は、初版時点で書かれた1章から15章であろう。

第1章「タールの沼」。大規模システムプログラム開発がタールの沼にはまってもがき苦しむ、恐竜やマンモスみたいなものだと記している。今でも、そのようなプロジェクトは枚挙に暇がない。ソフトウェア開発の難しさを端的にあらわしている表現である。

「新聞を読んでいると、二人のプログラマが改装ガレージで、大開発チームが最大限の努力で作り上げたものを凌ぐ重要なプログラムをいかにして作成したか、という記事をたまたま見つけることがある。(中略)
それなら、どうしてソフトウェア産業の開発チームはそうしたひたむきなガレージ二人組にすべて取って代わられてしまわないのだろうか」(第1章、4頁)

ソフトウェア製品とプログラムの作成の本質的な違いは、前者にはマニュアル、教育、サポート、継続的なアップデートなどがついていて、後者は単なる実行可能なプログラムというところにあり、前者を製作するにはプログラムを作るより大変な工数がかかるということにある。

ソフトウェア工学の歴史は、大規模なソフトウェア製品をいかにしてタールの沼にはまらないようにして作るかという歴史に他ならない。

「ソフトウェア産業がガレージ二人組に取って代わられてしまわない」というBrooksの指摘はある面、正しかったが、一方でインターネットやオープンソースソフトウェア(OSS)の発展は、「ガレージ二人組に取って代わられた」事例のようにも見れる。

1975年の時点で、世界(地球)規模のソフトウェア開発環境は存在しなかったし、それを見通すということは、Brooksであっても不可能である。しかし21世紀になって、地球規模のコラボレーションが可能になり、コミュニティによる開発というのが、ソフトウェア産業を取って代わるほどの影響力を持ちはじめているという点は指摘してもいいと思う。

確かに単一の銀の弾丸はなかったかもしれない。しかし、インターネットというメディアとコミュニテーによる開発というのは、「ガレージ二人組」が世界にインパクトを与える可能性がある事を示した点で意義深いものである。

Brooksはプログラミングがなぜ楽しいかという事も記している。

  • 物を作り上げる純粋な喜び
  • 他の人々に役立つものを作ることの楽しさ
  • 複雑なパズルのような組み立て部品を完成させ、それが巧妙に転回するのを眺めるおもしろさ
  • つねに新しいことを学ぶという喜び
  • 非常に扱いやすいメディア(媒体)で作業する喜び。その上、プログラムというのは、詩人の言葉と違って、現実に動いて働きだす

一方で、プログラミングの苦しさも記している。

  • すべて完璧にこなさなくてはならない。呪文の一字一句たりとも正しくなければ、魔法は使えない。
  • 壮大なコンセプトをデザインするのは楽しいものの、シラミの卵ほどの微細なバグを見つけ出すのはそれこそ単純労働だということである
  • あれほど長い間苦労してきた製品が完成時(またはそれ以前)には時代遅れに見えてしまうことである

OSSにかかわる多くの人は、プログラミングに楽しさを見いだしている。一方でプログラミングの苦しさを上手に回避している。一人で膨大な単純作業をやるのは苦しいが、コミュニティで開発すれば、それも苦ではないという事かもしれない。喜びは参加者の分だけ倍増し、苦しみは参加者の分だけ割引かれる。

Brooksの「人月の神話」は読めば読むほど味がでてくる名著である。

まだ読んでいない若い技術者にはぜひ読んでほしいと思う。強くお勧めしたい。

情報システム学会(ISSJ) 情報システムのありかたを考える会

情報システム学会の「情報システムのあり方を考える」会に参加した。

オープンソースソフトウェアの潮流というタイトルで小一時間ほど放談をさせていただいた。特に目新しい事を述べたわけではないが日頃考えていることを好き勝手にお話しした。いろいろなコメントをいただいたが、皆様どのような印象をおもちになったか興味深いところである。

OSSの可能性として、日本のこれから会社を停年退職するシニアエンジニアの皆様が、コミュニテーベースの開発に参加する事をわたしは期待している。日本の重厚な人材の集みを利用した世界貢献であり、それによって、日本という国が、単に経済的に豊かなだけではなく、人という宝があり、技術的にも優れているということを示す大変なチャンスだと思う。それは世界からも尊敬されるような日本モデルになるのではないだろうか、というような妄想を語ったのだが、諸先輩がたにはどう映ったのだろうか。おかしなやつだと思われただろうか。

だけど、わたしのようなおかしな奴が少しでも増えてくれば、少子高齢化の社会もちょっとはおもしろ可笑しく過せるし、何よりも団塊の世代とよばれる人々の楽しみも少しは増えるのではないだろうか。コミュニティの構成員が増えることは悪いことではないしベテランの参入は間違いなく良いことだし、それによって、コミュニティの価値も高まる。誰も損をしない、みんなが得をするモデルだと思う。

まあ、放談は放談で、「情報システムのあり方を考える」会にどれだけ役にたったか多いに疑問ではあるが、「情報システム」作り方としてコミュニティによるバザール開発みたいなモデルがあるということはご紹介できたのではないかとも思ったりする。

この発表のためにBrooksの「人月の神話」を久し振りに読んで、Brooksのパラダイムとは全く異なるソフトウェア開発パラダイムがあるということを自分自身再確認した次第である。

追記:参考までに発表用スライドをアップロードした。issj.pdf(発表用スライド)をダウンロード

カーネル読書会のめざすもの

YLUG(横浜Linux Users Group)カーネル読書会FAQページがあまりにも古いので更新しようと思ったのだが、どっから手をつけていいやら。

この手のFAQは個別のエントリに回答を重ねて更新する事はもちろん可能なのだが、ロードマップというかカーネル読書会をなぜ開催したいと思ったのかとか、なぜ続けているのかとか、どうしたいのか、とかいう明確な意志の表明なんかがあるといいかもしれないと思った。企業のビジョンステートメントみたいなものである。

おいおい、たかが趣味の世界でビジョンステートメントはいくらなんでもやりすぎだろう。大袈裟すぎやしないか、という声もある。そう思う人もすくなからづいそうだ。わたしもそう思わなくもない。

コミュニティ(?)のビジョンとかミッションというのは通常明文化されないし、されたためしも(ほとんど)ない。LinusのJust For Funという書籍は、ある意味その手のものかもしれないけど例外である。あ、StallmanのGNU Manifestというのがあるなあ。これは例外中の例外だ。

まあ、楽しいから続けていたら続いちゃったというのが本当のことであるが、どうせなら試しに、カーネル読書会にまつわる「よしおかの野望」を明示しておこうと思う。

わたしは、90年代中頃、シリコンバレーの大手データベースベンダーでRDBMS(リレーショナル・データベース管理システム)の開発をしていた。シリコンバレーのフリーペーパーには各種ユーザー会や勉強会の日程が載っていて、その量とバラエティに圧倒された。プログラマとしてプロフェッショナルな道を歩むために、ぜひその手の会合に出ようと思った。機会をみつけて参加したいと思った。たまたま参加した、SVLUG(Silicon Valley Linux Users Group)の活気、熱気には圧倒されたことを鮮明に覚えている。

会社の壁とか人種とか国籍とか性別とか年齢とか、そんなもの一切合切関係なく、ひとつのことについて自由に語りあっている場というのが、どんなにか素晴しいかというのを実感した。

99年に日本に帰ってきて、自分の生活圏にそーゆー場があったら素敵だなと思った。

これからはオープンソースでしょ。みたいなノリもあった。

自由命みたいなノリもあった。

自分が勤めている会社とは対極にあるムーブメントにしびれていたのである。

日本に帰って、たまたまYLUGというのを発見し、早速メーリングリストに参加した。特に会費も会則もないのが気にいった。時々宴会をしているらしい。楽しそうである。

そこで、カーネルのソースコードを読む宴会(?)というのを提案したところ、あれよあれよという間に参加者が集まって第一回のカーネル読書会が開催されたのである。

前半の勉強会形式のディスカッション、後半の宴会という黄金のパターンも第一回で確立された伝統芸みたいなものである。

当初は結構地味にソースコードを追っていたのであるが、何度もやるとさすがにあきるし、準備も大変なので、もちっとお気楽に行こうということで、お題提供者が適当にお題を披露する形式になった。

第8回から場所を渋谷マークシティのサンブリッジのセミナールームにうつしてそれが2001年末まで続き、その後天王町(保土が谷)OSDLジャパンの会議室で2004年にOSDLが引越すまでお世話になった。その後、固定した会場をもたない流浪の旅がはじまったのだが、NTTデータ、ミラクル・リナックス、日本SGI、日本HPなどおかりして開催し現在にいたる。
YLUG年表参照(http://www.ylug.jp/modules/pukiwiki/index.php?history)

時々出張か〜ねる読書会というのをやって新規参加者のリクルーティングをやっているのだが、なかなか思うように参加者が増えない。特に若い人と女子が少ないというのが構造的な問題だと認識している。やはり新規参加者が少ないとマンネリ化してしまうし刺激が少ない。

YLUG年表を見ると、よくもまあこんなにバラエティのあるお題を継続してやったなあと思う。発表者と参加者の皆様に心より感謝したいと思う。また会場を提供していただいた関係各位にも深く感謝したい。どうもありがとうございました。(ぺこり)

一つ一つの発表に思い出がつまっている。どれも大変楽しかったし、勉強になった。多くのことを学んだ。感謝につきない。そんなこんなで現在まで続いているのである。

と、ここまで書いていて、歴史を振り替えるところで力が尽きてしまって、「よしおかの野望」を記すまでには行かなかった。カーネル読書会のめざすところは次に記すことにする。(続く)

Community Based Development

オープンソースソフトウェア(OSS)の力はバザールモデルとして知られるコミュニティによる開発(Community Based Development)だと思う。

OSSの特徴としてフリーなライセンス(利用、変更、再配布の自由など)があげられる事が多いが、それはあくまで必要条件であって、十分条件ではない。ライセンスをフリーにしたからと言って、コミュニティが自然発生するとは限らない。商業ソフトウェアベンダは自社製品をプラットフォームとするために、あの手この手を使ってコミュニティを形成しようとするが、それには相当なコストと時間がかかる。

大雑把にソフトウェアを分類してみる。

最初のカテゴリは、プログラム。これは実行可能なソフトウェアで、趣味で作ったり学校の課題で作ったりする小規模なものとする。規模も小規模でせいぜい大きくても数千〜数万行程度のものである。おもちゃのプログラムに毛がはえた程度のものだ。もちろんサポートもなんにもないし、商業的な価値を見いだすことも難しい。

その次は、ソフトウェア製品。これは商用、非商用にかかわらず、ある程度のドキュメントと、利用者がついて、継続的に修正、改良されているソフトウェアである。製品というと商用のイメージがつきまとうが、他にいい名前を思いつかなかったので、とりあえずソフトウェア製品とここでは言うことにする。ブルックスはプログラミングシステム製品と呼んだが、わたしにはちょっとピンとこなかったので、ここではソフトウェア製品と呼ばせてもらう。非商用のソフトウェア製品というのが、ブルックスの時代(60〜70年代)には一般的ではなかったが、オープンソースの時代になって、星の数ほどでてきた。

最後は、ソフトウェアプラットフォーム(プラットフォームと略すことにする)。多くの利用者がつき、その上で重要なアプリケーションが稼働するようになる。あるいは、そのソフトウェアに依存するようなソフトウェアが多数生まれてくる。Linuxはまさにプラットフォームである。コンパイラのgccもプラットフォームと呼んでもさしつかえないと思う。商用製品で言えばデータベース管理システムのOracleもプラットフォームと呼べるだろう。そしてプラットフォームにはコミュニティの形成、存在が必要不可欠なのである。

上記の分類はあくまでざっくりとしたイメージで各カテゴリに明確な線引きがあるわけではない事をあらかじめお断わりしておく。

成功したOSSを見てみると、一人のプログラマの趣味からはじまったプログラムが、ある日誰かに発見され、利用が口コミで広がり、ドキュメントなどが整備されていって、それとともに、利用者、開発者コミュニティなどが自然発生的に生じ、ソフトウェア製品と言ってもいいほどになり、その後、そのソフトウェアを前提としたプログラムないしソフトウェア製品が次々と出てきて、商用サポートやトレーニングを提供する企業や、解説書の出版などがあいつぎ、プラットフォームの地位を確立するという発展をとげている。

Rubyというプログラミング言語を例にとると、93年にまつもとゆきひろ(Matzと呼ばれている)が自分の趣味で楽しいから自分用プログラムを作ったのが発端である。fjというインターネットのNewsシステムで発表され徐々にひろまっていったのが90年代後半である。最初のRubyの参考書が出版されたのが、99年で、英語の書籍は2000年である。2001年には初のRuby Conferenceが米国で開催され、2004年にはRuby on Railsという開発フレームワークが発表され、現在大ブレーク中という事である。

Rubyの開発は、当初はまつもとが一人で行なっていたが、徐々にメーリングリスト等でのバグの指摘、パッチの投稿など、まつもと以外の貢献の比率が増えてきて、より先進的な機能を実装するプログラマや、Sun MicrosystemsやMicrosoftに代表する大企業の開発者の参入など、開発者の層もひろがってきている。

Rubyはまつもとゆきひろが開発したソフトウェアであるが、徐々に彼以外の開発に関する影響力が増えているというのも事実である。

Rubyはプラットフォームと呼んでもさしつかえないだろう。プラットフォームには健全な開発者および利用者のコミュニティが存在する。

先日のRubyKaigi 2007キーノートスピーチ(感動的な素晴しいスピーチであった)でDave Thomasは、コミュニティが、その発展によってどのような影響を受けるか、そしてどのように対処するべきかということをユーモアを交じえて熱く語っていた。
http://jp.rubyist.net/RubyKaigi2007/Log0610-S5.html

Rubyは成長している。ティーンエイジのように気難しいが、親はその健全な成長を望んでいる。Rubyにはまつもとゆきひろ(Matz)とコミュニティというよい両親がいる。コミュニティは素晴しい。最近ではRubyはデートもしている。Rubyに迫りくる危機というのもある。爆発的な成長が新しい人を沢山呼ぶ。Rubyのお作法を理解していない人達もいっぱい来る。新しい人々を歓迎する準備をしよう。彼らから学ぼう。

愛に満ちたスピーチであった。成功したオープンソースソフトウェアはコミュニティに依存している。開発はコミュニティに依存している。新規参入者も排除されない懐の深さがある。分断の危機もあるが、それを乗り越えたコミュニティは強い。Rubyコミュニティはまさにそのような岐路にいる。

これは奇跡である。まつもとゆきひろという人間のパーソナリティがそれを可能にした。

Rubyはコミュニティによって開発されているというと、まつもとは相当違和感を持つかもしれないが、もはや彼の力の及ばないところで車輪が動きはじめているというのも事実なのである。彼が最も影響力のある人物である事は間違いないのだが、ティーンエイジのようにRubyは一人歩きをはじめて、その流れは、もはやまつもとですらコントロールできないところまで来ているのである。

コミュニティをコントロールする事は誰にもできない。しかし強い影響力を持つことができる。影響力はコミュニティに対する深い愛と貢献によって得られる。現時点で、最も影響力の大きいのは彼であるが、彼の右腕と呼べる何人かのハッカーが育ってきているのも事実ではある。

わたしはRubyの成長のプロセスを見て、かつてLinuxが発展していった姿に重ねあわせて見た。まつもとはLinusになる必要はないしなるべきではないとは思うが、linuxがたどってきた道はRubyのコミュニティにとっても大変参考になると思う。

RubyKaigi 2007には400人強の参加者があった。世界中から集まった。今後はSIベンダーやハードウェアベンダーのネクタイを締めたおじさんたちもいっぱい参加するようになるだろう。

Rubyのお作法、OSSのお作法を知らない傍若無人なやからも大挙することであろう。しかし、たとえそうであってもlinuxが上手に立ち回ったように、Rubyも上手にいなすと思う。

Community Based Developmentの奇跡である。ビジネスパーソンはこの価値の創造メカニズム、ソフトウェア開発方法論について理解を深めた方がいいと思う。わたしのミッションは、彼らにCommunity Based Developmentの革新性、有効性、持続可能性についてを伝えて、この波に参加することが彼らのビジネス(経済的な利益)にも繋がりうるということを理解させることである。

コミュニティは新しい人達の参入を歓迎することによって、さらに学び発展する。

愛だよ、愛。


6年前、アメリカでfirst Ruby Conferenceで私が受けたStanding Ovationを今年は日本でDave Thomasに返すことができてとても良かった、という話。

こういう話を聞くにつれ、Daveのキーノートは本当に感動的だったんだなあ、と思う。ただ単に「面白い話」では、人の心は動かない。彼が真摯に愛について語ったからに違いない。

Matzにっき


日曜のDave Thomasの講演の時に総立ちになったとき、思い起こしたのはもちろんあの日のことでした。Dave Thomasへのstanding ovationは、6年の歳月を経て、海外のRubyistからもらった賛辞に対しての、日本のRubyistからのお返しを象徴するものだと思います。2001年は40〜50人くらいだったように記憶していますが、2007年は約400人もの参加者がいました。ほぼ10倍です。ここまで大きくなったのは、6年もの間、まつもとさんと内外のRubyistたちが行ってきた努力や貢献の賜物以外の何物でもないでしょう。海外への普及の最重要人物であるDave Thomas氏に対し、残念ながら(とてもとても残念ながら)同席できなかったまつもとさんに代わり、盛大な拍手を返すことができたのは、Ruby communityにとって非常に意味のあることだったと思います。

6年後のStanding ovation/思っているよりもずっとずっと人生は短い。

NDD (Nomikai Driven Development)

昨日、日本SGIソリューション・キュービック・フォーラムのOSS/Linux パネルディスカッション−第4回目『OSSはビジネスの道具。もっとクリエイティブな作業を 』に参加した。

モデレータの高澤さんとは旧OSDL時代からのおつきあいで彼の要請であれば出ないわけにはいかない。カーネル読書会の会場にSGIホール(恵比寿)をお借りしているのでおなじみの方も多いと思う。

さて、自己紹介のあと、日本のIT産業が学生や若い人に人気のない3K職種じゃないかという刺激的な横河フィールドエンジニアリングサービス株式会社の丸茂さんのお話から口火を切ったのだが、とりあえづそれを受けてのわたしのお話が下記のNDDだ。

わたしは、カーネル読書会とかいろいろな勉強会で若いWeb2.0系にお勤めの人とお話をする機会があるのですが、彼らは本当に仕事が好きで、毎週金曜日に飲み会かなんかをよくやるそうで、そうすると仕事が好きなものだから、仕事の話になっちゃって、朝までブレーンストーミングみたいな感じになるそうです(若いから朝までオールでもへいちゃら)。そんでもって、いいアイデアかなんか出ると(飲み会の時は自分は天才じゃないかなんてよく思うもんなあ)、そのまま会社に戻って、土日つぶしてちゃかちゃかプロトタイプ作って月曜日にデリバーですよ。アイデアから実装まで数日。まあ、飲み会ドリブンデベロップメント(NDD)ですね。

一方で従来型の開発だと要求定義に半年、実装に半年、テストに半年とか、そーゆー単位で、今回の開発は速くて数ヶ月だったなんていく感じです。経験というのは何回そのサイクルを回したかできいてくるので、2週間で一回経験値を積むのと2年で経験値を積むのでは、その学習曲線の立ち上がりが全然違う。

さらに言えば、mixiなんてのはバタラさんが一人で自分のPCでプロトタイプ作って、会社の人に見せて、10人ユーザで、そのユーザが友達招待して100人で、その次1000人で、1万人、10万人、2年半で500万人ですよ。つい最近1000万人突破っていうプレスがでてましたけど、3年で1人から1000万倍スケールしちゃったわけです。1000万ユーザの基幹システムというのはあるけど、ユーザが10倍になるというのを設計時点で作りこんでいるというのはほとんどない。開発の方法論がまったく違う。mixiはミッションクリティカルシステムではないけど、そーゆーシステムの作りかたが従来のSI現場とは違うところでおこっている。

先週末RubyKaigi2007というのがあって、プログラミング言語のRubyというのがあって、まつもとゆきひろさんという人が一人で作ったんだけど、その会議に400人参加していて、情報を交換している。オープンソースの場合、技術情報というのは社内にあるのではなく、社外にある。自分の問題と同じ問題を持っている人は社内にいるのではなく社外にいて、そーゆー人たちとカジュアルに気楽に情報交換をして教えあっている。コミュニティベースで開発して助けあっている。そーゆー勉強会がいたるところにあって、情報共有をWeb2.0系の人たちは自然にやっている。

その人達の学習曲線は驚異的で一年もたてば、その道のエキスパートになっている。そーゆー世界がいまここにあるのだけど、なかなか大手企業の偉い人たちには、彼等のレーダにはそーゆー世界の話がうつっていない。

わたしが言うとすぐに大企業批判みたいに受けとられちゃうけど、そうではなくて、聞いたこともないちっちゃな会社と大手企業のコラボレーションができたらおもしろいなあと。

日本という地域でもっともっとコミュニティーベースの開発というのを根付かせたい。企業の壁をのりこえた開発の素晴しさ。それば企業にとってもビジネスになるし、利益にもなるということをもっと訴えたい。

というようなヨタ話(記憶にもとづいて書いているので相当脚色構成あり)をかましたのだけど、伝わっただろうか。

パネルで話したエピソードのまとめ。(順不同)

従業員意識調査のはなし。(人手が足りないという状況と、会社をもっともっと良くするために貢献したいというモチベーションの高い従業員)
人材/ユメのチカラ

http://blog.miraclelinux.com/yume/2007/01/post_6962.html

mixiのスケーラビリティのお話。(たくさんブックマークされている(58個))
500万倍のスケーラビリティ/ユメのチカラ
http://blog.miraclelinux.com/yume/2006/07/post_7ad0.html

mixiのスケーラビリティをささえるアーキテクチャ。
LiveJournalのアーキテクチャ/ユメのチカラ
http://blog.miraclelinux.com/yume/2006/07/livejournal_a718.html

金曜日の飲み会でアイデアを得て土日開発し月曜日に公開するという、おじさんには理解不能なスタイル。
Web2.0時代のソフトウェア開発のスピード/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/04/web20_5b1a.html

国内OSベンダーでISO/IEC 15408を取得しているのは弊社だけ。歯を食いしばってもOSを作らないといけない。
ISO/IEC 15408の取得/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/02/isoiec_15408_6bd3.html

ISO/IEC15408認証を取得しました/アジアのペンギン
http://blog.miraclelinux.com/asianpen/2007/02/isoiec_15408_e90c.html

Linux Kernel 2.6.20を開発した人の所属はどこかを調べた記事の紹介。それによると日本の企業でリストにはいっているのはMiracle Linux1社だけで、18位であった。
Who wrote 2.6.20? 誰がlinux 2.6.20を書いたのか?
http://blog.miraclelinux.com/yume/2007/06/who_wrote_2620__4b18.html

RubyKaigi 2007については下記
日本Ruby会議2007/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/06/ruby2007_cdaf.html

RejectKaigi2007/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/06/rejectkaigi2007.html

ムーアの法則を理解すること(その2)

アーキテクチャの設計寿命でもふれたが、Alpha AXPのアーキテクチャの設計ゴールは下記のとおりであった。
http://blog.miraclelinux.com/yume/2007/02/post_e9f1.html

   1. 高性能
   2. 寿命が長い事
   3. VMSとUnixが動くこと
   4. VAXおよびMIPSからの容易なマイグレーション

1と2については達成されたと考えていいだろう。3および4はDECが当時おかれていた状況から考えてまっとうな設計要求である。しかし、このゴールはDECという会社が消失してしまった以上達成はかなわなかった。

高性能のアーキテクチャを設計することは緻密なエンジニアリングを行っていれば、(もちろん簡単ではないが)達成不可能ではない。むしろ容易な範疇にある。

本当に難しいゴールと言うのは、マーケットに求められているものをタイムリーに提供し市場で受け入れられることである。こればっかりはエンジニアリングチームばかりではどうしようもない。マーケティング、営業、サポート、等々全社的な活動となる。企業の総合力が問われているのである。

世界で最高速のマイクロプロセッサを作っても売れなければなんの価値もないのである。こう言ってしまうと身も蓋もないが市場経済というものはそういうことである。

世の中で最も利用されているマイクロプロセッサのアーキテクチャはIA32である。命令セットに直交性がなかったり、CISCの典型的なアーキテクチャではあるが、互換性をキープしながら性能向上を図ってきた。

IA32の性能向上のアイデアは先行した多くのRISCマシンに見られるがそれを集大成しバイナリコンパチビリティをかたくなまでに守ってきた。

64ビット拡張ではIntel IA64があるが、Alpha同様、以前のアーキテクチャ(この場合はIA32)と互換性がない。今にいたるまでIA64の市場は広がっていない。

世界最大のマイクロプロセッサベンダであるIntelの力をもってすらアーキテクチャの移行というのは容易ではないのである。

マイクロプロセッサの命は命令セットであり、それを変更することはソフトウェアの重さから考えて容易ではない。結局、『増加したトランジスタ(向上した集積度)をどう使うか』という問題に対する回答は、互換性の維持に使われる、といういささかユメのないことになるのである。

多くのコンピュータアーキテクトがこの問題にチャレンジして、屍の山を築いてきた。汎用プロセッサのエリアでは、互換性が最も重要な設計ゴールとなっているのである。

このゲームのルールを変えるには勝負する土俵を変える必要があってゲームや携帯などの組み込み系から攻めていくというのが当面の流れかと思う。

一方でオープンソースがソフトウェアの重さ(膨大なソフトウェア資産の慣性)を軽くすることができるのだろうか?新しいチャレンジがそこにはあるような気がする。

ムーアの法則を十分理解した上での新しいソフトウェア設計、製造、保守のモデルとしてのバザールモデルへの熱い期待である。

ムーアの法則を理解すること/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/06/post_e653.html

ムーアの法則を理解すること

Matzにっき (2007-05-30)
インテル:「ソフトウェアもムーアの法則に従う必要がある」 - CNET Japan
http://www.rubyist.net/~matz/20070530.html#p07

「今まではハードがどんどん高速化してきたので、ソフトウェアの皆さんは(マシンのアップグレードで)自動的に性能向上を享受できていましたが、これからは諸般の事情でそういうことはできなくなります。ソフトウェアの皆さんもご協力を」という話。

っていうか、最初からそういう風に言ってほしいものだ。

このブログの読者ならご存知かと思うが、わたしは昔DEC (Digital Equipment Corporation)という会社に勤務していた。わたしがエンジニアリングのイロハを習った会社である。VAXそしてAlpha AXPというコンピュータ史に残るアーキテクチャを開発した会社でも知られている(若い人は知らないかもしれないけれど)。商業的にはその後コンパックに売却され、コンパックはHPに売却され今はその名はない。

さて、そこでソフトウェアエンジニアとしてのキャリアを積んでいったのであるが、そのエンジニアリングコミュニティは間違いなくムーアの法則をコミュニティとして理解していた。(マルチプロセッサ向けソフトウェアパラダイムとは、マルチプロセッサ向けソフトウェアパラダイムとは?(その2)を参照のこと)

Alphaの開発チームはVAX開発チームの後継で、ある意味DNAを受けついでいるのだが、当時の論文(90年ごろ)で、マイクロプロセッサのスケーラ ビリティを、クロックの向上で10倍、アーキテクチャの進歩で10倍、マルチプロセッサで10倍、10x10x10=1000倍の性能向上を達成するとか しないとか書いてあって、感心したのを覚えている。

http://blog.miraclelinux.com/yume/2007/01/post_ab8c.html


アーキテクチャの設計寿命で紹介した論文をふたたび引用する。1992年の論文であることに注意されたい。
Alpha AXP Architecture
by Richard L. Sites

http://www.hpl.hp.com/hpjournal/dtj/vol4num4/vol4num4art1.pdf

The remaining factor of 10 will come from multiple processors. A single
system will contain perhaps ten processors and share memory. We therefore
designed a multiprocessor memory model and matching instructions
from the beginning. This early accommodation for multiple processors
also distinguishes the Alpha AXP architecture from many other RISC
architectures, which try to add the proper primitives later.

今後15年から25年のレンジで性能向上をはかるためにクロックレートで10倍、それ以外の設計要素(投機的な実行、Out of Order、スーパーパイプライン、スーパースケラー等々)で10倍、そして残りはマルチプロセッサ技術で10倍、合計10*10*10=1000倍のスケーラビリティを確保する、という事である。

この論文が発表されたのは92年でAlpha AXPの開発が開始されたのは88年あたりだからAlpha AXPチームは約20年前には、間違いなく今後の性能向上にはマルチプロセッサの技術が必要になるというビジョンを持っていた。

商用OSはSMP性能でのボトルネックを発見し修正するという地味な作業を延々おこなってきたし、ミドルウエア(RDBMSなど)もSMPでの性能向上に力をそそいできた。今後も益々SMPの重要性は増すであろう。

そして、ソフトウェアコミュニティでも、それを理解する必要がどんどん増しているのである。

つい最近までハードウェアの性能向上にあぐらをかいてソフトウェア側の性能向上の努力というのはほとんどなかった(というのは言いすぎかもしれないけれど)。汎用的な性能向上という点から言うと進歩はゆっくりしていると言っても過言ではない。

ムーアの法則をもう一度よく理解する必要がある。

そして、もう一つ重要な点、増加したトランジスタ(向上した集積度)をどう使うかについては、後に記す(かもしれない)。

インテル:「ソフトウェアもムーアの法則に従う必要がある」
http://japan.cnet.com/news/biz/story/0,2000056020,20349605,00.htm

アーキテクチャの設計寿命/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/02/post_e9f1.html

マルチプロセッサ向けのソフトウェアパラダイムとは/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/01/post_ab8c.html

マルチプロセッサ向けソフトウェアパラダイムとは?(その2)/ユメのチカラ
http://blog.miraclelinux.com/yume/2007/01/post_95e7.html

マルチプロセッサとマイクロカーネル/ひら
http://d.hatena.ne.jp/hira_sosuke/20070604/1180968495

若者との会話

びぎねっと主催のオープンソースパーティ2007に参加した。今年は120人を越える参加者ということで、会場がごったがえしていたので、落ち着いて話をすることはなかなか難しかったが、それでも懐しい顔にいっぱいあえて楽しかった。前日はカーネル読書会だったので2日連続で会う人も少なくなかった。特にオープンドリームの皆様には、あ、どーも、とか言う感じであった。

入口近くには、びぎねっと勢が陣どっていて、Linux World Expo3日間の疲れかテンション低くまったりとしていた。

その一人大内さんとお話をする。まだ10代のハッカーである。はりぼてOSの会で、自分OSを作っている若者である。

はりぼてOSの会は、「30日でできる! OS自作入門」に触発されて自作のOSを作ろうという狂気(誉めています)の集団である。わたしみたいな人間はOSを自作しようなんていう発想にはまったくもってついていけないのであるが、若者はいとも簡単に、そーゆー事にチャレンジをしてしまう。「最近多いですよ、OS作る人」とか事もなげに大内さんは言うのだが、おじさんは、ひえ〜と退けぞるだけである。

いいなあ、元気があって。おじさんはエネルギーを貰ったよ。という感じである。

彼はまだ19歳なので、お酒は飲めないのだが、わたしは十分へべれけでいろいろ話を聞く。

最近のモチベーションというか、いろいろ聞くうちに、ちょっとしたヒントを言う。

自分がしたいことをリストにしてみる。すぐにできる事、すぐにできない事、簡単な事、難しい事、やりたい事、やりたくない事などなどともかくリストにしてみる。そして、それをやりたい順にソートして書き出してみる。

そのリストをわたしは見たい。そのリストをみんなでわいわい議論したら面白いかもしれない。ひょっとしたら、そのリストをもとに未踏に応募してみたり、あるいは誰かがスポンサーになって実現に手助けをしてくれるきっかけになるかもしれない。

ユメをカタチにするために、リストを作る。それは無駄な作業ではない。自分の羅針盤になるし、まわりを巻き込むツールにもなる。

そんなことを思ったオープンソースパーティ2007である。



カーネル読書会
http://blog.miraclelinux.com/yume/2007/06/post_da8e.html

オープンソースパーティ2007
http://blog.miraclelinux.com/yume/2007/05/post_da52.html

Linux World/BITS 2007
http://blog.miraclelinux.com/yume/2007/05/linux_worldbits.html

第74回カーネル読書会

今回は趣向をかえてPostgreSQLとSELinuxの組み合わせ〜

日時:5月7日(月)、18時半開場、19時ころ開始
会場:ミラクル・リナックス、セミナールーム

お題:SE-PostgreSQL : OSとRDBMSのセキュリティポリシーの統合
発表者:海外 浩平さん
内容:SE-PostgreSQLは、PostgreSQLにSELinuxとの連携による細粒度の強制
      アクセス制御機能を組込み、Linux kernel と RDBMS を統合されたセ
      キュリティポリシーの下で動作させるものです。
      今回の読書会では、SE-PostgreSQLの特徴/機能や実装、コミュニティ
      との連携についてご紹介します。

18:30頃、開場
19:00頃、お題開始
20:30頃、懇親会開始

場所はいつもの、ミラクル・リナックス社セミナー会場地図
http://www.miraclelinux.com/corp/about/maps_google.html

開場した後は、だらだらと自己紹介やら小ネタやらをやりますので、時間の許す限り早めに来た方が面白いお話をきけるかもしれません。

会場で、ピザとビールの懇親会つき。(予定価格1000円)
懇親会参加希望の方は、懇親会参加と明記してください。

登録はいつもの宴会君
http://utage.org/enkai/
宴会コード (kernel070507)

会場の都合で35人程度で締め切ります。早めに登録してください〜

U-20プログラミング・コンテスト

立場上(?)いろいろな委員会や業界団体の理事などにおよびがかかる。まあそれも一つのコミュニティみたいなものだから無碍に断わるのも角が立つ。しかし、一つだけ(というと微妙に語弊があるかもしれないが)、お願いしてもやらせていただきたいと思っているのが、U-20プログラミング・コンテストの審査委員である。

審査委員長は東京大学名誉教授の石田晴久先生。委員にはRubyのまつもとゆきひろさんや、カーネルハッカーのg新部さんなどがいる。

このU-20プログラミング・コンテストは経済産業省が若年層への情報処理教育の普及啓発、次代を担うIT人材の早期発掘・育成を目的に昭和55年から実施しているコンテストである。(説明が固いなぁ)

U-20すなわちアンダー20(20歳以下)、中学生、高校生が思い思いにプログラムを作り、課題は特にない、予備審査をとおった作品について、作った本人のプレゼンにより審査する。もちろんソースコードの品評もさせていただく。

プログラムを作ってよかったと思える瞬間はどんな時ですか、とかいう質問を高校生のプログラマにする。彼等のコードを読む。あらけづりでまだまだ改良の余地はあるが力のこもったコードを観賞する。

彼等からプログラミングの面白さ、楽しさを教えてもらう。初心に帰る思いである。

今年はどんなプログラムに出会えるか今から楽しみである。

若者のチャレンジを待つ。

未来のいつか/hyoshiokの日記
コンテストで検索

Matzにっき
U-20で検索

U-20プログラミングコンテスト/ユメのチカラ

Rubyって何よ。

先日、NHK土曜ドラマ「ハゲタカ」の事をこのブログで書いたものだから(「ハゲタカ」、「職人気質」など)、日頃このブログの読者でない方も多数訪問されている。ご訪問ご苦労さまです。45度おじぎ。(ぺこり)

ハゲタカファンの皆様にとってはこのブログ、わけのわからない、Rubyだ、オープンソースだ、gdbの使い方だで、ほとんど興味を引かないものばかりかと思うのだが、ここは一つ、ハゲタカファンの皆様にRubyについて、お話をしてみたいと思う。

Rubyというのは、まつもとゆきひろという一人のプログラマが作ったソフトウェアである。(ふむふむ)。ソフトウェアを記述する言語のことをプログラミング言語というのであるが、Rubyはそのプログラミング言語の一種である。(ふーん)世界には様々なプログラミング言語があるのだけど、Rubyは赤丸急上昇の人気言語なのである。

ソフトウェアの世界にも流行すたりがある。プログラミング言語にも流行すたりがある。多分バブルも、バブルの崩壊もあるかと思うがよくわからない。

大田区あたりの町工場で、世界最先端のその会社しかできない技術があるというようなお話は時々聞くが、Rubyもそんな感じの言語である。(どんな感じだ?)島根県松江市在住のまつもとゆきひろが趣味で作りはじめた、プログラミング言語が世界の注目をあびている。

プログラムを作るのに広大な敷地と莫大な設備投資をして工場を持ったりする必要はない。工作機械もいらない。インターネットにつながるパソコンさえあれば、極論すると世界のどこででもプログラムは作れる。

もちろん日本語を書けるからと言って、世界的な文学が書けるとは限らないように、パソコンがあっても世界的なプログラムを書ける人は、ほとんどいない。(とすると、まつもとゆきひろという人は世界的な文豪みたいなものか)

レンズ磨きの工作機械があってもレンズ磨きの達人になるのに40年かかるのと一緒である。(本当かな)

野球好きの少年が、大リーグに行った野茂の姿を見て、いつかは僕も大リーガーだと夢みるように、Rubyというプログラミング言語を作ったまつもとゆきひろは世界の言語オタクのアイドルなのである。(なるほどね)

で、日本Ruby会議2007という、まつもとゆきひろのファンクラブの年一回の大会のチケットは是が非でもゲットして参加しなければいけないのである。で、そのプラチナチケットをゲットしたものだから、しかも一度買いそこねて、キャンセル待ちでゲット、狂喜乱舞したのである。

このムーブメントは世界中に飛び火していて、2001年からは米国でもRuby Conferenceというのが開催されていて、松江が生んだ世界のアイドルになっている。島根県議会は、まつもとゆきひろを「地域資源」としてとらえているらしい。(人間国宝みたいなものなのか?)

さらに面白いことに、まつもとゆきひろはそのRubyを無償で公開しているのである。それでお金儲けしようと思えばできなくもないと思うのだが、無償で公開しているのである。世界でまつもとゆきひろのように自分で作ったプログラムを公開している人は少なくなくて(実際大変多い)、それらのソフトウェアを大雑把にくくって、オープンソースソフトウェアとかいったりするのだけど、世界中には無償の愛があふれているのである。

Rubyをはじめ、オープンソースソフトウェアは無償で流通しているので、世の中99.9%はカネで解決するのだが、カネで解決できないというか、カネのチカラが、あんまり影響力を持たない世界がそこにはある。

じゃあ、どーやって、そこでお金儲けをするのよという素朴な疑問が生じるわけであるが、そーゆーものから距離をおいた世界が、世の中にはあるのである。

まあ、そーゆーわけでRubyの説明をするつもりが、わけがわからなくなってしまったが、ソフトウェアというのは人が作るのである。人はお金だけじゃなくても動くのである。もちろんお金は重要だけど。

Web2.0時代のソフトウェア開発のスピード

最近、あるWeb2.0系の会社の方たちと勉強会をしているのだが、その勉強会もさることながらその後の懇親会でのユルイ会話が面白い。ていうか、勉強会の後の懇親会が好きでやっているのだろうとかいう突っ込み。否定しません。というか、飲み会に大義名分をつけるために、勉強会と称しているのだろう>自分

それはともかく、いろいろ面白いお話を伺う。

Web2.0系のサービスってのは、やってみないと分からない類のものが多いのでともかく思いつきでも何でもとりあえづやってみる。だめだったら考え直す。そーゆースタイルらしい、極論すると。

古典的なウォータフォールモデルでのソフトウェア開発だと、だめだったら考え直すなんていうアバウトなことを言ってはいけないという前提で物事が進むから、ともかく石橋を叩きつつ確実に確実に事をはかる。それはそれで確立されたスタイルなので、間違いではないが、プロジェクトを開始した時点と終了するころには、回りの環境もごろって変わっているだろうし、顧客の要求も全然違っている事も少なくはない。開発期間が年単位だと、顧客要求の変化というのは致命的なリスクであることは間違いない。

アジャイルな開発だと、取り合えづ動くものを作りそれをどんどん改良していく。その改良のプロセスの中で顧客の要求にどんどん合わせていく。

ところで、新しいサービスはどうやって作るんですか、どっからアイデア得るのですか、とか言うことをその飲み会で聞いてみた。

以下はわたしの中の脳内変換された会話。(括弧の中はわたしのなかの反応)

Web2.0:そうですね、飲み会ですかね

よ:え、え?(アイデアを飲み会で出すとかそーゆー事かなあ?)

Web2.0:金曜日に飲み会するんですよ。(ふむふむ)。で、そこで仕事の話とかになったりするんだけど、結構サービスのアイデアとかでたりするんですよ。(ふむふむ)。それでみんなであーだこーだ言っているうちに、ブレーンストーミングみたいな感じになって、どんどんアイデア膨らむんですね。(なるほどね)。金曜日の飲み会だから、朝まで飲んじゃうこともあって、そーゆー時はそのアイデアをすぐにでも実装したくなるじゃないですか。(え?)。そうするとそのまま会社に戻っちゃたりするんですよ。(まさか)。みんな近所に住んでいたりしますしね。(げげ、そーゆー問題でもないだろ)。それで一気にコーディングとかはじめちゃったりして、(ぐは)、そんでもって、取り合えづ、月曜日にみんなで評価して、面白そうだったら、それでサービスデリバーっすよ。

よ:金曜日の飲み会のアイデアを月曜日にサービス開始??

Web2.0:ま、そんな感じっすかね。

やばい、全然ついていけない。

テストカバレージ

先日Ottawa Linux Symposiumに論文のproposalがとおったという話を書いたが、論文を鋭意執筆中である。今回crackerjackというリグレッションテストのフレームワークをうちの若手のkyagiさんがばりばり作ったのであるが、それから呼ぶbtraxというカバレージ測定ツールがこれまた凄い。これは日立の藤原さんというハッカーが実装したのだけどなかなか金銭ではなく琴線に触れるツールである。

ハッカーのバイブル、IA-32 Intel Architecture Software Developer's Manual, Volume 3: System Programming Guideの15章はおなじみのDebugging and Performance Monitoringである。わたしもhardmeterを実装する時は読みに読んだ。マニュアルがボロボロになるまで読んだ。お疲れ様、マニュアルである。

Intelのマニュアルは4半期から半年に一回くらいアップデートしていて手元にあるハードコピーは16版目のやつだ。

15.5からLast Branch Recordingのお話である。Pentium 4/Intel Xeonプロセッサは分岐、割り込み、例外を記録するハードウェアメカニズムを持つ。LBR(Last Branch Record)に最後の分岐、割り込み、例外の情報を記録する。このブランチレコードにはどこから(branch-from)と、どこへ(branch-to)の命令アドレスの情報を保持する。そしてその情報をBTM(Branch trace messages)としてシステムバスに流す。そのBTMをメモリ常駐のBTS(Branch Trace Sotre)に保持する。というような仕組みである。

さて、ハードウェアが分岐命令についていろいろ情報を提供してくれるというのはわかった。

これを使うとどんなことができるのか。

例えば、if (A) then x else y; みたいなコードがあってxを実行したのか、yを実行したのかのトレースがとれる。

テストプログラムの網羅性を議論する時、条件分岐で、どっちのパスも実行、試験した方がいいわけだが、そのカバレージを測定できるのである。

テストカバレージでC0カバレージというのは、命令網羅率とも言われていて、命令を実行したかしなかったかを問う。if(A) then x;みたいな文については条件Aが成立した時に命令を網羅したことになる。

テストカバレージでC1カバレージというのは、条件網羅率とも言われていて、条件(真と偽がある)を網羅したかを問う。if(A) then x;は条件Aが成立した時だけではなく条件Aが成立しなかった時も実行しないと網羅率100%にならない。

高級言語レベルでの網羅率測定はgcovなどのツールを利用すれば簡単に測定できる。linux kernelのカバレージを測定するためにはパッチが必要でLTP(linux test project)のcoverage 分析プロジェクトというのがgcov-kernelパッチを公開している。http://sourceforge.net/project/showfiles.php?group_id=3382
http://ltp.sourceforge.net/coverage/lcov.php
しかし、いかんせんカーネルパッチというのが敷居が高い、お手軽ではない。

そこでbtraxである。btraxは、カーネルパッチも必要ないし、別途カーネルを構築する必要もないので日頃利用しているカーネルの分岐網羅性などを測定するのにうってつけである。

さらに今回のbtraxは機械命令レベルでの分岐網羅性を計測するのでgcc/gcovよりも粒度がより小さい(すごい)。しかもハードウェアレベルで計測するのでオーバヘッドが小さいはづである(多分)。

ソースコードとの対比をすれば未実行のところが一目瞭然である。
Gettimeofdaycovhtml http://btrax.sourceforge.jp/


こーゆー良いツールはどしどし紹介して利用したいと思う。

リグレッションテスト

プログラムを変更した際、予想外の影響があらわれる事があり、それをリグレッションあるいはディグレードと呼ぶ。そのようなリグレッションを発見する事を目的に作られたテストがリグレッションテストである。

リグレッションテストのコンセプトは非常に単純なのであるがその効果は絶大であり商用ソフトウェアの開発現場では日常的に利用されている。しかしながらOSSの世界では必ずしも利用されているとは限らない。Linuxについて言えば公式のリグレッションテストというのは残念ながら存在しない。バザールモデルの特徴である多くの目玉によってピアレビュー、テスト、運用によって問題点が発見される。

Linuxの場合、何か新機能を追加したいと思った人は、LKML (Linux Kernel Mailing List)にRFC(Request for Comments)という提案をメールし議論を開始する。多くのカーネルハッカーによって、その仕様および実装案についてレビューがおこなわれる。いろいろな突込みが活発におこなわれる。議論がだいたい収束しつつあるとサンプル実装というかPOC(Proof of Cencept)実装がパッチの形でLKMLに投稿される。そのコードも多くの人達にレビューされる。興味を引かない提案は無視される。コメントもつかない。コードに対する質問やコメントに対しては、メールでやりとりをし、実装上の問題については、再度パッチの形で回答する。何度かやりとりをするうちにパッチは洗練していく。ラフなコンセンサスがまとまるとAndrew Mortonのmm-treeと言われているカーネルに取り込まれる。コンセンサスがとれない場合は無視される場合がある。いろいろな環境で、実際に利用され意図しない副作用等がないか確認され、有用であるというコンセンサスがとれればLinusのKernelにとりこまれる。長い道のりである。

上記のプロセスは多くの人の目玉によるレビュー、検証に依存するのが特徴と言えば特徴である。

変更点はChangelogやgitのコメントに残るのだけど、それによる副作用がどうあるのかは、明示的に書かれる事は少ない。仮に書かれたとしても、何百もある変更点の中から自分に関連する副作用を発見することは現実的ではない。ミドルウェアの実装をしている人は結果として、随分後に、自分に影響がある変更を認識して、途方にくれたりする。

一方で副作用のある変更を一切禁止するというのも現実的ではない。それはOSSの進化や発展を阻害するし、OSSそのものの価値を殺すことになる。

進化の速度を減速しないまま、影響度の大きい意図しない副作用を早期に発見し、その影響を最小限にしたい。意図する副作用であっても、それによるメリットが大きければ、痛みをともなっても導入することが全体の利益になったりするので、その影響範囲についてもなるべく早い段階で議論をしたい。

そのような問題意識に答えるのがリグレッションテストなのである。

リグレッションテストによって、ある程度自動的に前のバージョンとの動作の違いを発見する。動作の違いというのは、必ずしも悪いことではなくて、バグ修正、新機能の追加、性能向上など積極的に変更する価値のあるものもある。そのような動作の違いによって利益を得る人も入ればアプリケーションに影響がある人もいる。全体でみて利益の方が大きければその変更を受けいれるし、影響が大きければ、その動作の違いを最小化する方法をとればいい。その議論のきっかけになるのがリグレッションテストによって発見される動作の違いなのである。

リグレッションテストは開発者と利用者のコミュニケーションツールになるのである。

Linuxのリグレッションテストが広く利用されるようになれば(われわれの願望である)、カーネル開発者とミドルウェア開発者が、それを媒介してプラットフォームの動作について議論できるようになる。ミドルウェア開発者は問題点の指摘をそれを再現するテストによっておこない、カーネル開発者はリグレッションが発生していない事をリグレッションテストによって担保する。パッチの提供者はピアレビューだけではなくカーネルリグレッションテストを通す事を要求されるようになるというイメージである。

カーネル開発者はカーネルの変更がミドルウェアに悪影響をおよぼさづに大胆に行えるようになり、ミドルウェア開発者は安定したカーネルを手にいれられるようになる。

テストという退屈な仕事が楽で楽しい仕事になる。

crackerjack project http://sourceforge.net/projects/crackerjack/

MySQLのマルチコアスケーラビリティとLinux

スラッシュドットの情報。FreeBSDとLinuxでsysbench(MySQLを利用している)の結果が出ている。結論から言うと8コアのAMD64のマシンでスレッド数を上げていくと8スレッドまではLinuxでの性能が良かったが、それ以上になるとがたっと性能が劣化して、FreeBSDのSMPngの実装が勝つ。

下記を参照してほしい。
http://jeffr-tech.livejournal.com/6268.html

MySQL 5.0.2xではSMPスケーラビリティに問題があることは、われわれの性能評価でもあきらかになっていたが、(例:MySQLに対応した評価ツールDBT-1を利用したハードリソース変更によるパフォーマンスへの影響の考察を参照)、OSのSMPスケーラビリティ問題というよりMySQLの実装上の問題だと考えていた。

linux 2.6.18/2.6.20.1上でMySQL 5.0.27(これはスケーラビリティ上の問題が顕著)と5.0.33(スケーラビリティの問題を若干解決した)を評価したグラフを見ると、あきらかにFreeBSD-ULEの実装と比較して、linuxはスケーラビリティの問題がある。スレッド数がコア数(8)を越えたあたりから性能が急激に劣化する。

Linux Kernel Mailing Listでも早速話題になっていて、(http://www.ussg.iu.edu/hypermail/linux/kernel/0702.3/0299.htmlからのスレッドを参照)、Linuxのスケジューラの問題という認識になりつつある。

特に、SMT(IntelのHyperthread)やMC(Multicore)用のスケジューラが悪さをしていそうである。http://www.ussg.iu.edu/hypermail/linux/kernel/0702.3/1142.html

CONFIG_SCHED_SMTとCONFIG_SCHED_MCをオフにした結果が下記に出ている。
http://www.ussg.iu.edu/hypermail/linux/kernel/0702.3/1133.html

http://www.ussg.iu.edu/hypermail/linux/kernel/0702.3/1133/transactions.png

若干現象が良くなっているが抜本的な解決にはなっていない。

MySQLで発見された現象が正しく理解されれば、遠くない将来に問題は解決されるだろう。

いろいろな人がいろいろな評価をしたり、知恵を出したり、コメントしたり、バザールモデルの醍醐味である。

OSS性能・信頼性評価プロジェクト

IPA(独立行政法人情報処理推進機構)の支援をうけて実施していたオープンソースソフトウェアの性能・信頼性評価プロジェクト結果をOSS情報データベース「OSS iPedia」で公開した。

本プロジェクトはIPAの統括のもと、下記の9社によって実施した。(五十音順)
SRA OSS, Inc.日本支社、NTTデータ先端技術(株)、住商情報システム(株)、日本ヒューレット・パッカード(株)、(株)野村総合研究所、(株)日立システムアンドサービス、(株)日立製作所、ミラクル・リナックス(株)、ユニアデックス(株)

弊社もPostgreSQLやMySQLの評価で参加した。

今回のプロジェクトの詳細については下記のOSS iPediaのデータを参照したいただきたい。

2006年度 オープンソースソフトウェア(OSS)の性能・信頼性評価の成果

これまで、PostgreSQL 8.1では8CPUまでは性能が向上することが確認されていたが、最新版8.2では、16CPUまで性能が向上することが示された。最新版MySQL 5.0.32については同様に4CPUまで性能向上することが確認された。

このOSS性能・信頼性評価プロジェクトは2004年から実施していて、今回で一応の成果をみとめて発展的に解散する。

iPediaの読み方。

下記を例に、考察データを読みといていく。
MySQLに対応した評価ツールDBT-1を利用したハードリソース変更によるパフォーマンスへの影響の考察
http://ossipedia.ipa.go.jp/capacity/EV0612260303/

DBT-1というのは旧OSDL(現在のLinux Foundation)が開発したTPC-W風のワークロード(ベンチマーク)で、CPU数を4から8に変化させてMySQL 5.0.24と5.0.32(最新版)で性能を評価した。

5.0.24では8CPUの性能が4CPUの性能より低いことが図1より読みとれる。一方、5.0.32では8CPUでの性能が向上した(図2)。しかしながら、それでもCPU数8個では十分なスケーラビリティが確保できない。

oprofileのデータをみると8CPUの場合、ロック関連で約70%の処理時間を費やしていて、ロック競合によって性能が出ていないことわかる(MySQL 5.0.24の場合)。性能改善がはかられた、MySQL 5.0.32のoprofileのデータを確認するとmutex_spin_waitという処理がトップ5から姿を消し、ロック関連処理のが約23.8%となっていて5.0.24の70%より減っているのが確認できる。それでお約2割がロック競合なので、さらなる性能向上がみこめる。

http://ossipedia.ipa.go.jp/capacity/CS0612210243/ 他に関連する性能データ(MySQLの設定ファイルやoprofileの測定データ)があるので、実際にダウンロードして確認してみてほしい。

実際のoprofileのデータを読みとくことは性能評価の定跡であるが、そのような生データが無償で公開されている意義は非常に大きいと思う。教育的価値も高い。OSSを対象とした性能評価プロジェクトであったため、商用製品の評価と違い、測定結果を自由に公開できるというのは、多くの人にとって価値があると思う。商用製品の場合、ライセンスでベンチマークの公開を禁じている場合が多いのである。

プロジェクトの裏話や想い出については別途記すかもしれない。

Rubyで習作の性能評価

うひょ〜。大変なことになった。手習いで書いた初めてのRubyプログラムが大御所によってたかって添削指導をうけている。

確かに突っ込みどころ満載のゆるゆるのコードなので、弊社のrubistからの突っ込みくらいは想定していたが、まつもとさん弾さんの登場までは想定外であった。多くの皆様のコメントに感謝したい。

実装についても、ArrayやらHashやらSetやらいろいろあった。そこで、ちょっと性能評価をしてみた。

具体的には time ruby -rprofile でruby自前のプロファイルをとってみた。

Array#includeはコストが高い。実行時間が21秒〜24秒くらいとなっていて、そのうち12秒〜13秒をArray#includeで消費している。

表の見方なのであるが、コストのかかっている処理のトップ3を表示した。左から、全体から比率、累積実行時間(秒)、実行時間(秒)、呼び出し回数、1回あたりの実行時間(ミリ秒)(self)、1回あたりの実行時間(ミリ秒)総和、処理

下の例だと、Array#include?という処理は全体の61.49%を消費し、12.58秒かかっている。1256回呼出され、それぞれ一回あたり10.02ミリ秒(self)、16.03ミリ秒(総和)かかっている。selfと総和というのがよくわからないが。

bonlife.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
61.49    12.58     12.58     1256    10.02    16.03  Array#include?
36.90    20.13      7.55   735858     0.01     0.01  String#==
  0.93    20.32      0.19        4    47.50  5115.00  Array#each

real 0m21.438s
user 0m20.469s
sys 0m0.575s

kyagi.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
59.83    12.90     12.90     1256    10.27    16.93  Array#include?
38.82    21.27      8.37   735858     0.01     0.01  String#==
  0.46    21.37      0.10        3    33.33    56.67  IO#each

real 0m23.199s
user 0m21.565s
sys 0m0.618s

masaka.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
60.37    12.11     12.11     1256     9.64    15.88  Array#include?
39.03    19.94      7.83   735858     0.01     0.01  String#==
  0.35    20.01      0.07      628     0.11     0.16  Kernel.print

real 0m21.265s
user 0m20.073s
sys 0m0.572s

sumim.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
58.37    12.93     12.93     1256    10.29    17.12  Array#include?
38.69    21.50      8.57   735858     0.01     0.01  String#==
  1.35    21.80      0.30      629     0.48    69.51  Array#each

real 0m23.778s
user 0m22.161s
sys 0m0.604s

sumim1.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
57.38    13.33     13.33     1256    10.61    18.02  Array#include?
40.03    22.63      9.30   735858     0.01     0.01  String#==
  0.47    22.74      0.11      628     0.18    36.32  Range#each

real 0m24.673s
user 0m23.240s
sys 0m0.635s

Hashの実装はArray#includeよりコストが安い。

dan.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
34.55     0.19      0.19        3    63.33    70.00  IO#each
21.82     0.31      0.12      628     0.19     0.30  Array#each
18.18     0.41      0.10        1   100.00   340.00  Hash#each_key

real 0m0.717s
user 0m0.561s
sys 0m0.011s

diffpkg.rb (わたしの実装)

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
34.04     0.16      0.16        3    53.33    83.33  Object#makehash
23.40     0.27      0.11        1   110.00   220.00  Hash#each
12.77     0.33      0.06     2553     0.02     0.02  Hash#[]=

real 0m0.632s
user 0m0.482s
sys 0m0.011s

matz.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
30.23     0.13      0.13        1   130.00   240.00  Hash#each
25.58     0.24      0.11        3    36.67    63.33  IO#each
13.95     0.30      0.06     2553     0.02     0.02  Hash#[]=

real 0m0.482s
user 0m0.432s
sys 0m0.013s

Setでの実装も比較的コストが安い。

maoe.rb

  %   cumulative   self              self     total
time   seconds   seconds    calls  ms/call  ms/call  name
41.18     0.21      0.21        3    70.00   170.00  IO#each
15.69     0.29      0.08     1925     0.04     0.05  Set#add
11.76     0.35      0.06      628     0.10     0.10  Kernel.print

real 0m0.709s
user 0m0.521s
sys 0m0.011s

実行のコストでいうと、matz/わたし/maoe/danの一群、anaitoが僅差、ずっと離れてbonlife/masaka/kyagi/sumimという感じである。

それぞれのコード

anaito.rb (メールでもらった)

#!/usr/bin/env ruby
# by Atsushi Naito

def sort_list(pkg_list, file_list)   h = Hash.new   pkg_list.each do |key, value|     file_list.each do |f|       if value.include?(f)         (h[key] ||= []) << "included."       else         (h[key] ||= []) << "not included."       end     end   end   h.sort_by{|key, value| key} end begin   pkg_list = Hash.new   file_list = Array.new   ARGV.each {|filename| file_list << filename}   ARGF.each do |line|     key = line.chomp     (pkg_list[key] ||= []) << ARGF.filename unless key.empty?   end   pkg_list = sort_list(pkg_list, file_list)   pkg_list.each do |key, value|     puts "#{key}\t#{value.join("\t")}"   end rescue Interrupt => err rescue => err   $stderr.puts err.message   exit 1 end

bonlife.rb
http://d.hatena.ne.jp/bonlife/20070202/1170416653

dan.rb
http://blog.livedoor.jp/dankogai/archives/50757687.html

diffpkg.rb
http://blog.miraclelinux.com/yume/2007/02/ruby_b40b.html

kyagi.rb
http://blog.miraclelinux.com/yume/2007/02/ruby_b40b.html#comment-884779

maoe.rb
http://d.hatena.ne.jp/maoe/20070204/1170619870

masaka.rb
http://blog.miraclelinux.com/yume/2007/02/ruby_b40b.html#comment-884800

matz.rb
http://www.rubyist.net/~matz/20070202.html#p01

sumim.rb sumim1.rb
http://d.hatena.ne.jp/sumim/20070206/p1

勝手に性能評価(Lingr編)

週末にLingrを利用したチャットイベントがあったそうだ。[JTPA] Lingrイベントの顛末/My Life Between Silicon Valley and Japan

昨日のオンラインサロンは、参加者が集まるにつれてLingrが重くなってしまって残念ながら中止となりました。

実のところLingrの実装がどうなっているかは全く知らないのだが、何百人もわらわら集まってチャットをやろうという心意気が楽しい。素晴しい。やってみてスケールしなかったというのも主催者側は若干凹むかもしれないが、それもいい経験で、むしろそーゆー得難い経験を得られたと考えた方がいい。

Lingrの開発者の江島さんは、梅田さんのブログで再挑戦を表明しているので楽しみにしたい。

さて、今回の経験から江島さんら実装者の皆さんは何を学んだのだろうか?ぜひ情報公開をしてほしいと思うのだが、わたしだったらどうするか勝手に記してみたい。

わたしはネットワーク方面には全く土地勘はないのだけど、システム回りとRDBMSあたりだったら若干の経験があるので、いくつかの教訓めいたことを。

サーバーアーキテクチャの再点検、改善などをあげているが、負荷テストをまづやりたい。そこで、vmstat/iostatをおこない、CPUボトルネックになっているのか、IOボトルネックになっているのか、メモリボトルネックになっているのか、あるいはRDBMSがボトルネックになっているのかをみきわめる。

IOボトルネックなのに、CPUを追加しても意味がないし、CPUボトルネックなのにディスクを追加しても意味がない。何がボトルネックかを定量的に把握するのが一番である。

しかし、vmstatなどではシステム全体の負荷はわかってもどのプロセスに最もコストがかかっているのかという微視的な視点でのプロファイルはわからないので、oprofileを利用してシステムのどこで最もコストがかかっているかプロファイリングする。DBサーバに負荷がかかっているとしたらキュエリの実行プランを出して、適切な検索プランになっているか検討する。

負荷テストで現状の定量的な把握をおこないボトルネック解析、およびそれの対処を実装し、再度定量的に計測する。それを所望のゴールになるまで繰り返す。

上記のテストを繰り返している間は、機能はフリーズして、バグフィックス以外はチェックインしてはいけない。大規模な実験の前にバージョンアップをするというのは最もやってはいけない手なのだけど、外野(わたしの事)は勝手な事を言えるのでここの部分は聞き流してほしい。

vmstatでカーネルのCPU利用率を測定し、それが20%を越えていたらカーネルの処理にコストがかかりすぎなので、システムの実装を見なおした方がいいかもしれない。一方ユーザのCPU利用率が90%以上ならば、アプリケーションプログラムの実装を見直すいい機会になる。

どちらもoprofileのデータがチューニングする時によいヒントを提供するのでそれを利用したい。

1000クライアントを一つのPCサーバでサービスするというのは結構しんどいのではないかと想像するけど実装がどうなっているのか全く知らないので情報公開をまちたいと思う。(Lingr and Comet - 技術解説編)

いずれにせよ、データを取れデータを。(oprofileならなお可)

2月6日の追記:

「梅田サロン中止のお詫び、およびアーキテクチャ変更についての技術詳細レポート」という顛末が公開されている。

http://blog.japan.cnet.com/kenn/archives/003556.html

Rubyで習作

最近会社でRubyの勉強会をしていて手習でRubyのスクリプトを書いたりする。
http://blog.miraclelinux.com/asianpen/2007/02/ctrlz_bfd3.html
に触発されて、同じような事をするスクリプトをRubyで書いてみた。Ruby歴3日の初心者が書くとこんな感じになるという例として見てほしい。
繰り返しがいっぱいあるのでもっとブロックとか上手に使うとすっきりしそうな気がするのだが全然土地勘がないのでよくわからない。読者諸氏の添削を期待したい。

#!/usr/bin/env ruby
#
# by Hiro Yoshioka
# 2/2/'07: inspired by
# http://blog.miraclelinux.com/asianpen/2007/02/ctrlz_bfd3.html

def makehash(h, f)
  while line=f.gets
    line=line.chop
    h[line]=line
  end
end

begin
  file1 = File.open(ARGV[0], "r")
  hash1 = Hash.new
  makehash(hash1, file1)
rescue
  puts 'error ARGV[0] ' + ARGV[0].to_s
  exit
ensure
  file1.close unless file1.nil?
end


begin
  file2 = File.open(ARGV[1], "r")
  hash2 = Hash.new
  makehash(hash2, file2)
rescue
  puts 'error ARGV[1] ' + ARGV[1].to_s
  exit
ensure
  file2.close unless file2.nil?
end

begin
  file3 = File.open(ARGV[2], "r")
  hash3 = Hash.new
  makehash(hash3, file3)
rescue
  puts 'error ARGV[2] ' + ARGV[2].to_s
  exit
ensure
  file3.close unless file3.nil?
end

hash1.each do |key, pkg|
  line = pkg.to_s + ', '

  line = line + if pkg == hash2[pkg]
    "included,     "
  else
    "not included, "
  end

  line = line + if pkg == hash3[pkg]
    "included\n"
  else
    "not included\n"
  end

  print line

end

どうでしょうか?

バザールモデルにおける品質

ソフトウェア開発モデルとしてのバザールモデルというのは従来のソフトウェア開発モデルとまるっきり違うので、簡単に対比して考えてみる。

古典的なウォータフォールモデルでは、工程を要求定義、外部設計、詳細設計、実装、単体テスト、統合テスト、運用保守となる。工程による分割可能で、要求定義を上流工程と実装、テストなどを下流工程と言う。それぞれの工程には明確なアウトプットがあり、要求定義のアウトプットは要求定義書で、それが外部設計のインプットになる。

要求の獲得から実装という一連の流れのなかで、利用者の何らかの問題を解決しなければならないのだけど、要求定義が利用者の要求とかけはなれたものであったら、いくら設計から実装が正しくとも、まったく意味のないものができあがってしまう。要求を的確に把握する事が重要なのだけどそれが一番難しい。

仮に要求定義の時点で利用者の要求を把握していたとしてもウォータフォールモデルでは要求定義をしてから実装が出て運用にいたるまで長い期間がかかるため、その間に要求が変化してしまうこともあり、利用者にジャストミートなソフトウェアを提供することが難しい。

そのためプロトタイプを作って要求の見える化をしたり、素早く実装をくりかえして環境変化による要求変化に追随したりする。

一方バザールモデルはというと、明確な要求定義書とか外部設計書、詳細設計書の類いは通常は存在しない。誰かが問題を発見し、それがバグフィックスであったり、機能的な不備であったり様々なわけであるが、通常は問題を認識した人が実装する。実装者が要求者の場合、実装する人は要求(問題)を正しく認識しているので、要求そのものの齟齬というのは原理的には発生しえない。

機能の需要者が供給者という構図である。

実装については多数の目玉がピアレビューをする。それは機能面と実装面から徹底的にレビューされる。メーリングリストへ、XXという機能を実装したいというRFC (Request for Comments)を投げると様々な観点からのレビューがおこなわれる。実装(パッチ等で提供される場合が多い)についても同様にレビューがおこなわれるだけではなく、様々な環境でテストされるので、機能的な問題、実装上の問題が効率よく発見される。

ソフトウェアのバージョンは安定版と開発版と分離し、通常、新機能については、開発版でProof of Conceptされて、有用性や互換性が検証され、安定版には重要なバグ修正のみを適用することによって安定性互換性を担保している。

リグレッションテストのような自動化した互換性確認というのの適用は今後の課題となっている。

Linuxの品質特性の一つとしてセキュリティについての数字があってWindowsとの比較すると下記になる。

Windowsの脆弱性の緊急度、最高(5%)、高(33%)に対しLinux Kernel 2.6は0%である。狭義の品質不良(機能的不具合)についての定量的データは少ないが、定番のOSSのバグ密度が低い事はよく知られている。

商用ソフトウェアのような予算、スケジュール、リソースの明示的な制約(?)というのはなく自発的な開発者による自発的な開発に依存している。

ただしOSS(オープンソースソフトウェア)だからといって上述したバザールモデルの開発になるとは限らない。むしろ多くのOSSはバザールにならず、ひっそりと誰にも注目も利用もされず忘れさられている。しかしLAMP(Linux/Apache/MySQL/Perl/PHP)等に代表される定番のOSSはバザール開発モデルになっている。

バザールモデルは環境変化、要求変化に対し極めて柔軟にしかも素早く対応する。要求に適合したものがタイムリーにリリースされる。これは通常のウォータフォールモデルによる開発ではなかなか達成できないものである。

このようにバザールモデルで開発したソフトウェアの品質は極めて高いといえる。

なぜソースコードを読むのか?/ユメのチカラ

オープンソースの生産性/ユメのチカラ

ハッカーのつくりかた

先日も朝から3人面接し、午後外出の後、夕方1人とじっくり話しこんでしまい、結局ディスカッションは2時間くらいになった。

まあ、ブレストなのか雑談なのかなんなのかよくわからない面接なのであるが、忘れないうちにブログのネタとして書いておく。

彼は弊社一番のカーネルハッカーでバックエンドチームに所属している。カーネルにまつわるどんな問題も魔法のごとく解決する凄腕である。

わたしの下心としては、彼のコピーをどのようにして作るのかというところにある。もちろん人間のコピーなんていうのが簡単にできるわけはない。しかしそれでも彼の1/10くらいのハッカー予備軍ができればおつりがくる。

カーネルの場合、必要とする知識はユーザーランドのアプリケーションより遥かに広範囲である。知識量勝負の部分がある。詳解Linuxカーネル程度の事は常識として理解していないといけない。割り込みの場合、コントローラのレジスタがどうだこうだという知識も必須である。

ある程度の知識がないと時間ばっかりかかって全然前に進めない。一方で、必要最低限の知識が得られたら、あとはずんずん経験を積んでいくしかない。その原動力は結局のところ、その作業が好きか嫌いかによる。

社内でのカーネル勉強会というのは知識の共有には非常に役にたつが楽しさの共有という点ではどうだろうか。

勉強の方法というか、知識の獲得方法の獲得方法というようなものも必要になてくる。カーネルハッカーが持っている暗黙的な知識や知識の獲得方法を、どうにかして明文化したいというのがわたしの下心なのであるが、カーネルハッカーはそのような事を無意識のうちにやっているので、言語化するなんていうことはあんまり考えたことがないようである。

銀の弾丸はないので、カーネルハッカーのそばに座って、その背中を見ながら盗むしかないのであるが、いかんせんこの方法だとスケールしない。手間暇がかかる。

そこでわたしがカーネルハッカーにお願いしたのは、何らかのトラブルシューティングをしたら、それをケーススタディとして、どのような作業をして、その問題を分析したか簡単(本当は詳細にと言いたいところだけど、ちょっと遠慮した)に記述してほしいと。その記述をもとに皆でそのケースについて議論をしてベストプラクティスを獲得する。

ソースコードのちょっとした読み方のコツとかエディタの便利な使い方とかいうのは、そのケーススタディではごっそり抜け落ちてしまうのだが、それは背中を見ながら盗むか、質疑応答であぶりだしてほしいのだが、初心者は質問ができないというワナがある。

トラブルシューティングの方法を記述するというのは、エキスパートだけではなく初心者にとっても大変役にたつ。初心者は自分の作業をふりかえる良いきっかけになるし、それ以上に、そのプロセスを明示化することによって、ムラ、無駄、無理、などを発見する機会にもなる。明示化されることによって初心者には気がつかない落し穴とかもっと良い方法などがエキスパートによって発見されるようになるかもしれない。

作業の見える化という感じである。

一つの作業が数分で終わるようなものだとプロセスの記述の手間のオーバヘッドが大きいが、複雑な問題だと数時間から数日かかる場合があるので、それをまとめておくメリットは大きい。

ハッカーへの道は遠いが、その一歩としてハッカーがやっている事を観測して理解するというのはあながち遠回りという事はないと思う。

How To Become A Hacker (ハッカーになるために)
Eric Raymond, 12/19/'98

オープンソースマガジン連載「ハッカー養成塾」リンク集

どうでもいいプチ蘊蓄、i18nの話

読者の皆様、これはブックマークだ。

baccus-dのブログを見ていたらi18nのお話が出ていたので、i18nの起源というプチ蘊蓄を語る。
この起源についての質問はインターネットでも時々間欠温泉のようにわきあがるいわばFAQみたいなものなのだが、90年代初頭にはつかわれていたとかいう証言がえられるが、なかなか起源まで行きつくものは少ない。

これはずばり85年頃のDEC (Digital Equipument Corporation) (後にコンパックに買収され、その後コンパックはHPに買収された)にScherpenhuizenという人がいて、彼のマシン(VMS/DECNET)名にS12Nという名前をつけていた。当時のVMS/DECNETはノード名の制限が6文字だった。なんでS12NかというとScherpenhuizenという名前は最初のSから最後のnまでに12文字あるからである。

この長い名前を(最初の一文字+中間の文字数+最後の一文字)という風に略すやり方は当時のDECでは流行っていて、DECのヨーロッパのソフトウェア国際化チームがそれにならってInternationalizationをI18Nと略すようになった。

当時のDECの社内は全てのマシンがDECNETで結合されていてI18N::というノードも存在した。

------------------
さて上記のような蘊蓄を語ろうと思ったのだけど、記憶が曖昧だったので当然Googleにたよった。しかし、i18nだけで検索したらどう考えても、どうでもいい定義には行きつくが、起源までには辿りつけないと思った。

そこで、自分のはてなの日記(未来のいつか/hyoshiokの日記)をi18nで検索するが回答にたどりつけない。http://d.hatena.ne.jp/hyoshiok/searchdiary?word=i18n

自分はDECが起源であるという正解を知っているので、その知識を利用して、「dec i18n 起源」を検索キーワードとして検索した。

そうすると、http://b.hatena.ne.jp/donayama/20060930というブックマークがあって、その対象がそのものズバリの質問である。

LocalizationをL10N, MultilingualizationをM17N, InternationalizationをI18Nという風に省略しますが、こういう風な表記をし始めた発端、普及した経緯・きっかけなどを教えて下さい。http://q.hatena.ne.jp/1159582709

そして、その第一回答がそのものずばりの回答で、
http://www.i18nguy.com/origini18n.html
である。

Excerpts of the Email Discussionでの登場人物は80年代後半〜90年代にソフトウェア国際化で活躍したエキスパート達である。Jim Melton はDECで ISO SQL標準にかかわり(SQL標準の編集者)、SQLの国際化機能を設計した人、John McConnel、Tim Greenwoodは当時のDECの国際化アーキテクト(わたしもその一人)、樋浦さんはSunの人である。

--------------------
まったくもって思い出モードにはいってしまうのだが、80年代というのはソフトウェアの国際化という概念がまだ確立されていなかった。当時日本DECという外資系に勤務していて、ソフトウェアの日本語化に四苦八苦していたわたしはどうにかしてこの問題を解決したいと強く思っていた。未来のいつか日本語化というような作業なしに英語と同じように簡単に日本語が利用できる世界を夢見ていた。

米国本社と議論をかさねるうちに、ソフトウェアの国際化で苦労しているグループがヨーロッパにいることを知った。わたしにとっては米国も欧州も同じようなものかと思っていたので(われわれはよく欧米と一括りにする)、驚きであった。

ドイツ語、フランス語のアクセント記号やウムラウト付文字は7ビットのASCII文字にははいっていないので、それらの言語が正しく表現できないのである。

ソフトウェアが7ビットASCIIを仮定していたので欧州系の言語ですら正しく表現されないというのが80年代初頭の状況であった。そこでヨーロッパのエンジニアリングチーム(Jurgen Bettelsらのチーム)と共同でソフトウェアの国際化について議論をはじめたのが80年代中頃である。その後、各種標準活動を通じて他社のエンジニアと議論をふかめていった。

当時のプログラミング言語はCを筆頭にASCII前提の言語仕様になっている。ソースコードがASCII前提というのは現実的制約ではあるが、プロセスコードも多くはASCII前提である。

UnixはCの影響でばりばりASCII依存のコードになっていたのはよく知られている。

当時は、わたしはDEC Rdbの開発チームにいたので、Jim Meltonらとも標準や実装について徹底的に議論をしたし、その後ISO/IEC JTC1/SC22/WG20  というそのものずばりソフトウェア国際化について議論するグループに参加したので、企業や地域の枠を越えたコラボレーションをおこなっていた。標準化活動というのは通常は企業の利害対立の場でもあるのだがソフトウェア国際化という夢の実現にむけては利害が一致していた。非常に貴重な経験をしたと思っている。

企業や地域の枠を越えたコラボレーションの例としてISO/IECのような標準化団体での活動、Xコンソーシアムのような産学共同プロジェクト、/usr/groupなどのUnixユーザグループなどの形態がいろいろあるが、それらのコラボレーションの経験を積んだ人々は、オープンソースのバザールモデルへの理解が深いのも特徴だといえる。

解くべき正しい問題を解決するには地域や組織の枠をこえた多くの人や組織とのコラボレーションが必須であることを、わたしはその経験から学んだ。それがわたしのオープンソースに対するコミットメントの原点にもなっている。

マルチプロセッサ向けソフトウェアパラダイムとは?(その2)

マルチプロセッサ向けソフトウェアパラダイムとは?」で、今後はますますマルチプロセッサ技術が重要になると指摘した。

またありがたいことにいくつかトラックバックをいただいた。

「Cのような低レベルの言語で書いているのであれば、それもしょうがないと思うが、スクリプト言語で書いたようなアプリケーションであれば言語処理系でよきにはからって欲しいとも思う。例えば構文で繰り返しを発見したらそれを自動的に並列化するくらいの事をやってくれてもばちはあたらない。Fortranのような数値計算処理系だとDOループを自動的にパイプライン化したり並列化したりして性能向上をシステムがおこなってくれたりする。」

薄いブログ/ホワット・ア・ワンダフル・ワールド

それなんて第五世代コンピュータ計画,と

ムーアの法則によりインテルの単一 CPU パワーの激増によって淘汰された超並列計算機アーキテクチャとプログラミングが,ムーアの法則の限界に直面し再び表舞台に復活するかもしれない,という歴史の皮肉.やはり時代を先取りしすぎだったのでしょうねぇ.

とのこと。

第五世代は論理型プログラミングだったけど、もちろん関数型言語やスクリプト言語でもかまわない。副作用のない言語だと並列性を発見した時の処理が素直に実装できるのでいく分有利かもしれない。

APLのような配列を簡単にあつかえる言語もいいかもしれない。PrologとかGHCとかKL1みたいな言語を勉強するのもいいかもしれない。

コンピュータアーキテクチャとして大規模並列マシンのコネクションマシン(プロセッサ数約6万)での経験より、
http://www.personal-media.co.jp/book/comp/062_f.html#part1

アルゴリズムの研究も必要である。ハロルドストーン(IBMワトソン研)はIEEE Computer誌にコネクションマシン上の文献検索アルゴリズムは一見高次の並列度を有しているように見えるが、インデックスを利用したシーケンシャルアルゴリズムを用いれば同じ主記憶サイズのたった1台のプロセッサで実行した方が速いという結果を詳細に導きだしている。このように必ずしもプルートフォースなアプローチで並列度が出たと喜んでいてもすぐ足をすくわれかねない。

並列度を生かすアルゴリズムの研究がかかせない。つまり並列度を構文的に発見できたとして、それを単にプロセッサにはりつけているだけではだめだったりするのである。

実装においても、いろいろな工夫が必要かと思うが、まだまだこれからの世界だと思う。

Pugsでの実装例
Parallel Scripting Now!

% /usr/bin/time pugs -e '(1..100000).>>sqrt'
        9.27 real         9.09 user         0.13 sys
% env GHCRTS=-N2 /usr/bin/time pugs -e '(1..100000).>>sqrt'
        5.79 real         6.92 user         0.15 sys

More SMP parallelism.
デュアルぐらいではパラダイムはシフトしがたい
 
Rubyのまつもとさんのブログより
20XX年のユビキタス、ロボット、Web/Tech総研

プログラミング言語も超メニーコアの時代になって、 1PCに65536個くらいCPUが載るようになると並列性を人間に取り扱える形で(つまり、あまり見せないように)、取り扱える言語が求められるようになり、 FORTRANのベクトル化技術に類似するものが復権してスクリプト言語を含めて広く利用されるようになる。

か、並列化が行いやすい副作用のない関数型言語が今とは別の意味で注目される。

http://www.rubyist.net/~matz/20070104.html#p02

BINARY HACKS

高林さんに献本(Binary Hacks)をいただく。本日到着しました。ありがとうございました。

昨年12月にあったBinary 2.0カンファレンスをきっかけにできあがった書籍である。素晴しい。わたしも高林さんのブログでBinary 2.0カンファレンスを知り、早速申し込んだ口であるが、無理矢理すべりこむため(だって、あっと言う間に満員で登録締切になってしまったから)、持ネタのCache Pollution Aware Patchを5分でプレゼンをした。

Binary 2.0で発表。
ライトニングトーク
Binary 2.0

先日、Gree主催のオープンソーステクノロジ勉強会で鵜飼さんの「プログラムが main()にたどりつくまで」を聞いたのだが、その宴会で高林さんからBINARY HACKSを送りますよ〜というありがたいお言葉。

さて、第6章プロファイラ・デバッガHackである。#87〜#89の例が残念ながらショボイ。人工的すぎてリアリティがない。やはり、rubyのキャッシュミスを測定するくらいの実アプリを意識した例になっていたらと思う。(おしい)

もちろんだからと言って本書の価値がそこなわれているわけではない。

#89でoprofileを有効にする場合のカーネルの設定でCONFIG_PROFILINGおよびCONFIG_OPROFILEをオンにしておくというのがあるが、コールグラフを計測するには、それに加え、Kernel HackingのCONFIG_FRAME_POINTERをオンにしておく必要があると思う。このフラグをオンにしていないのがデフォルトなので、結構はまるところである。

キャッシュミスを検出する(337ページ)でeventとしてBSQ_CACHE_REFERENCEを、マスクとして0x10fをあたえている。BSQ_CACHE_REFERENCEというのは、Pentium 4ないしXeonのイベントなので、PentiumIII以前や最近のCoreプロセッサでは当然違うイベントになるし、それらの情報については、IA-32 Intel Architecture Software Developer's Manual Volume 3B, System Programming Guide, Appendix Aの表を見よという情報がないと、わけがわからないと思う。#91「ハードウェアのデバッグ機能を使う」では上記のリファレンスが載っているので#89は若干不親切な気がする。

イベントマスクの0x10fなのであるが、当該マニュアルを見ると
Bit
0: RD_2ndL_HITS
1: RD_2ndL_HITE
2: RD_2ndL_HITM
3: RD_3rdL_HITS
4: RD_3rdL_HITE
5: RD_3rdL_HITM
8: RD_2ndL_MISS
9: RD_3rdL_MISS
10: WR_2ndL_MISS
となっているので、0x10fはRD_2ndL_MISS/RD_3rdL_HITS/RD_2ndL_HITM/RD_2ndL_HITE/RD_2ndL_HITSがオンだという事を示している。ということはL2キャッシュミス(RD_2ndL_MISS)だけではなく、L3キャッシュヒット(RD_3rdL_HITS)およびL2キャッシュヒット(RD_2ndL_HITM/RD_2ndL_HITE/RD_2ndL_HITS)も同時に計測しているような気がする。(いかがだろうか?)

#94「プロセッサのメモリオーダリングに注意」の例のプログラムだが、これはメモリオーダリングの例ではなくてアトミックな交換(xchg)が出来ていない例なのではないだろうか?

アプリケーションレベルでメモリオーダリングに注意しなければいけない例というのはあまり思いつかなかったのでもし適切な例があればご教示いただきたいところである。

以上重箱の隅をつつきまくったが、つつきたくなるほど素晴しい本である。通勤電車の行き帰り、没頭して乗り過す危険性が高い本でもある。この第二版の企画があったらぜひcrashダンプの読み方、kprobe/djprobeやsystemtapなどの話も追記してほしいところである。

高林さんのブログ
Binary Hacks が届きました/いやなブログ

小飼弾さんのブログ
Binary Hacks/404 Blog Not Found

Rubyのプロファイリングをするお話などは下記を参考。

コードを読むな、理解しろ
Rubyのプロファイリング

生産性

生産性という言葉はおそらく経済学から来ているのだと思うが、経済学者でないわたしがアバウトな理解で使うと火傷をするのでいろいろグーグルで検索してみた。

生産性(productivity)=産出量/投入量

この産出量というのは製造業とか農業だと、ねじだくぎだ、あるいは米だ麦だという計測が極めて容易で、投入量も、労働時間とか、土地だ、原料だとこちらも計測可能なので、生産性の測定も簡単にできる(と思う)。ところがこれがサービス業だったりすると産出量っていったいなんなんだと言うことになる。

ソフトウェア品質管理の文脈でいうと産出量を価値とおきかえて議論する事が多い。この価値というのも、ねじやくぎと違って簡単に測定できないので、近似値として製品価格とかを置く場合が多い。価格を近似値として利用するのは、価値は市場で価格として評価されるからという前提をおいているからである。価値より高い価格をつければ需要が少ないので、おのずと価格は下落し、価値より低い価格をつければ需要が多いので、価格は上昇し結果として適切な価格に収斂するという理屈である。

生産性=価値/投入量

ソフトウェアの場合、投入量というのは通常労働時間になるので(機械によって完全に自動化はできない)、それを工数(人月で計測したりする)という単位で近似すると以下になる。

生産性=価値/工数

ソフトウェアの価値はソフトウェアの機能という形で実装されるので、それをいれると次になる。

生産性=(価値/機能)*(機能/工数)

価値は機能で実装されているのだが、機能Aの価値と機能Bの価値は当然違うので単位機能あたりの価値が高い機能を実装したほうがこのましい。ひらたく言うとみんなが欲しがる機能は誰も使わない機能より価値があるので、そのようなものを作りましょうという話である。一方、ある機能を実装するには当然工数がかかるのだが、簡単に実装できるもの(工数が小さい)ものもあれば非常に時間がかかるもの(工数が大きい)ものもある。

前者を価値生産性、後者を機能生産性として定義すると、ソフトウェアの生産性というのが後者の生産性に注目していることが往々にしてある。(狭義の生産性)

価値生産性=価値/機能
機能生産性=機能/工数

狭義の生産性を向上させるためにはいかにして工数を削減するかという議論のもと、テストの自動化をしたり、要求仕様の厳密化をして手戻りを削減したり様々なソフトウェア工学的なアプローチが提案実践されてきている。

機能生産性もさらに分解してみると

機能生産性=(機能/コード量)*(コード量/工数)

前者(機能/コード量)はある機能を実装するのに必要なコード量の比率で定義でき、コードの表現力が大きいほど生産性が高くなる。豊富なライブラリが充実していて、コードを書かなくても、ある機能を簡単に実装できたり、メタプログラミングによってコードのほとんどを再利用できたりすると前者の生産性はあがる。これを仮にコード生産性とよぶ。

コード生産性=機能/コード量

後者(コード量/工数)は、あるコードを書くのに必要な工数の比率で定義し、狭義のプログラマの生産性といえる。これを仮にプログラマ生産性とよぶことにする。プログラマAとプログラマBとが単位時間あたりに生産できるコードの量というのは相当違うというのをわれわれは経験的に知っているが(時には100倍くらい違うのであるが)、その差について積極的に議論することはある種のタブーになっているような気がする。

プログラマ生産性=コード量/工数

コード生産性というのは、ある意味プログラミング言語の歴史でもあり、機械語、アセンブリ言語、低水準言語、高水準言語、…という方向で、単位コードあたりの機能の向上という進化をとげてきた。プログラミング言語におけるパターンランゲージの利用というのは、ある言語でのベストプラクティスを再利用するという試みで、機能の実装に関して、ほとんどコピペですましてしまおうという風に理解できる。

機能生産性(コード生産性*プログラマ生産性)というのはかなりホットに議論されているが広義の生産性の重要なファクタである価値生産性には一切関与しないことに注意したい。

生産性=価値生産性*機能生産性

生産性の向上には機能生産性の向上だけではなく価値生産性の向上が不可欠なのである。

機能生産性の向上にはハッカーをどれだけ発見し育てるかという観点があると思うが、価値生産性の向上には全く別の方法論が必要になる。

つまりどんな世界最強のハッカーと世界最強のプログラミング言語とその環境、パラダイムをもってしても価値生産性の向上には直接的には寄与しない。

価値生産性は結局のところ、顧客が求めるものをいかに経済的に提供するかということにつきる。品質管理の言葉では顧客満足度(品質)というもので定義されているが、価値生産性を向上させるためにはいかにして顧客満足度を向上させるかという事ど同義である。

ソフトウェア製品においては早期に顧客に製品を投入して(ベータ版など)、顧客の声を積極的にとりいれるというようなことが行なわれているが言うほど簡単な話ではない。

生産性の向上のためには価値を向上させなければいけないというのが本日の結論なのであるが、どうやって価値を向上させるかというのは試行錯誤というのが実状である。

もちろんソフトウェア工学的アプローチ、品質保証的アプローチ、プロジェクトマネージメント的アプローチ等々、様々あるが本当の意味で価値を向上させるのは人に強く依存しているというのも、また厳然たる事実である。

下記は主にコード生産性(機能生産性の一要素)に関する議論となる。

Rubyの生産性の高さはどこまで本当か?/分裂勘違い君劇場
http://d.hatena.ne.jp/fromdusktildawn/20061002/1159784863

Rubyを仕事に使うべし!Part1 なぜ仕事で使うとうれしいのか
http://itpro.nikkeibp.co.jp/article/COLUMN/20060919/248312/

プログラミング言語foobarの生産性の高さはどこまで本当か/404 Blog Not Found
http://blog.livedoor.jp/dankogai/archives/50647659.html

価値生産性と機能生産性についてを正しいものを作ることと、正しくものを作ることと対比した。

正しいものを作ることと正しくものを作ること(未来のいつか/hyoshiokの日記)
http://d.hatena.ne.jp/hyoshiok/20050508

価値生産性の向上についてのエントリーは少ない。

ソフトウェア開発の生産性と good enough(未来のいつか/hyoshiokの日記)
http://d.hatena.ne.jp/hyoshiok/20040522

hatenalabo(未来のいつか/hyoshiokの日記)
http://d.hatena.ne.jp/hyoshiok/20060225#p1

トラブルシューティングの実際

レガシーエンコーディングのプロジェクトなんかやったものだから中途半端に各種OSSの実装に詳しくなった。ノートPCには、開発環境が残っているので、ちょっとコードを覗いてみっか、という敷居がぐぐっと下って、すぐに当該ディレクトリにcdしてfindそしてegrepだ。
中途入社の方の日報に下記のような感想というか所感を見付けたので、早速返事を書いた。

>> サポート業務全般に言えるのだが、どこを調べれば
>> よいという経験やノウハウが足りないので時間が
>> かかってしまいます。これから知識や経験を
>> 身に付けていかなくてはいけないと感じました。

わたしの返事:

> どのように調べたかログをとっておくと後から
> 役に立つのでおすすめです。
>
> そしてそれを公開すれば、新人にも役にたつし
> 達人からの突込みも期待できるので、自分の
> 役にもたちます。

ログだよログ。そーゆーわけで、たまたまみかけたmysqlメーリングリストで議論されていた不具合について、どのように追っていったか記してみる。

\(半角)→\(全角)という問題である。
円マークが全角の\に化けると。

藤原さんが「MySQL日本語の旅」 を紹介していて、「バックスラッシュ(\,5C)が文字化けする(続々編)」を 読むと、

mysql> SELECT HEX(CONVERT( _ujis 0x5C USING sjis ) );
+----------------------------------------+
| HEX(CONVERT( _ujis 0x5C USING sjis ) ) |
+----------------------------------------+
| 815F                                   |
+----------------------------------------+
1 row in set (0.00 sec)

となる。0x815Fを何か特別に変換しているようだ。
eucjpmsという謎のコードセットではどうだろうか?ちなみにこのeucjpmsというのは今回作ったレガシーエンコーディングの一つである。

mysql> SELECT HEX(CONVERT(  _eucjpms 0x5C USING sjis ) );
+--------------------------------------------+
| HEX(CONVERT(  _eucjpms 0x5C USING sjis ) ) |
+--------------------------------------------+
| 815F                                       |
+--------------------------------------------+
1 row in set (0.01 sec)

あれれ?それではcp51932ではどうだ?

mysql> SELECT HEX(CONVERT(  _cp51932 0x5C USING sjis ) );
+--------------------------------------------+
| HEX(CONVERT(  _cp51932 0x5C USING sjis ) ) |
+--------------------------------------------+
| 815F                                       |
+--------------------------------------------+
1 row in set (0.00 sec)

ここでeucjpmsとかcp51932とかをいきなり持ち出したのは文字コードに関する知識を持っていたのと、たまたまレガシーエンコーディングプロジェクトでそれを実装したからであるが、当該ページではutf8とかlatin1で確認しているので、今回のトラブルシューティングにおいては問題領域依存の知識というのはあるに越した事はないが必須の知識というわけでもない。 力づくでfind/egrepで検索すると下記になる。

$ time find -type f|xargs egrep -il 815f
./Docs/mysql.info
./strings/ctype-cp932.c
./strings/ctype-eucjpms.c
./strings/ctype-gbk.c
./strings/ctype-sjis.c
./strings/ctype-ujis.c
./strings/ctype-cp51932.c~
./strings/ctype-cp51932.c
./mysql-test/t/ctype_cp932.test
./mysql-test/r/ctype_cp932.result
./mysql-test/r/ctype_eucjpms.result
./cscope.out

real    0m0.890s
user    0m0.436s
sys     0m0.253s

とでるので、./strings/ctype-sjis.cあたりを眺めてみる。すると

$ egrep -iC 3 815f ./strings/ctype-sjis.c
     0,     0,     0,     0,     0,     0,     0,     0,
0x968B,0x8146,0x813E,0x8153,0x8151,0x80FC,0x8171,0x816E,
0x8165,0x8166,0x8174,0x8183,0x8188,0x818A,0x8180,0x8182,
0x81A0,0x8195,0x81A4,0x81A3,0x815F,0x8193,0x81A9,0x81B0,
0x81B5,0x81BE,0x81B8,0x81BD,0x81C0,0x81C2,0x81BA,0x81C9,
0x81CD,0x81D1,0x81D9,0x81D8,0x81C8,0x81DA,0x81DF,0x81E0,
0x81E7,0x81FA,0x81FB,0x81FE,0x8201,0x8202,0x8205,0x8207,
--
}
/* page 0 0x005C-0x00F7 */
static uint16 tab_uni_sjis0[]={
0x815F,     0,     0,     0,     0,     0,     0,     0,
     0,     0,     0,     0,     0,     0,     0,     0,
     0,     0,     0,     0,     0,     0,     0,     0,
     0,     0,     0,     0,     0,     0,     0,     0,
--
  {
    if (wc == 0x5c)
    {
      code= 0x815f;
      goto mb;
    }
    s[0]= (uchar) wc;

というあやしげなコードが発見される。5c(\)の時わざわざ815f(\)しているのである。なぜだか知らないが、そーゆーコードがあるのである。cp932というコードページには同様のコードがないのでsjisだけの実装と言える。(ここでcp932というコードページをもちだしたのは問題領域依存知識なので、知らないと解決するのに時間がかかってしまうが strings/ctype-cp932.c というファイルがそれを実装しているというのはfind/egrepで発見できているのでたどりつけないわけではない)

そこで、先程のmysqlのサンプルをsjisからcp932に変えてみると、

mysql> SELECT HEX(CONVERT(  _ujis 0x5C USING cp932 ) );
+------------------------------------------+
| HEX(CONVERT(  _ujis 0x5C USING cp932 ) ) |
+------------------------------------------+
| 5C                                       |
+------------------------------------------+
1 row in set (0.01 sec)

となり所望の動作になった。

ここに到着するまで15分くらいかな。
(というか、ブログを書く時間の方が長かったくらいだ)

Happy Hackingである。

テストの参考書

ソフトウェアにおけるテストとは何か?端的に言えば、ソフトウェアの不具合を発見するための一連のプロセスである。
テストはソフトウェアの不具合を発見するプロセスなのだから、良いテストというのは効率よく不具合を発見するものであり、悪いテストというのは不具合を発見しないものである。
テストではプログラムのエラーを示すことはできるがバグがないことを証明することはできない。Myersの古典的名著「ソフトウェア・テストの技法 第2版」(最近第二版が発行された)では、成功したテストとはエラーを発見したテストであると定義している。なかなか強い立場である。

若い人の中にはを読んだことがない人がいるかと思うので、参考書として推薦しておく。
今度プロジェクトでご一緒する若手のエンジニアにはとりあえづMUSTで読めと言っておいた。

コードを読むな、理解しろ

コードを読まないで理解するというと何やら心眼で読めとかテレパシーを使えとか、そーゆー荒唐無稽な方向に走れという事ではなく大局的に理解しましょうという話である。

カーネル読書会のネタで今回はmallocのお話だったのだが、そこでRubyのささださんがいらっしゃっていて、GC(ごみ集め)と記憶域管理の関係について熱い議論が沸騰し、その後いろいろブログなどでフォローされていたりする。

わたしもRubyでmallocやGCがどう実装されているか興味があったのでoprofileで実行プロファイルをとってみたりした。日頃利用しているノートPCでRubyのテストプログラム(test/runner.rb)を実行してoprofileしたのは先日ブログに書いたとおりである。

「それとわたしのノートPCではキャッシュミスを測定できないので、Xeonのマシンでキャッシュミスを測定すると面白いと思った。GCの時ぼろぼろキャッシュミスが発生するということだが、それを巧みに減らすというのが課題になる」ユメのチカラ:Rubyのプロファイリング

思いたったら吉日ということで、会社の最新のDual Coreマシンでキャッシュミスも計測してみた。

そうすると案の定GCでキャッシュミスが多発しているので、そこにちょっとしたパッチをあてればキャッシュミスを減少できるだろうという仮定のもと1行パッチを作成し効果を測定した。キャッシュミスは約半分に減ったのだが実行時間にはほとんど影響がなかった。残念。

さて、oprofileで実行プロファイルを取ってからRubyのパッチを作るまでの道のりであるが、わたし自身はRubyのソースコードにはまったく土地勘がなくほぼ「まるで初めて(略して(まるは)」の初心者が、どのようにパッチを作るかというケーススタディは、初心者ハッカーが自分で獲得しなければいけない道のりという意味でなんかの参考になるのではないかと思い記してみる。

自分のノートにはruby 1.8.4しかはいっていなかったので、最新版の1.8.5をダウンロードする。パッチを作る時、最新版でやるというのは基本中の基本である。(まるはの皆さんここ重要です)

なぜ最新版でやらなければいけないかという理由は101以上あると思うのだが、2〜3あげると、1)最新版ではその問題はすでに解決しているかもしれない、2)コミュニティの力を借りるためには最新版の方が力を借りやすい、3)作成したパッチを本家にとりこんでもらうためには最新版で作成する必要がある、等々。

oprofileを効果的に利用するために、kernel-debuginfoパッケージをあらかじめインストールしておく必要がある。これはカーネルのシンボルを表示するためである。Asianux 2.0 (MIRACLE LINUX 4.0) では kernel-debuginfo-2.6.9-11.19AX というパッケージである。

キャッシュミスイベントを計測するためにインテルのマニュアルを参照する必要がある。Pentium4系のイベントとDual Core系のアーキテクチャでは計測できるハードウェアイベントが異なるので注意が必要である。

今回は下記のようなイベントを設定した。Weighted cycles of L1 miss outstanding というイベントで10万回ごとにサンプリングして、カーネルおよびユーザーモードのイベントを計測する。

opcontrol --event=DCACHE_PEND_MISS:100000:0:1:1

opreport -l
で関数ごとの頻度が表示されるので、最初の2〜3の関数から調査をする。

opreport -dg 詳細が下記のように表示される。

CPU: Core Solo / Duo, speed 2666.77 MHz (estimated)
Counted DCACHE_PEND_MISS events (Weighted cycles of L1 miss outstanding) with
a unit mask of 0x00 (Weighted cycles) count 100000
        vma      samples  %        linenr info                 app name symbol name
000000000042be50 244787   33.2383  gc.c:1661                   ruby         os_each_obj
  000000000042bfac 1        4.1e-04  gc.c:1599
  000000000042bfb9 5         0.0020  gc.c:1599
  000000000042bfbe 6         0.0025  gc.c:1599
  000000000042bfd0 4862      1.9862  gc.c:1601
  000000000042bfd3 228573   93.3763  gc.c:1601
  000000000042bfd6 2698      1.1022  gc.c:1601
  000000000042bfd8 250       0.1021  ruby.h:672
...

gc.c 1601行目でキャッシュミスが多発しているのが分る。

さてここからソースコードの旅がはじまる。

static VALUE
os_obj_of(of)
    VALUE of;
{
    int i;
    int n = 0;

    for (i = 0; i < heaps_used; i++) {
RVALUE *p, *pend;

p = heaps[i].slot; pend = p + heaps[i].limit;
for (;p < pend; p++) {
    if (p->as.basic.flags) { /* ここの部分 */
switch (TYPE(p)) {
  case T_ICLASS:
  case T_VARMAP:
  case T_SCOPE:
  case T_NODE:
    continue;
  case T_CLASS:
    if (FL_TEST(p, FL_SINGLETON)) continue;
  default:
    if (!p->as.basic.klass) continue;
    if (rb_obj_is_kind_of((VALUE)p, of)) {
rb_yield((VALUE)p);
n++;
    }
}
    }
}
    }

    return INT2FIX(n);
}

コードを読まづして、高速道路で一気に目的地に到着した。キャッシュミスが多発している場合の性能向上のパターンとして、1) プリフェッチ、2) カラーリング、3) ブロッキング、等々いろいろある。

プリフェッチというのは、メモリにアクセスするかなり以前にあらかじめフェッチ(アクセス)しておいて、キャッシュに載せておき、実際にアクセスする時点ではキャッシュに載っているのでレイテンシーが低くなる(高速にアクセスできる)というテクニックである。

for ループだと次にアクセスする要素があらかじめわかっているので簡単にプリフェッチのコードを仕込むことができる。コード変更量最小化の法則にしたがうとこれは非常にやりやすい変更である。

ここまではコードを読まづにたどりついたわけだ。パフォーマンスボトルネックという現象を理解するためには、コードを読まづしてツールを利用すればできるという事である。コードの字面だけを追っていてはキャッシュミスや性能上の問題は発見できない。

# diff -u gc.c~ gc.c
--- gc.c~       2006-08-25 17:12:46.000000000 +0900
+++ gc.c        2006-10-03 10:47:08.000000000 +0900
@@ -1594,10 +1594,15 @@
     int n = 0;

     for (i = 0; i < heaps_used; i++) {
-       RVALUE *p, *pend;
+       RVALUE *p, *pend;

        p = heaps[i].slot; pend = p + heaps[i].limit;
        for (;p < pend; p++) {
+         if ( (p+1) < pend) {
+               __asm__ __volatile__ (
+                  " prefetch (%0)\n"
+                  : : "r" ((p+1)->as.basic.flags) );
+           }
            if (p->as.basic.flags) {
                switch (TYPE(p)) {
                  case T_ICLASS:

というパッチになった。

コードを読むな、コードを理解しろ

という事である。

参考:

まつもとさんの日記

未来のいつか/hyoshiokの日記 Rubyのキャッシュミスを測定する。

未来のいつか/hyoshiokの日記 Cache Aware Ruby Patch

Rubyソースコード完全解説という名著があるが、その第5章も大変参考になった。

第67回カーネル読書会、ビデオ公開

第67回カーネル読書会のセミナー部分のビデオを公開した。今回は

お題: glibc malloc について
発表者:小崎さん

malloc関数はlibcの中でもっとも使用頻度が高い関数の一つでありながら、そ
の実装の詳細は意外なほど知られていません。

Unix誕生当初のプログラミングスタイルでは、ほとんどのデータはスタックと
グローバル変数に格納されており、mallocの使用頻度は低かったようです。し
かし、今日ではGUI、スクリプト言語、C++といったmallocを多発するソフトウェ
アが極めて一般的になり、mallocの性能の重要度は増しています。

こうした点に注目して、素朴な malloc では何が問題だったのか。また、
glibc malloc がどういった点に注力してチューニングされているのか。といっ
た点を説明できれば。と思います。

資料はYLUGのホームページからダウンロードできる。

ビデオ撮影、編集、Googleへのアップロードはびぎねっとの伊藤さんのご尽力による。どうもありがとうございました。

梅田望夫氏との対談イベントもそうだったのだが、こうやってカーネル読書会とか各種勉強会、セミナーとかをどんどん無償でネットワークにアップロードするというスタイルが一般化するとまた違った可能性が広がっていくようでいて大変面白い。

内容はmallocに関する技術的な詳細の説明である。mallocという関数は厳密にいえばCのライブラリ関数なので、カーネルのシステムコールではないのだが、一般アプリケーションから非常によく使う関数の一つであり、カーネル読書会の題材としてはぴったりのものである。メモリ管理というのはまさにカーネルの最も重要な機能の一つなので、カーネルやライブラリがそれをどのように実装しているかを理解することは大切である。

オープンソースなので実装の隅々までオープンに議論できるのがうれしい。カーネルの専門家ではなくても、アプリケーション開発者の立場から、いろいろ質問したり、突っ込みを入れたりできるのがうれしい。カーネル開発者(ライブラリ開発者)にとってみれば自分が提供するサービスがどのように利用されているかの声を聞けて双方にとって有益な情報交換になる。

今回もmalloc/freeのコストについてRubyの笹田さんがRubyでのメモリ管理の観点から細かい突込みを入れていたが、OSとアプリケーション(この場合はプログラミング言語の実装)の境界を越えて、いろいろ議論できるのが楽しい。

いっそのこと、カーネルやライブラリのレイヤではなく、もう少し上のレイヤ(例えばスクリプト言語とかRDBMSとか)で自前のメモリ管理機能を持ってがしがし最適化するのもありなんではないかというような議論も当然でる。ライブラリは汎用化しなくてはいけないので、ある用途に徹底的に最適化することはできないがRubyならRuby、PerlならPerl、あるいはPostgreSQLならPostgreSQLなりのメモリ管理システムを持ち、カーネルに独立して徹底的にメモリ管理を最適化する。キャッシュミスを削減したりマルチコア、マルチスレッドに最適化するなどいろいろなアイデアが出てきそうである。

このような議論は、カーネル、ミドルウェア、スクリプト言語といった縦串をまたがった議論になる。オープンソースなので自由にその境界線を設定できる。一つの場所に集い自由に議論をする。そこにソースコードがあるからこそそれが自由にできるのである。

小崎さんのブログ、
革命の日々!
カーネル読書会で講演してきました

未来のいつか/hyoshiokの日記
第67回カーネル読書会

Linux Kernel 2.6.18とCache Pollution Aware Patch

9月20日に最新のLinuxカーネルが公開された。最近ではだいたい3ヶ月程度で新バージョンが公開されているというペースである。

  2.6.12  2005/06/17
  2.6.13  2005/08/29
  2.6.14  2006/10/28
  2.6.15  2006/01/03
  2.6.16  2006/03/20
  2.6.17  2006/06/18
  2.6.18  2006/09/20

実はこのバージョンには、わたしが書いた cache pollution aware patch というのが入っている。パッチそのものは昨年の今頃に書いたもので、すぐにAndrew Mortonのmmツリーと呼ばれるものにはマージされたのであるが、Linus Torvaldsの本家のツリーにはなかなかマージされていなかった。

Cache Pollution Aware Patchというのは、一言で言うと、コンピュータの中央処理装置(CPU)にはキャッシュというメモリアクセスを高速化するハードウェアが付いているが、ちょっとしたトリックを使って、その処理をさらに高速化するというものである。

コンピュータはムーアの法則によって約18ヶ月で半導体の集積度を倍に向上させてきた。CPUの処理速度もそれに比例して年々向上してきた。メモリの速度はCPUの処理速度の向上に比べ遅いペースで向上してきているので結果としてCPUから見てメモリアクセスというのは遅い処理に見えてくるようになった。

最近のプロセッサだとメモリへのアクセスは200〜300クロック程度かかる。CPUクロックが2GHzのマシンだと1クロックあたり0.5nsec(ナノ秒=10億分の1秒)なので、100nsec〜150nsecかかる。それでも随分速いように思えるが、レジスタへのアクセスが2クロック程度なので100倍程度遅いことになる。

そこで、遅いメモリとレジスタの間にキャッシュと呼ばれる容量は小さいけど高速のメモリを置き、メモリアクセスを高速化する。1次キャッシュ(L1と呼ぶ)はインテルのPentium 4だと8KB(キロバイト)で202クロック程度でアクセスできる。キャッシュにデータが載っていればメインメモリにアクセスするより10100倍程度速くアクセスできる。

キャッシュのサイズは小さいので、どのようなデータをキャッシュに載せ、どのようなデータをキャッシュに載せないのかが性能を左右することになる。必要なデータがキャッシュにある時、それをキャッシュにヒットしたとよび、キャッシュにない時、キャッシュミスしたとよぶ。

性能を向上させるためには、いかにしてキャッシュミスを減らすか(キャッシュヒットを増やすか)というのが重要になってくる。

どのようにキャッシュにデータを載せるかというアルゴリズムは広く研究されている。通常はCPUがメモリにアクセスする時、まづキャッシュに当該データが載っていないか調べ、載っていればキャッシュからデータをとってきて(速い)、載っていなければ、メモリにアクセスし(とても遅い)、キャッシュに載せる。わざわざキャッシュに載せるのは、一度アクセスされたデータは近い将来またアクセスされるかもしれないので、それを期待してとりあえづキャッシュに載せておくのである。これを時間的局所性があると言うが、これは思いのほか上手くいく戦略である。

またメモリからキャッシュにデータを載せる時、アクセスするメモリの周辺のデータも一緒に持ってくる。Pentium 4の場合、64バイトないし128バイトをキャッシュに載せる。これはあるデータにアクセスしたらその近傍のデータにもアクセスする可能性が高いと仮定していて、そのような性質を空間的局所性があると言うが、これも思いのほか上手くいく戦略である。

メモリアクセスのスピードとCPUの性能向上のギャップは年々拡大傾向にあるので上手にキャッシュを利用するアルゴリズムは益々重要になってきている。

さてCache Pollution Aware Patchなのであるが、キャッシュポルージョン(cache pollution)というのは、キャッシュにデータを載せる時、キャッシュのサイズは限られているのでキャッシュ上のデータを捨てないといけないが、その時、すぐに利用される有効なデータを追い出してしまい、結果としてすぐにキャッシュミスを発生させるような状況をさす。

時間的な局所性がない(すぐに再度アクセスされない)データをキャッシュに載せるのはキャッシュポルージョンを発生させるのでよろしくない。

時間的な局所性があるのかないのかというのは通常はなかなかよくわからないのであるが、今回のパッチの作成にあたっては、oprofileというカーネルプロファイリングツールを利用して、カーネルのどこでキャッシュポルージョンが発生しているかを特定した。厳密に部位を特定できたのでパッチの作成そのものはそれほど困難ではなかった。

インテルのPentium4/Xeonプロセッサはデータをアクセスする時にキャッシュをバイパスする命令がある。今回のパッチではカーネル中のキャッシュポルージョンを発生している部分でキャッシュをバイパスする命令を利用しキャッシュポルージョンを効果的に削減した。

iozoneというベンチマークを利用した性能評価ではwrite()システムコールにおいて約10%の性能向上が確認できた。

Linux Kernel 2.6.18
http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2
http://www.kernel.org/pub/linux/kernel/v2.6/ChangeLog-2.6.18

Cache Pollution Aware Patch (わたしが作ったパッチ)
http://kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c22ce143d15eb288543fe9873e1c5ac1c01b69a1

未来のいつか/hyoshiokの日記
cache pollutionに関する記述がいくつかある。
http://d.hatena.ne.jp/hyoshiok/searchdiary?word=cache%20pollution

2005年度オープンソースソフトウェア活用基盤整備事業
「OSS性能・信頼性評価/障害解析ツール開発」
OS層
〜CPUスケーラビリティ評価編〜
http://www.ipa.go.jp/software/open/forum/development/download/051115/OS-cpu.pdf

訂正:L1キャッシュのアクセスを20クロック程度ではなく、2クロック程度と訂正しました。L1キャッシュとメモリのアクセスの性能比は100倍程度になります。

gdbの実践的使い方

「大規模ソフトウェアの効率的な理解(その123456)」などという大袈裟なタイトルでブログを書いたが、今回は一気に実践編ということでフリーソフトウェア定番のデバッガ gdb の実践的使い方について記す。

プログラマの日々には、プログラムを書くためのエディタ、プログラムをコンパイル(あるいは実行)するためのコンパイラ(あるいはインタプリタ)、そしてプログラムを理解するためのデバッガという三種の神器が必須である。

この定番はわたしの場合xemacs/gcc/gdbである。前々職(DECという会社に務めていた)の場合、それぞれプロプライアトリな物を使っていたので微妙に異なるがやることは一緒である。

gdbは何のために利用するかというと、プログラムを理解するために利用する。デバッガなんだからデバッグのために利用するというのは、gdbの底力の半分も利用していないと言ってさしつかえない。

gdbはプログラムを動作させてその動的な振舞いを逐一追って理解するための道具なのである。

よくプログラムをデバッグするとき出力(C言語ならばprintf())を埋め込んでやる人がいるが、それはお勧めしない。お勧めしない理由は多分101以上あるが代表的なものを順不同で言えば、

  •   printf()の副作用で、printfを挿入した時と、挿入していない時で実行結果が異なる場合がある。
  •   printfを埋め込んだおかげでバイナリが異なってしまい、ダンプやスタックを追うのが困難になる。
  •   複数のバイナリを管理しなければいけないのでコストがかかる。間違ってprintfを埋め込んだ版を本番用にインストールしてしまうかもしれない。
  •   printf版は徹底的にテストされないので、バグが残っているかもしれない。セキュリティホールになる可能性がある。

printfデバッグは百害あって一利なし。

でもやるやつは後をたたない。

それはgdbの使い方を十分伝承していないからである。gdbを使いこなせればprintfデバッグの呪縛から(多分)のがれられる。例外はLinux Kernelのように定番のデバッガがない場合で、その場合は泣く泣くprintk()というのを埋め込んでデバッグする必要があるかもしれないが、今回はふれない。

トップダウンアプローチ(巨視的理解)

gdbの起動は簡単だ。

  gdb program

main()があるプログラムならとりあえづ、そこにブレークポイントを設定し実行する。

  (gdb) break main
  (gdb) run

そうするとmain()で一時停止する。ステップ実行をしたい場合はnext(n一文字だけでもOK)である。nは関数の中にもぐっていかないので、中身まで実行の様子をみたいのならstep(s一文字でもいい)する。

変数の値を見たい場合は print である。プログラムの理解のプロセスは、適当な位置にブレークポイント(b)を設定して、そこまで実行(r)し、変数の値を確認(p)する。これの繰り返しである。

xemacsのスクリーンショットを添付したので参考にしてほしい。デバッガの部分とソースコードの部分が表示されている。run の後にコマンドオプションをわたしている。
3
実行を再開するのは continue (c)である。そうすると次のブレークポイントまで全速力で実行する。ブレークポイントにたどりつく前に実行が終了(正常か異常かはとわず)する場合がある。

プログラムを理解するプロセスは、ブレークポイントで変数の確認をし、再実行をくりかえす、ということになる。ソースコードも同時に表示されるので、その前後のソースコードをじっくり読んで字面から理解を深めつつ、実際の変数の値を確認し、動的な側面からの理解をする。自分の予想と違う値であれば、それ以前にどこかでその変数の値を変更した場所(代入等)があるはづなので、そこまで遡って理解をする。ソースコードから追ってもいいし、ブレークポイントを実行順のより前に設定し、最初から再実行してもいい。

これを繰り返し理解を深めていく。

gdbを利用したソースコードの理解というのは必ずしもデバッグ(プログラムの不具合の修正)だけではなく、ソースコードを効率的に読む時にも利用できる。

gdbはソースコードの理解を助ける偉大なツールなのである。

日本語文字コードのお話

レガシーエンコーディングプロジェクトというのをやっていて昨日その検収があった。

開発そのものは一段落したのだが、まだ、事務処理が残っているので、全て完了というわけではない。

プロジェクトの背景として、Unicodeによるオープンソースソフトウェアの国際化が普及した結果として、日本語処理にいろいろな問題(文字化け)が発生したというのがある。奇妙に聞こえるかもしれない。Unicodeというのはソフトウェアの国際化のためにやっているのではないか?ソフトウェアが国際化すれば文字化けは解消するのではないか?話が逆じゃないのか?という疑問があるだろう。ところがだ、Unicodeによって解決した問題ももちろんあるがそれによって生じた問題もある。

例えば、日本語を表現する文字のエンコーディングとして、シフトJIS、日本語EUC、JISコードなど複数あるが、それぞれのコード変換で文字化けする場合がある。あるいは〜のような文字が文字コード変換で文字化けする。機種依存文字(まる一)が変換できない。

これらは、Unicodeを中心とした変換テーブルを使っているが故に発生する。例えばシフトJISから日本語EUCへの変換は、まづシフトJISのコードをUnicodeに変換し、その後、日本語EUCへ変換する。そうするとシフトJISで未定義の文字はUnicodeに変換できないし、日本語EUCで未定義な文字も変換できない。機種依存文字は日本語EUCで定義されていないので変換できないのである。

一方、シフトJISと日本語EUCのエンコーディング(ビットの組み合わせ)は機械的なアルゴリズムによって変換できるので、そのようなアルゴリズムを利用して変換している場合は情報の損失なく変換できる。

プロジェクトのWikiページに代表的なエンコーディングの対応関係を示すが、JIS X0208(漢字)の1区1点から94区94点の文字については各エンコーディング毎にマッピングは可能である。

JIS X0208の85区〜94区は、まるまる空領域(文字が定義されていない)のだが、マイクロソフトが定義したシフトJIS(CP932)では89区から92区にNEC選定IBM拡張文字というのが定義されている。

Unicodeを利用したマッピングだと、シフトJISからUnicodeへの変換はできるが、日本語EUC側に対応する文字がないので変換できない。これがアルゴリズムでシフトJISの85区1点を日本語EUCの85区1点に、85区2点を同様に85区2点へと変換していけば、コードの場所そのものは保存されるので、シフトJISから日本語EUCへ双方向で変換できる。従来の(太古の)ソフトウェアはそのようにして日本語のエンコーディングに対応していた。従ってある区点番号に文字が定義されていようがいまいが、その区点番号そのもので相互変換できたので、例え日本語EUCで文字が表示できなかったとしても再度シフトJISへ変換しなおせばデータは復活できたのである。ところが、Unicodeを利用したマッピングだと未定義な文字なので、どうころんでも一度変換に失敗すると復活させるすべがない。

この問題に対する解の一つは、日本語だけを特別あつかいをして、シフトJISと日本語EUCの変換アルゴリズムをソフトウェアに埋め込むというものがあるが、文字コードの種類(N)が増えてきたらN*(N-1)組の変換アルゴリズムを実装しなければならなくなって現実的とは言えない。(昔はごりごり、そーゆープログラムを書いていたのだけど)

もう一つの解は、シフトJISの文字種に対応した日本語EUCを定義してしまう事である。すなわち、機種依存文字とよばれるものNEC特殊文字(13区)、NEC選定IBM拡張文字を89区から92区に配置してしまうのである。これらの文字集合はeucJP-msとして知られていて、オープングループの日本ベンダ協議会が定義した。

今回のレガシーエンコーディングプロジェクトでは、eucJP-ms以外に、cp932、ISO-2022-JP-MSとCP51932を9つのOSS(libiconv/glibc/Perl/Ruby/Python/PHP/PostgreSQL/MySQL/nkf)について実装した。

文字化けのように昔から良く知られていて皆が解決が必要だと思っている問題でもよく見てみるとまだまだ整備されていないというものはOSSでも少なからづあるという事である。こーゆー問題を一歩一歩地味だけど着実に解決していくことがOSSの価値を高める事になるのである。

リンク:
Legacy Encoding Project Wiki
http://legacy-encoding.sourceforge.jp/wiki/
Sourceforege Project
http://sourceforge.jp/projects/legacy-encoding

日記など:
http://d.hatena.ne.jp/hyoshiok/20060316#p1

謝辞:
本プロジェクトはIPA (情報処理推進機構) の 2005年度下期 オープンソースソフトウェア活用基盤整備事業 で「オープンソースソフトウェアにおける統一したレガシーエンコーディングの変換機能の開発」として採択され支援を受けた。

大規模ソフトウェアの効率的な理解(その6)、リグレッションテスト

この「大規模ソフトウェアの効率的な理解(その4)」で巨視的理解、微視的理解という視点を紹介した。前者はソフトウェアをマクロから見ていわば俯瞰する。いわば鳥から見た図だ。後者は細部から全体像を把握する。いわば蟻の目である。地面にはいつくばっている。そのどちらの視点も忘れてはならない。Google Earthみたいに、自由に宇宙から眺めた視点からぐんぐんズームアップしていって、一つ一つのビルまではっきりくっきり見えるミクロの視点まで自在に動きまわらなければならない。

また、「大規模ソフトウェアの効率的な理解(その5)」で動的理解、静的理解という視点を紹介した。デバッガで1ステップ1ステップ実行するのは、微視的な動的理解であり、ソースコードを一行一行読むのは微視的な静的理解である。

リグレッションテストというのは、自動化テストの一種で、あらかじめ予想される出力結果を準備して、ソフトウェアを実行し、その実行結果と、予想した出力を比較し、予想どおりならOKそうでないならNGというように報告するものである。

最近ではテスト駆動型開発などのように最初にテストを準備して、その後に実装にはいるというベストプラクティスが広く実用化しているが、継続的な開発の場合、前バージョンで利用したテストがそのままリグレッションテストになる。

リグレッションテストは、巨視的な動的理解と言える。実装の詳細にたちいらないで(ブラックボックスとして)、入力と出力の組でソフトウェアの挙動を理解するという立場である。

大規模ソフトウェアの場合、ソフトウェアの隅々まで詳細に把握しているということは通常ない。大規模ソフトウェアのある機能を変更、追加する場合、自分の意図しない挙動を発生させることがある。いわばバグを作りこんでしまうことがある。リグレッションテストが整備されていれば、それを早期に自動的に発見できるので、大胆にソフトウェアを修正することが可能になる。リグレッションテストが整備されていないと、影響範囲を特定する事が困難なので変更量は可能な限り局所化最小化しなければならない。

リグレッションテストを整備しておけば、自分のソフトウェアの対する理解を仮想的に極大化できるのである。

OSSの実装も単にソースコードやドキュメントを整備するだけではなく、リグレッションテストをどれだけ充実するかという視点で議論、評価される時が来ているように感じる。よりOSSが大規模になり、修正が頻繁に求められるようになるとリグレッションテストが整備されているかいないかで、その変化に対する対応力が全然かわってくるのである。

Test Early Test Offten

なぜソースコードを読むのか?

遥か昔に下記のようなものを書いた。1999年当時私はオラクルの開発部隊に所属していた。1998年に米国ネットスケープがそのコードをオープンソース化し、世間ではいったいオープンソースとは何かということが良く知られていなかった頃の話だ。当時の様子がよくわかるので再録する。ちょっと長くなるが読んでほしい。

日経ソフトウエア1999年9月号、77ページ 掲載
よしおか ひろたか

Eric S. Raymondは、「The Cathedral and the Bazaar」という有名な論文で、フリー・ソフトウエア(後にオープン・ソース・ソフトウエアと呼ばれるようになる)がどのように開発されていくか、そして発展していくのか、一般の人々にもわかりやすい形で解説した。従来型の大規模ソフトウエアの開発を「Cathedral(大聖堂)」型開発、オープン・ソースの考え方に基づいた開発を「Bazaar(市場)」型開発と定義したのだ。

私は、あるデータベース・ベンダーに勤務している。Eric S. Raymondに言わせれば、Cathedralのプログラマであろう。信頼性の高いソフトウエアを開発するためには、ソフトウエア開発体制の「整備」とか「管理」とかが必要であるというパラダイムにいる。白状するとこれまで私は、明確なプロジェクト・リーダーもいなければ管理者もいない、技術的なロードマップも明らかでなければ、厳密な品質管理も定義されていない場当り的なプロジェクト(つまりフリー・ソフトウエアのことだ)によって、品質の高いソフトウエアが生まれるわけがない、と思ってきた。

例えば、私の日常生活はこんな感じだ。

朝、テスト担当者からメールが届いている。私が昨日、行ったプログラムの変更によって、リグレッション・テストにdiffが出たという。ついては、そのdiffが予期するものか予期しないものかを教えてほしい、という内容だ。多くの読者にとっては、チンプンカンプンなメールだろう。

一般に、データベース・エンジンのような大規模ソフトウエアは、プログラムの変更を毎日管理していて、担当者(例えば私)が変更したプログラムは、すべて構成管理データベースへ登録される(この登録をチェック・インと呼ぶ)。多くの担当者がそれぞれ変更を行っているから、時にはその変更が予期しない副作用を生じさせることもある。そこで、毎日その変更点を取り込んだソースコードからソフトウエアを構築し(これをデイリー・ビルドと呼ぶ)、テストにかける。これをリグレッション・テスト(回帰テスト)と呼ぶ。昨日まで正常に動作していたリグレッション・テストが今日の変更分から動作しなくなったとすると、昨日の変更が最もあやしいということになる。少しでも変更したら、すべてテストをやり直し、それを延々毎日繰り返す。まあ、きわめて単純な作業である。

メールに出てきたdiffというのは、そのリグレッション・テストで、昨日までの結果と今日の結果に「違い(UNIXのコマンドdiffからきている)」があった、という意味である。プログラムの機能を変更したのだから、その意図通りのdiffであればよいが、意図と違う副作用であれば問題だ。その判定は変更者にしかできない。したがって、私のところに問い合わせのメールが来たわけだ。

私はそのメールを読んで、「ああ、これはシンタックス・チェックを厳しくしたから、従来はノーチェックでうまくいっていた命令がエラーになったんだな。だからこのdiffは安全なやつだ、うんうん…」、とかいうことを考える。そして、実際にテストのログを見て、自分の仮説が正しいことを確認し、担当者に返事を書く。「このログは意図した変更だから問題ない。新しいテストのログをチェック・インしてくれ」と----Cathedral型開発には、そのような管理の仕組みがある。

一方オープン・ソース・ソフトウエアはどうだろう。プログラムの変更は、大多数の善意のプログラマたちがよってたかってソースを読み、レビュー(ピア・レビューと呼ぶ)することによって行われる。多くの目があればそれだけ早く問題は発見され解決する。それがBazaar型開発だ。ここにソースコードを公開する意味がある。

ソースコードを読むチカラ

私が驚いたのは、このピア・レビューの方法論が、Linuxのような大規模で複雑なソフトウエア開発でも機能する、ということだった。結局、私はこの素朴な、しかし協力な方法論の重要性を十分よく理解していなかった。それは、前述したようにCathedralのシステマチックな仕組みの中にいるためなのか、それとも単に私が愚か者だからなのか、あるいはその両方なのかはわからない。だが、ある時、ふと気がついたら世界観が変わっていた。そんな感じなのだ。

オープン・ソース流の開発では、コアのコードを最初に書く少数のプログラマと、そのコードをよってたかって改良、変更する大多数のプログラマがいる。そして大多数のプログラマにとって重要な技術は、プログラムをゼロから設計して実装する技量よりも、むしろ先人の書いた大量なコードをすばやく読んで理解するチカラだ。

今後、すべてのソフトウエアがオープン・ソース化されることはなくても、何らかの形で、オープン・ソースは一般化し普及していくことだろう。このとき、ソースコードが公開されていても、それを読みこなせなければ宝の持ちぐされである。

ソースコードを読む。その基礎的な技術がオープン・ソースの時代には最も必要とされているのである。
---
(引用終)

あれから7年たった。

オープンソースは一般化し、ソフトウエア業界にいるものは誰でも知っている存在になった。大聖堂(Cathedral)のプログラマであった私にとってはバザールモデルのソフトウエア開発は驚異的なソフトウエア開発方法論であった。7年間経験を積みその驚きは確信になった。

オープンソースの利用がより広範囲にそしてよりミッションクリティカルなシステムに広がっている状況を鑑みるとこのバザールモデルでのソフトウエア開発に対する深い理解が必須になってくる。

そして大規模ソフトウエアの効率的な理解という文脈でソースコードを読むチカラの重要性はますます高まっている。

大規模ソフトウェアの効率的な理解(その5)

動的理解、静的理解

ソフトウェアの理解のもう一つの視点は、ソフトウェアの動的な理解と静的な理解というのがある。

動的というのはソフトウェアを実行した時の挙動のことをさし、静的というのはソフトウェア(プログラム)の字面をさす。

静的な側面からの理解はソフトウェアのコードを読み、そこから何らかの形でプログラムの挙動を理解していくというアプローチになる。字面からの理解ということで、ディレクトリ構造やファイル名や変数の命名規則、コードリファレンスなどが静的な理解の対象になる。

動的な理解は、デバッガによる実行、プロファイラ、トレーサー、ベンチマーク、リグレッションテスト等々実行結果による理解となる。各種ツールが理解を支援してくれる。

ソフトウェアというものは、単純化すれば、ある入力に対して何らかの出力をする機械ととらえれば、ソフトウェアを理解するという事は、その入出力の組を知ることに他ならない。動的な理解というのはまさにそのソフトウェアを動作させ、その入力と出力の組を確認することになる。マクロでとらえればそのようになるが、実際は、その入力と出力の変換方式を詳細におっていくという作業になる。

動作をどんどん微分していけば最終的にはソースコードの一行になる。何百万行の大規模ソフトウェアも最終的には一つ一つの命令に帰着する。そうするとその動作はプログラムの静的な側面になる。机上デバッグというソースコードを机上で一行一行読み理解するプロセスというのはその一行一行の静的な意味を積み重ねて動的な意味に脳内で変換する作業といえる。

動的な理解と静的な理解をいったりきたりしながらソフトウェアの挙動を徐々にとらえていくというプロセスになる。

このソフトウェアを理解するプロセスというのは、あまり明文化されていないし、各人のスタイルに依存するが、あえてそのプロセスを明記する事を試みる。それが成功(?)すればデバッグやトラブルシューティング、性能チューニングの手法の一助になるかもしれない。(ならないかもしれないが、やってみない事にはわからない)

大規模ソフトウェアの効率的な理解(その4)

巨視的、微視的な理解

大規模ソフトウェアを理解する視点として、巨視的な理解、微視的な理解というのがある。巨視的な理解では、ソフトウェアをトップダウンに全体像から細部へと理解の道筋をたどる。一方、微視的な理解では、逆に細部から全体像へとボトムアップな理解の道筋をとおる。

規模の理解というのは、典型的な巨視的な理解の手法であり、ソースコードの解析は微視的な手法である。どちらも重要な視点で、それぞれの手法をバランスよく利用する必要がある。

大規模ソフトウェアの場合、微視的な視点からスタートすると、その規模のため、時間がおそろしくかかるという特徴があるので、最初は、巨視的な理解からはじめるのが王道である。その理解のプロセスの中で、興味のあるサブコンポーネント(論理的あるいは物理的な部分)へ到達したとして、そのサブコンポーネントの理解は徹底的に微視的な視点からはいるという方法もある。

例えば、あるソフトウェアのバグ修正などという作業の場合、ある程度の巨視的な理解の上、どの部分でバグが発生しているかを同定した後は、ソースコードレベル(微視的な)の理解をしつつデバッグをするというプロセスになる。

またコードリーディングは典型的な微視的な理解の方法論である。(ひらメソッドコードブログなども参考にされたい)

巨視的理解、微視的理解それぞれに必要なテクニックやツールというのがあるので、それについてもプロのプログラマとしては十分訓練しておく必要がある。

巨視的な理解    規模の把握(ファイル数、行数など)、ディレクトリ構造、ドキュメントの精査、プロジェクトのポータルサイトの確認(サイトマップ)、メーリングリスト、掲示板等コミュニティサイトの確認、名前付け規約の確認、ソースコード管理システム、バグ管理システム、

微視的な理解    ソースコード、ソースコードリファレンス、ChangeLog、バグデータベース、ソースコード管理システム(バージョン間の差分)、検索エンジン、メーリングリスト

トラブルシューティングの場合、前提条件としてあるソフトウェアについての巨視的理解については、ある程度おわっているとして、いきなり微視的な作業からはじまる。例えば、ある不具合についてバグデータベースを検索し、同様の不具合があるのかないのかの調査、エラーメッセージを検索エンジンで調査するなどのフェーズがある。問題を再現したら、デバッガを利用しつつソースコードの解析、分析などをしながら問題点の詳細な理解などをしていく。その時に必要な道具立てもいろいろかわってくる。

このようなツールと手法あるいはプロセスについては明文化した教科書がないので、各人がそれぞれのスタイルで長年の経験のなかで培っている。今回あえて自分のプロセスを公開するのは、このことによって、多くの人に参考にしてもらうとともにさらなる改良をほどこしたいと思っているからである。それがインターネット時代あるいはオープンソース(バザールモデル)の基本的なスタイルであるからだ。

公開することによって進化する方法論といっても差し支えない。
読者諸氏のコメント、トラックバックなどを強く期待するところである。

それぞれのツールと手法についてはまた別途記す。

大規模ソフトウェアの効率的な理解(その3)

規模の把握

大規模ソフトウェアの理解はいろいろな観点からのアプローチがある。ソースコード一式(通常tarballと呼ばれている)を入手し、適当なディレクトリに展開する事からはじまる。tarballではなく、CVSのようなソース管理システムから直接入手する場合もある。

tar.gzというような形式の場合、$ tar xvzf XXXX.tar.gz というようなコマンドで展開する。$ cd XXXX してざっとディレクトリをながめる。通常、READMEないしINSTALLなどのファイルがあるので最初にそれを良く読む。またDocsなどというドキュメントを置いておく場所があれば、その中になにがあるかをざっと見る。

いきなりソースコードを変更するのではなく、このようにディレクトリ構造を調べたり、規模の把握をしたり、おおまかな骨格を理解するようにする。ディレクトリ構造は当該ソフトウェアの物理的構造をあらわしている。ソースコードのディレクトリ、テスト、ドキュメント、各種ツールなどなどからなる木構造になっている。

大規模ソフトウェアの森に地図もなしにいきなり飛び込むと迷子になってしまうので、ソフトウェア構造の下調べとして、規模の把握やディレクトリ構造の調査、そしてドキュメント類から名前付け規約などを調査しよう。

ソースコードの分量を知るには
$ find -type f |egrep '\.([chp](xx|pp)*|cc|hh)$'|wc -l
でファイル数が表示できる。ソースコードの行数は
$ find -type f |egrep '\.([chp](xx|pp)*|cc|hh)$'|xargs wc -l
ファイル数が多いと最後のwcのあとに、さらに
$ find -type f |egrep '\.([chp](xx|pp)*|cc|hh)$'|xargs wc -l|grep total
とする。

自分がこれから格闘しようとしているソフトウェアの正確な規模もしらないで、どのようにしてそれに取り組むのか。tarballを展開して最初にやる作業はソフトウェアの規模の確認というのは王道だと思う。小規模なソフトウェアであればたいした準備もなく格闘できるかもしれないが大規模ソフトウェアであればやはりそれなりの心構えと準備が必要である。どのくらいの装備が必要かは自らの経験とソフトウェアの規模と複雑さによる。

プログラマが感じるソフトウェアの規模と複雑さは、その人の経験とスキルにかなり依存する。新人にとっては、1万行のソフトウェアでも十分大規模に感じるだろうが、ベテランプログラマであれば小規模に感じるだろう。いずれにせよ、規模を把握して心の準備をしよう。

大規模ソフトウェア探索の旅はそれから始まる。

大規模ソフトウェアの効率的な理解(その2)

ソフトウェアの規模を大体下記のような感じでわたしはとらえている。

規模         行数
小規模       10万行以内
中規模       10万〜100万行程度
大規模       100万行以上

ソフトウェアを構成する行数でおおざっぱにくくっている。あるいは開発に関与する人数によっても同様にくくれる。

規模         人数
小規模       10人以内
中規模       10人〜100人程度
大規模       100人以上

ここで見ているのはあくまでも量での視点で,質的な複雑さとか難しさは一切見ていない。いずれにせよ規模の観点からいうとLinuxカーネル(あるいは定番のOSS)というソフトウェアは大規模なソフトウェアである。そして大規模ソフトウェアを開発するのにはそれなりの難しさというか小規模なソフトウェアを開発するのとちょっと違ったテクニックを必要とする。そのようなテクニックとか開発のプロセスとかは現場で経験して徐々に身につけていく種類のものでソフトウェア工学の教科書にもあんまり載っていなかったりする。ある意味でこれは各社のソフトウェア開発の現場が持っているノウハウなわけだけれどそれ自体はシリコンバレーあたりでは明文化されてはいないがある種の共通の認識みたいなものがあったりする。その明文化されていない開発プロセスをOSSという題材を利用して明らかにしたいなあと思っているのである。

かつて、わたしはモジラの解剖というウェブのページを持っていたのだが(今は残念ながらないが、ウェブのアーカイブに残骸が残っている。文字化けするときは、Microsoft Internet Exploreの場合:表示>エンコード>日本語(シフトJIS)Mozilla Firefoxの場合:表示>文字エンコーディング>日本語(Shift_JIS))、モジラを題材に大規模ソフトウェアの理解のプロセスを記そうとした。大規模ソフトウェアの開発にはある種の定番があるのでそれを記してみたい。

注:ひらさんとの議論はどちらかというとコードリーディングという大規模ソフトウェアの理解の一部分としてわたしはとらえている。

大規模ソフトウェアの効率的な理解

大規模ソフトウェアの開発が大企業によって行なわれていた太古の時代、新人はそのプロジェクトに配属されるや膨大なドキュメントを渡され、とにもかくにもそれを読むことを要求された。わからないことは隣の先輩に聞いて覚えた。失敗はどやされるが、それがいい経験になって少しずつ大規模ソフトウェアの全貌を理解していった。すぐそばにその大規模ソフトウェアを作った人がいるから細かいところも突っ込んでわかるまで聞くと言うことができた。大規模ではあるが秩序だった管理システムがあり見通しは悪くなかった。ある意味牧歌的な時代であった。変化もそれほど激しくなかった。

一方OSSの場合、一人のコア開発者がこつこつ自分の興味の赴くままその核となる部分を開発する。ある程度、機能もそろったところで、アルファ版みたいなものを公開する。サイズもそれほど大きくない。ソースコードもまだごちゃごちゃしていないので、構造を理解することはそれほど難しくない。

しかし、定番のOSSであるLinuxカーネルやMySQL/PHP/PostgreSQL/Samba/Perl等々は十分でかくて、ソースコードのサイズも100万行を超えるものが珍しくない。なんの準備もなくそのソースコードの森に飛び込めば確実に迷子になる。初期のころから関わっている開発者ならまだしもぽっとでの新人がすぐに全体像を理解できるほど単純でも小規模でもない。

OSSの時代こそ大規模ソフトウェアの実装の効率的な理解の方法論が求められている。企業が自分が作ったソフトウェアを自社のエンジニアに教育(OJT)するのと違って、OSSはそのような内部構造の教育コースがない。自分のすぐそばにコア開発者がいないので簡単に聞くことが難しい。

頼りはソースコードとメーリングリストとポータルサイトだ。Googleも助けてくれるが隣に聞く人はいない。ソースコードを効率的に理解する方法論がいまこそ求められているのである。

その実践的な方法論についていろいろ議論していきたいと思う。

頭に豆電球がともる瞬間

よく、アイデアが閃いた時、頭に豆電球がともる絵を書くが、デバッグをしていて延々試行錯誤をしているのだけど全然解決の糸口すらつかめないとき、ひょんなところからぱっと解決策を思いつくことがある。

そのぱっと閃くまでの手順というのは通常再現することは難しい。思いついっちゃったんだからしょうがない。なんかいろいろ試行錯誤していたうちにたどり着いたというのが正直なところである。

その豆電球がともるまでの道のりは闇の中を彷徨しているようなものでストレスがたまるがぱっと閃いた瞬間の快感は経験したものでないと分からない。言語化するのが難しい。しかし、そのような経験をぜひ若手のエンジニアにも味わって欲しいと思う。そのぱっと閃く経験を積み重ねれば積み重ねるほどエンジニアとしての経験値、力量は上がっていくわけで、引出しの多いエンジニアになる。

コアテクの路地からのトラックバックを貰ってそんなことを考えた。

日常的な仕事の中では毎日毎日そんなに豆電球はともらないかもしれないが難しい問題でうんうんと唸っていた後に到達した場合は問題の難しさに比例する快感がある。山登りみたいなものかもしれない。

実はわたしは昔からカーネル開発者にあこがれていて、いつかはカーネルコミュニティにデビューしたいと思っていた。できることならばLinuxカーネルの性能向上に微力ながらでも貢献したいと漠然と思っていた。正真正銘のカーネルハッカーならば、鼻歌交じりに性能上の問題を発見しそれを修正するだろうがわたしのような素人は手も足もでなかった。

そこで、性能上のボトルネックを発見するにはカーネルプロファイリングツールが必要だということでhardmeterというツールを3年ほど前に開発した。そのアイデアは幸運にも未踏ソフトウェア創造事業に採択された。パフォーマンスチューニングをするときにプロファイリングをとってそのデータをもとに分析するというのはチューニングの王道中に王道である。しかし、hardmeterの開発では精密なカーネルプロファイリングが取得できるようになったが、それを利用して実際カーネルをチューニングするまでにはいたらなかった。(残念)

後に日本OSS推進フォーラム開発基盤WGのプロジェクトでカーネルの性能評価をしたときにhardmeter開発の経験が役に立ったことは言うまでもない。oprofileという2.6に採用されたカーネルプロファイリングツールを利用してデータを収集した。当初は全く問題点が見えていなかったが約一月ほどプロファイリングデータを分析したところある日突然頭に豆電球が閃いた。その結果はCache Pollution Aware Patchという形になったのだが、後にhardmeterで採取したデータを見ていたら、oprofileで発見した問題の兆候がくっきりとあった。2003年では発見できなかったものを2005年には発見できるようになったのである。

歳をとっても人間は意外と進歩しているのである。脳みそをフル回転してときには頭に豆電球をともさないとと思った瞬間であった。

デバッグの話(昔の日記から)

わたしは、90年代にシリコンバレーにいたとき、シリコンバレー日記と言うものを書いていてWebで公開していた。今そのサイトはないのであるが、インターネットのWebアーカイブにその内容が残っている。先日「プロセスプログラミングの実践方法」というエントリでデバッグの話を書いたので、それつながりということで、当時、記した日記を全文転載し、ちょっと長くなるが後書き的な解説を加えたい。文体が微妙に違うがご愛嬌と言うことでご勘弁願いたい。

転載始まり

デバッグ

誰もが使っている言葉なんだけど,実のところよく分からない言葉というのがある.少なくとも,なんとなくの定義はあるのだけど厳密な全員が納得できるような定義があるようでない言葉というのがある.

デバッグというのも実はわかったようでいてよく分からない.とりあえづ,デバッグというのはプログラムのバグを直す作業だとしよう.そうするとプログラムのバグとは何か?という当然すぎる疑問が湧く.バグというのを,仕様書と実際の動作との差という風にも定義できそうである.これはプログラムの予期せぬ動作を,「いや,それは仕様です」といういいわけに使えるので,プログラマには好まれる定義かもしれない.しかしもう少し広範囲にとらえれば,やはり,利用者の期待する動作と実際の動作の差をバグという風に言えなくもない.期待する動作より,いいほうに実際の動作があればだれも文句を言わないだろうから,不都合側の動作ということにしてみよう.

というわけで,とりあえづの定義として,デバッグという作業はそのプログラムのバグを直すことだとしよう.

さて,そのデバッグをあなたはどのようにしているのだろうか?ワークステーションの前に座って,コーヒーをがぶがぶ飲みながら時にはハンバーグをほお張りつつ何時間か格闘するといつのまにかにバグが直っている.そーゆーなぞのプロセスなのだろうか?

そのプロセスをわれわれは記述できないだろうか?どーゆーステップをもってわれわれはデバッグをしているのか?

それを記述する事にどのような意味があるのか?一つはそのようなプロセスが記述できれば,無駄や,無理や重複作業などを発見する手がかりになるのではないか?つまり理解していない事は決して改善できないのだという大前提の元,プロセスを理解すればそれを改善するきっかけをつかめるのではないかという立場である.

あるいは新人エンジニア(彼らは往々にしてデバッグ作業の効率が悪い)に対してのお手本になるのではないだろうか?

わたしは大胆にも自分のデバッグのプロセスをここで記す事を試みてみたいと思う.皆様の忌憚なきコメント,サジェスチョンを頂ければ幸いである.

バグの発見:なんらかの方法でバグが発見される.われわれはバグが誰によってどのように発見されるか実はそれほど深く理解していない事実にも驚かされる.

実のところ,その前にバグの作成というプロセスがあるのだが,ここの部分もまったくと言っていいほど解明されていない.一つだけ確かな事があるとしたら,バグが誰によって作られるかという事実である.もちろんプログラマによって作られる.すなわち,わたしや,プログラマであるあなたによって,作られるのである.作られるという受け身な態度は潔くない.バグはわたしやあなたが作るのである.バグが自然発生することは決してない.しかしながらどのようにバグを作るか,なぜ作るかという点に関してはわれわれは十分理解はしていない.

ここでは,バグがなぜ発生するかという問題にはとりあえづ触れない事にする.ともかく,誰かが作ったバグを誰かが発見する.そして誰かが直す.すなわちわたしやあなただ.

バグの再現:誰かが発見したバグの現象を再現する.ある操作をすると,システムがクラッシュすると報告されたのならその操作を繰り返してみる.それで再現できればいいのだが,タイミングや作動環境の違いで再現できない場合が多々ある.その場合は,作動環境,例えば,OSの種類や,各種ハードウェアなどをできるだけ同一の条件にする必要がある.それでも再現できなければ,バグを発見した実機の環境で同様な作業を繰り返し,バグを発生する条件を確認する.場合によってはここで座礁する事もある.試行錯誤の繰り返しでもある.

バグを再現する事に成功したとしよう.条件がよければ,エラーメッセージや,コアダンプなどの資料が入手できるかもしれない.

どこでメッセージを出しているかを見つける:どのルーチンがどのエラーメッセージを出しているか?通常はスタックフレームを見れば,どのルーチンで異常終了しているかがわかる.当面はそのルーチンの界隈から,狭義のデバッグ作業が始まる.

当該ファイルをデバッグオプションでコンパイルする:OS付属のデバッガーを利用して,デバッグオプション付きで再コンパイルしたプログラムを実行する.異常終了するルーチンにブレークポイントを設定して,異常終了する直前の各種の変数の値などを調べる.

それからのプロセスは,ちょうどプログラムの実行を逆順に戻っていく作業になる.例えば,ある変数がXなので異常終了したとしたら,なぜその変数がYでなくXになったのか?それを探っていく.変数の場合は代入されない限り,値は変更されないので,代入されている場所を特定する事がポイントになる.

情報をいかに検索するかがデバッグの効率を左右する.全体像を理解するためにソースコードの理解がかかせない.どのルーチンがどのルーチンから呼ばれているか,呼んでいるか,というコールグラフ.どの変数がどこで定義され,どこで代入され,どこで利用されているか.そのような理解をする.

原因の特定:プログラムの挙動を詳細に理解すれば,自ずとバグの原因は発見できるであろう.わたしには原因の特定の瞬間のプロセスを記述する事はできない.手に余る.ともかくわかるときにはわかるのである.

修正案の検討:バグの原因は特定できたとしよう.特定できれば,それをどのように修正すればいいかのいくつかの案を検討する.実装上のコスト,修正の容易さ,その他の要因を勘案の上,修正案を比較検討する.修正が現実的なコストでできない場合もありうる.そのコストとバグの影響と比較検討して,バグを修正しないというオプションもありうるという事に注意する.

修正:上記の修正を実施する.

テスト:修正の結果,確かにバグが直っていることを確認する.テストは原則として日々のリグレッションテストに組み入れる.

リグレッションテスト:修正が従来の機能に影響(リグレッション)を与えていない事を確認するために,リグレッションテストを流す.

ソースコードレビュー:変更したソースコードを担当のプログラマとレビューする.変更が軽微なものなら,変更分をメールで何人かのプログラマに送ってコメントをもらう.

チェックイン:修正をソースコード管理システムに登録する.

それ以降:これでバグを一つ修正した.それ以上なにが必要なのだろうか?デバッグのプロセスを通じてわたしはなにを学んだろうか?もっとうまい方法はないだろうか?この修正はベストだったのだろうか?それともデバッグというのは黒魔術と一緒で,学習可能なものではないし習得可能なものではないのだろうか?

わたしはデバッグというもっともプログラミング上で神秘的なこのプロセスをもっと深く理解したい.そしてもっと熟達したい.エキスパートになりたい.そのために,自分の作ったバグを記録し,デバッグの記録を取っている.そして記述を通して,自分の稚拙なプログラミングテクニックを再確認しいかにしてそれを向上させるかを学んでいきたい.できれば,あなたのデバッグプロセスからも学びたい.われわれがプログラミングについて理解するために,そしてそれによって少しでも賢くなるため,このような微視的な記述やデータが必要だと思うのである.

はげましのお便りは よしおかひろたか
までどーぞ.
日記のページへもどる.
一覧へもどる.

シリコンバレー日記/未来のいつか
http://web.archive.org/web/20000928213350/www.best.com/~yoshioka/d/98/i980301.html
文字化けするときは、
Microsoft Internet Explore 表示>エンコード>日本語(シフトJIS)
Mozilla Firefox  表示>文字エンコーディング>日本語(Shift_JIS)

転載終わり

1998年3月1日に書いた日記である。デバッグのプロセスというのはほとんど変わっていないように思う。技術の進歩と言うのは速いのだろうか?遅いのだろうか?ソフトウェア開発に対する理解というのがこの10年どのくらい進歩したのだろうか進歩していないのだろうか?

マクロでみるとソフトウェアのテスト&デバッグのプロセスはかなり定式化できることがわかる。またある程度自動化することもできる。そしてそれがデイリービルド&リグレッションテストとしてよく知られているベストプラクティスである。

ソフトウェア開発の非常に人間的な部分であるデバッグのプロセスをもっともっと深く理解したい。その思いは10年位前と変わらない。しかしながらこの10年で自分がどれほど進歩したかと言うと正直言って忸怩たるものがある。商用ソフトウェアを作っていた当時と比べて自分の専門性がどれだけ研ぎ澄まされたかと言うとほとんど進歩していないのではないだろうか。そう考えると道はとてつもなく長く険しい。

しかし10年前と現在で大きく変わったことがある。OSSとインターネットである。

10年前わたしが記述したバグ情報はすべてプロプライエタリな情報として企業の壁の中にあり同僚以外と共有することができなかった。わたしの書いたコードは門外不出だし、変更記録も、バグデータベースの記述ももちろん知的所有権の名の元に幽閉されている。

10年前はわたしとあなたは微視的なデバッグの記述を共有できなかった。

ところが10年たってわれわれはオープンソースと出会い、わたしはわたしのコードだけではなく、わたしのつたないデバッグのプロセスをあなたや世界中の誰かと自由に分かち合うことができるようになった。

なんていうことだ。

この情報をインターネットに公開しておけば、未来のいつか、世界の誰かがこの情報を発見してくれるかもしれない。ひょっとしたらデバッグのプロセスをチューニングしてくれるかもしれない。それはあたかもソースコードを公開すれば、そのコードが利用するに値するだけの価値があり、利用者の注目を浴びて、多くの人に利用されるのならば、世界の誰かがコードを改良するという、ソフトウェア開発におけるバザールモデルのように、このデバッグというプロセスをより高度にチューニングしてくれるかもしれない、などと夢想するのである。

8年前に書いたわたしの日記を8年後に自分自身が再発見し、それをきっかけに一つのブログを書き、それを読んだあなたがひょっとしたらいつの日かソフトウェアプロセスのチューニングに参加してくれるかもしれないと考えると、インターネットというのはすごいメディアだとつくづく思うのである。世の中まだまだ捨てたものではないなあなどと妄想するのである。

デバッグのプロセスを詳細に記述する。そこからデバッグに対する深い理解が生じるようになる。
そしてその記述はインターネットによって時間と空間を越えて共有できる。それはデバッグに対する深い理解として人類共有の財産になりうる。

OSSとインターネットというのはすごい環境である。

プロセスプログラミングの実践方法

学ぶ方法を学ぶことは重要だ。知識は陳腐化する。しかし、学ぶ方法というのは、道具立てが変わってもかなり安定的で変化は少ない。

インターネットのおかげで確かに知識の取得方法は劇的に変化した。量的な変化が質的な変化に転換した。なんでもかんでもインターネットで検索してからことをはじめるという感じになってしまった。あんまりじっくり考える機会がなくなったような気がしないでもない。

かつてプロセスプログラミングと言う概念が流行った。最近ではあんまり言わないがソフトウェア開発の究極の姿だと言われた。ソフトウェアは人が作るのだが(当たり前だけど)、そのプロセスを厳密に記述していければ、つまりコンピュータが理解可能なくらい精密に記述できれば、ソフトウェア作製も自動化できるのではないかというアイデアである。随分荒唐無稽なことを言うとあなたは思うかもしれないがあながち夢物語ではない。

例えば、ソフトウェア開発では誰でも利用している make ファイルと言うのがある。これは実行可能なソフトウェアを作成するプロセスを厳密に記述したものといえる。コード自体はもちろん人間が書くのであるが、それを環境に合わせて設定をして、コンパイルしてリンクして様々なディレクトリに配置するという細々とした作業は make システムが Makefile に記述したとおり自動的に行なう。ソフトウェアを作成するというプロセスを自動化したため、些細なタイプミスとかがなくなり生産性は劇的に向上する。

プログラミングの一部分の自動化からもう少し広い範囲でソフトウェアの設計、製造、テスト、デバッグを自動化してやろうというのがプロセスプログラミングのアイデアである。ソフトウェア開発を自動化するためにはどのようなプロセスでわれわれがソフトウェアを作っているかわれわれ自身が知らなければならないのだが、それを記述するのがプロセスプログラミング言語ということになる。機械が実行可能というということで言えばある種のスクリプト言語であるわけだが、人間とのインタラクションがどうしてもはいるので、掲示板とか、コード管理システムとか、バグデータベースとか、カレンダー等々の機能が必要になってくる。あれ、これって、ソフトウェア開発用のグループウェアか?ということである。

オープンソースソフトウェアプロジェクトを立ち上げると取りあえず、sourceforgeあたりにプロジェクト用のサイトを立ち上げる。厳密なスケジュール管理をするわけではないが、大まかなプロセスとして、プロジェクトマネージャのわたしの頭の中にあるものを書き物にして(通常それをロードマップとか言うのだけど)、プロジェクトのポータルサイトに貼り付けたりする。メーリングリスト、Wikiのような双方向の掲示板、バグデータベース、コード管理システム、カレンダーなどなど標準的なツールを利用してプロジェクトを発足させる。

ロードマップを実装するのは人間で機械ではない。コードを書き、テストをし、デバッグをするのも人間で機械ではない。しかし、バグデータベースにバグを登録すると誰かにそれが通知され、誰かがそれを修正し、コード管理システムにその修正を登録する。その流れは、コードを直すという行為など人間が関与する部分とコードを管理するなど機械が関与する部分とに記述可能である。

テストなどもデイリービルドとリグレッションテストという黄金のパターン、王道中の王道があるわけだが、それは自動化でき、ベストプラクティスとして広く利用されている。

コードを書く部分など人間の創造的な部分はもちろんある程度は残るが部品と部品を組み合わせて高い生産性でソフトウェアを作ると言う流れはある。最近フレームワークが流行っている。

デバッグのところはどうだろうか?

問題解析というもっとも人間的な部分はそもそも記述可能なのだろうか?記述可能であればなんらかの方法で機械化、自動化できるかもしれないけど。

デバッグは一つ一つが特殊でそれを記述することは不可能であると多くの人が言う。本当にそうなのであろうか?

デバッガを利用して、デバッグすることを考えよう。わたしは定番の gdb というデバッガを利用して日々デバッグしているのだが、そのプロセスは下記のとおりだ。

  1. gdb を起動する
  2. 適当な位置にブレークポイントを設定する
  3. 実行開始する
  4. ブレークポイントで停止する
  5. 問題となっている変数の値を確認する
  6. 値が期待する値なら、2に戻る
  7. 値が期待する値でないならば、実行開始してから停止した間のどこかにバグの原因があるはづなので、それ発見するために当初設定したブレークポイントより実行位置が早い部署にブレークポイントを設定し、1から実行する。
  8. 正常に実行終了したら終わり

ほら記述できるではないか。

記述できると何がうれしいか?上記のプロセスを誰かに伝えることができる。「ソフトウェアのデバッグと言うのは試行錯誤でやるんだよ」、「気合だよ気合」、「まあ経験と勘だな」という先輩の言葉よりはるかに具体的でかつ再現可能である。「ブレークポイントをどうやって見つけるんですか?」という本質的な質問を後輩がしてきても心配いらない。力ずくの方法であれば実行位置の真ん中あたりに適当にブレークポイントを設定して何度か試行錯誤をすればいい。もう少し気の利いた方法であれば、ソースコードをよく読んであたりをつけるのであるが、こっちは経験と勘の感じがするのでちょっと説明が難しい。しかし前者の力ずくの方法は必ずしも悪くない。2分検索で効率的に問題領域を絞り込むことができる。(2分検索の具体的なイメージはみたのブログBisection searches あたりを参考にしてほしい)

デバッグの方法は記述可能だし、gdbのコマンドとして実行可能ですらある。

xemacsとgdbという黄金のツールを日々わたしは利用しているのであるが、コマンド履歴はxemacsのバッファに残るので、それをファイルに保存しておけば、自分がどのように問題を解決しているかコマンドレベルで記録できる。それを見れば自分の試行錯誤の足跡がはっきりと見て取れる。それを見ながら時々 hisotory コマンドを利用してトラブルシューティングを繰り返すのである。

コマンドのオプションを忘れたら man を見ればいい。ソースコードをまとめて tarball にするという作業の度に man するというのもいいがかつてどうやったかを hisotry で確認してそれをカット&ペーストすれば間違いが少ない。

昨日までのデバッグの足跡もgdbのバッファに残っているので、デバッグのプロセスを再開してもすぐにフルスピードでデバッグに復帰できる。makeしてテストしてデバッグしての履歴もすべてxemacsのバッファに残っている。ファイルの落としておけば数ヵ月後にバグが見つかってすぐにトラブルシューティングしなければいけないとき、そのファイルを見ながら、~という設定をしてXXということをやってmakeしてテストしてデバッグして…というプロセスにすぐに復帰できる。人間の記憶は当てにならないがコマンドの履歴は厳密である。

プロセスプログラミングの第一歩はシェルの履歴を保存することにある。

そして、それはプログラマとしての自分自身の生産性を劇的に向上させる。一度お試しあれ。

500万倍のスケーラビリティ

カーネル読書会で、mixiのバタラさんにmixiのシステムをどのようにスケールアップしたかの話を聞く。開催以来最多の90名の登録(会場の都合で90名で登録を終了した)で、会場は立ち見が出るほどの盛況であった。宴会も50数名の参加をえてこれも大盛況であった。(大よっぱらいの人もいたけど(笑))

内容はYAPCでの発表をアレンジしたものである。ようさんの日記に詳しい報告がある。

システムを1ユーザから500万ユーザまで約2年半でスケールアップしたというお話で、苦労話満載の非常に興味深いものであった。様様な試行錯誤をへて現在のシステムにいたっているが、1ユーザから500万ものユーザをサポートするなどというスケーラビリティはあらかじめ設計されていたものではない。問題にぶつかるたびに一つ一つ問題を解決していって今に至るということである。この500万倍のスケールアップと言うのは本当にとてつもないことである。そのとてつもないことを飄々とこなしているバタラさんのお話が興味深かった。

これがシリコンバレーなら、次のようなシナリオになるだろう。

3年ほど前に誰かがSNS(Social Networking Services)的なものを考え付いたとして、仮に500万ユーザを集めるとしよう。そのビジネスプランが実行可能で期待する収益がそこそこあるのなら、それに対しVC(Venture Capital)がどんと掛け金を張る。

通常、ユーザを獲得するところが最もコストがかかるわけだが、昔のネットベンチャーはそこに莫大なコストをかけユーザを獲得していた【例えば一人当たり100ドルとか(mixiはある意味ユーザ獲得に全くコストをかけていない。口コミで友達の輪を広げていく。)】。3年前に500万ユーザを獲得するというビジネスプランを書いたとしてもたぶん誰も相手にしなかっただろう。

まあ、そんなこんなをすべて取っ払って、仮にVCがどんとお金を提供したとしよう。

ネットバブルのころだと、VCからどんと資金を調達したら、Sunのサーバ(最近はもちろんLinuxだ)をいっぱいたててDBは当然OracleRACだ。掛け金が高いので定番の部品でSIをやる。時間をお金で買う。

最初から500万人分のシステムを構築するのは非常に高価なのであるが、あらかじめ500万人分の負荷に耐えられるような設計にはしておく。1人のユーザにはもちろんオーバースペックでコスト高である。

シリコンバレー的なアプローチはトップダウンでキャパシティプランニングをしてそれに必要な人モノ金を調達する。人は人材の流動性が高いのでその道のエキスパートを適切なコストで調達可能である。お金が集まらなくて十分な収益が上げられなかったら、お金が尽きたところで、終わりである。The End。お金が尽きる前に収益をあげられれば生き残ることになる。

一方mixiはそのようなシリコンバレー的な発展の仕方をしたわけではない。バタラさんが一人で始める。ユーザも一人。まさかそれが2年半後に500万ユーザになるなんて自分自身も思っていなかった。だけど、ちょっと面白そうだからやってみた。そんな感じである。

だから今からみると、その時その時の場当たり的な対処方法に見えなくもないが、その時その時のベストエフォート、最善策を適用していくことによってシステムを育てていった。いかにして限られた資源の中で低コストでシステムをスケールアップしていくか。そしてそのアプローチは、お金も、人も、様々な資源も乏しいネットベンチャーならではの知恵とちょっとした工夫でしのいでいくのである。リスクを最小限にしながらのスケールアップというのはGoogleやYahoo!のような巨艦企業とは違ったベンチャーが取るべき賢いアプローチなのではないかとお話を聞いていて思った。

東京はシリコンバレーではない。シリコンバレーをコピーするのではなく東京ならではのユニークな方法で問題を解決していく。そのようなヒントに満ちたお話であった。

そしてカーネル読書会である。東京にはmixiやらGreeやらはてながある。

カーネル読書会とよしおかの野望
http://blog.miraclelinux.com/yume/2006/07/post_69b1.html

OSSの技術カンファレンス、縦串横串
http://blog.miraclelinux.com/yume/2006/07/oss_f5f1.html

カーネル読書会をきっかけにいろいろなコラボレーションが有機的に発生し様々な専門性をもった人たちとの核融合がおこれば面白いと思う。臨界点には達しているような気がする。

OSSの技術カンファレンス、縦串横串

カーネル読書会とよしおかの野望に平さんからトラックバックをいただいた。ありがとうございます。

弊社の場合、Linux OSのベンダーなのでLinuxの専門家がいるわけだが、同時にOracleとかRDBMSの専門家もいて、それを一つのウリにしている(わたしも元はと言えばRDBMSの開発者だったので、データベースには土地勘がある)。

SIをしていると当然ながら様々なコンポーネントの組み合わせ問題が発生し、その時々にノウハウTipsを組み合わせて対処するわけだが、それぞれの部品がブラックボックスだと、正直言って問題が発生しないようなバッドノウハウを組み合わせることがSIになってしまい、全体最適を目指すと言うことはなかなかできない。

トラブルが起こったときブラックボックスだと対処のしようがないので、結果として定番の部品の組み合わせでなるべく冒険をしないようにする。万が一ドラブったとしてもワークアラウンドに終始して抜本的な対策が取られることは少ない。定番の部品はそのようなバッドノウハウが積み重なっているのである意味安心して使われてさらにバッドノウハウが積み重なるというフィードバックがかかる。

そこでOSSだ。OSSはホワイトボックスなので業者に技術力さえあればとことん原因を追究できる。性能上の問題だろうが機能上の問題だろうが時間とコストの制約の元最適化ができる。OS層、RDBMS層、Web層、アプリケーション層、そして運用それぞれの層で「すり合わせ」が可能である。ある場合はRDBMS側で対処するのが最適だとか、OS側で対処するのが正しいとかそのような判断がホワイトボックスがゆえにできる。

オープンシステムというのが既存のプロプライエタリな定番製品の「部品の組み合わせ」であったのが、OSSで構築したシステムの場合は「部品のすり合わせ」である。従ってシステムとしてより最適なものを構築できる可能性がある。

徐々にOSSの開発者コミュニティも量的にも質的にも増えてきたので日本で一つ集まっちゃおうということである。それぞれの層で困っている問題を公開して共有してみんなでわいわい考えようということである。プラットフォームから見ると下から上まで縦串を通している感じだし、それぞれの層で見るとPostgreSQLだMySQLだ、あるいはJBOSSだTomcatだ、さらにはPerlだRubyだPHPだというような横串でもある。そのメッシュの中で共通の問題、例えばスケーラビリティをどう確保するかとか、運用コストをどう下げるかとか、あるいは楽しいハックの方法とか、さらにはプログラマとして幸せな社会とはとか、まあなんでもいいのだけどごった煮風にいろいろ議論できたら楽しいのではないかなあなどと思った次第である。

僕はカーネル専門だが、カーネルを読んでいると特定アプリ(DBMSとか)のパフォーマンス
を上げるための工夫を見つける。
そういったものを見ていると、どうしてもカーネル単体として説明するのではなく、ア
プリを含めた全体として説明したくなる。そうなるとすごく面白いんじゃないかと。

中略

つまり、上から下まで、特定アプリからCPUレイヤまで通して説明したい。縦串である。
でも実際問題、こういうのは難しいと思ってた・・・。
ところが7月のLMSに、難しいと思ってたコラボが実現できた。kosakiさんが、遠方はる
ばる参加してくれることによりアプリ→glibc→カーネル→CPUのストーリーを作ること
ができる。縦に上から下まで説明できる。これは本当にすごいことだ。
ひら/縦串 http://d.hatena.ne.jp/hira_sosuke/20060702/1151836228

弊社の武田のブログも微妙にからんできて、

今回は、mixiのシステムの成長に関するお話ということで、ちょっと興味があります。ここ数年カーネルのお仕事中心でやってきましたが、この知識をもっと上のレイヤに生かせないかと思っていた丁度このごろでした。ぜひ、現実のシステムでの課題を聞いてみたいと思います。最近mixiを使い始めたこともあって、私の琴線にものすごくヒットしています。
カーネルとアプリケーションの関係 http://blog.miraclelinux.com/uraura/2006/07/post_98f8.html

いい感じである。

日本にはGoogleはないけど、OSの専門家やRDBMSの専門家やWebアプリケーションの専門家がバーチャルにコラボレートして世界にないものを創造していく、そーゆー緩い場ができると面白いなあなどど最近思っているのだ。それを東京と言う地域でやれないかなあと。

会社情報 採用情報 個人情報保護方針 商標等取り扱い事項 English
Copyright(c)2000-2006 MIRACLE LINUX CORPORATION. All Rights Reserved.