環境

2009/11/03

PCを買い換えた。

もし技術史の試験に合格していたのなら、CPUはXEONのW5580にしようと心に決めていたのだが、残念ながら落ちていたからCore-i7 920で妥協しておいた。

それでも、当然だが以前のマシンと比べれば比較にならないほど高速である。当たり前だが。

現在は新PCで今まで通り開発作業を行えるようにするために環境を整えている最中である。しかし、やることが多すぎていくら時間があっても足りない。とりあえず、画面のデザイン等はおおよそ自分のいいように調整することができ(それでも不満は多いが)。

とりあえず、画面を曝しておく。



Firefoxの後ろに見えているのは、VirtualBoxにより動作させているWindows2000である。XPモードではない。

本来であればこんなものは使う予定になかったのだが、なにぶんVisual Studio 6.0はバージョンが古すぎてWindows 7では動作しないのだから仕方がない。

だったらXPモードにしておけばいいのではないかという考えもあるのだが、いろいろと思うところがあって完全に環境を切り離しておくことにした。

感慨

2009/10/31

PCをリプレースすることになり、今日秋葉原で各種のPCパーツを買いそろえてきた。
今は、今夜で最期になる現行PCからこのblogを書いている。データを移し終わったら、後はバラして捨てるだけだ。

さすがに10年使ってきたPCだから、入れ替えるとなるとやはり感慨深いものがある。

ファジング

2009/10/26

久しぶりに、新しいコンテンツを一つ追加しておいた。ブルートフォース法によるファイルのファジングを行うツールである。

別に、どうしても急遽このツールが必要だったという訳ではない。ただ何となく、「主筆」で使用しているモジュールの動作を確認してみたくなって自作したに過ぎない。

「主筆」では設定ファイルとしてWindowsでよく使用されるini形式のファイルを使用している。しかし当然だが、Unixではini形式のファイルを読み込む標準のライブラリなどは存在しない。その為「主筆」では自前でini形式のファイルを読み込むモジュールを作成している。いや、正確に言えば「主筆」で使うために作ったのではなく、俺がそれよりも前に作成していたモジュールを流用したのである。

そういう経緯があるため、ini形式のファイルを読み込むモジュールは「主筆」を構成するモジュールの中でも群を抜いて古い。おそらく、俺が作ったプログラムの中で現存している最古のものではないかと思われる。

一般的に言って、古いプログラムというものはバグも少なく安定していると考えられている。つまり、技術的に枯れていると考えられる。だがこの場合は、何分俺が作って俺が使っているだけであるため、到底枯れているなどと言える状態にあるとは思えない。

そもそも、これを作った当時はセキュリティ性なんて微塵も考えておらず、単に動けばいいという程度にしか考えていなかった。だから攻撃を受けた場合に大丈夫なのかどうか全く自信がない。

だったら、自信がないのなら、十分なテストを行い品質を確保すればいい。そういうことで実際に攻撃をやってみようと言うことで作ったのがこのツールである。

まぁ、無論、このツールで生成できる攻撃用のファイルには制限も大きく、大して実用的とは言えないものかも知れない。だが、今後機会があれば拡張してゆく予定である。

PC

2009/10/22

長年使ってきた今のPCだが、ついに入れ替えようと思う。

OSやアプリケーションが変化しない限り、PCの性能が低くても問題はないものと考えていたのだが、やはり、必ずしもそういうわけにはいかないようだ。ウイルス対策ソフトにしろ、周辺機器にしろ、ブラウザで見るWebページにしろ、どうしても求められるPCのスペックは年々向上して行き、ついに俺も耐えきれなくなってきた。まぁ、CPUがK6-IIIの450MHzであることを考えれば、よくがんばった方だといってもいいだろう。

そうすると問題は、次はどんな奴にするのかという事だ。

SPECの値を俺なりに分析すると、以下の傾向があることが判った。
 ・純粋な1スレッドあたりの処理速度という観点からすれば、Core2Duoが一番早い。
 ・複数スレッドによる処理を考慮に入れた、CPU単体の処理速度という観点でいくと、XEONのW3580やCore-i7 965がほぼ拮抗していて最高速。XEONの5500番台は必ずしも一番早いと言うわけではないが、その差はわずかである。
 ・性能の値を価格で除したコストパフォーマンスで分析すると、Phenom II x4が群を抜いて一番いい。Core-i7 920は二番手集団に位置している。XEON、特に5500番台のコストパフォーマンスは著しく悪い。

また、これはSPEC intやSPEC floatのベンチマークの性質によるのだろうが、HTはほとんど性能向上に寄与していないらしい。それどころか、むしろスレッド数を増やした方が性能が劣化しているという結果が多数散見され、向上しているデータは少ないように見える。まぁ、Intelの誇大広告ですらHTによる性能向上は25%だというのだから、実際にはどれだけ早くなるのか、推して知るべしということなのだろう。

CPUの選定に関わる重要な要素は二つあるものと考えている。一つは性能である。これには、コストパフォーマンスの概念も含まれる。そしてもう一つは、男の沽券である。Core-i7やPhenom等といった民生用の軟弱なCPUでいいのか、それとも、男らしくXeonやOpteronにするのかという問題である。

OpteronはなぜかCPUそのものが売っていない。マザーボードも手に入りにくいようだ。そうすると、Opteronで自作という線は消える。そういう意味でのスキルは俺にはない。そうすると、男の沽券を守る方向でいくとなると、Xeinがもっとも可能性が高くなる。しかしこれではあまりにも価格が高くなりすぎる。俺の試算が正しければ、Xeonのマルチプロセッサ構成にした場合、55万から75万は必要になる。

では、安い方向でいくとした場合は、やはりコストパフォーマンスが重視されるから、Core-i7の920かPhenomである。Core-i5やCore-i7の800番台はベンチマークの結果になかったから評価していないが、価格によっては考慮の対象になる可能性もある。いずれにせよ、この方向で進んだ場合は、安ければ10万を下回る価格で手にはいる可能性がある。多少こだわっても、20万がいいところだ。

男の沽券を取るか、金を取るか。

どうにも決められないから、考え方を変えてみる。すなわち、俺の男の沽券の価格が55万円(75万-20万)と解釈してみる。そして、買うべきか否か悩むときには、悩んでいるものを人にその値段で売り払う事ができるか否かで考えるといいという。そのアルゴリズムに従って考えてみると、すなわち、俺の男の沽券を人にくれてやる(あるいは捨てる)代わりに55万円入ってくるという事になる。俺の沽券に55万もの価値があるのだろうか。

だがしかし、男の沽券とはそもそもなんなのだろうか?

困難

2009/08/29

三ヶ月ぶりに着信メールを確認したら、ジャンクメールが多数きていたから全部消してしまった。最も、メールボックスの容量はなぜか知らないが120MBまで利用できるため、あふれると言うことはないのだが。

今現在、「主筆」の文字列データを保持するロジックを開発しているのだが、最近になってようやく文字列をまともに追加/削除できるようになってきた。後は、構文に従って色を設定するロジックと、文字幅から行がされる位置を決定するロジックを作り込むのみである。

しかし、この処理は複数スレッドを回して並列に処理させるつもりである。すなわち、今まで作り込んできた処理の難易度はほんの序の口で、これからが本番だと言える。それぐらい困難な作業になることが予想される。

一応、基本的な考え方やアルゴリズムについては、頭の中ではできてはいるのだが、しかし、それをコードに落とすのがそう簡単にできることとは思われない。とりあえず、スレッドの生成やウェイトを行うための部品を作るところから手を付け始めたが、すでにして難しい雰囲気が十分に漂ってきている。

まぁ、誰に急かされている訳でもないのだから、ゆっくりと進めていくまでの話だが。

UPS

2009/07/26

気がついたら、オーディオ機器に接続するUPSが著しく増殖していた。



別にだからなんだということでもないが。

ついでに言うと、左に見えている黒い板はPioneerのKUROの背面である。でもって、這い回っているケーブルの大部分は電源とLANである。

出火しなければいいのだが。

同期

2009/07/20

主筆」の、テキストデータを保持し、編集する部分の実装を進めてはいるのだが、やはり難しい。とりあえず、文字列の追加と削除を行う処理だけを先に作って、その部分だけでもとりあえず動くようにしようと考えているのだが、それだけでも難しい。

今現時点では、追加・削除の処理を行う部分のコーディングが終わり、少しずつ動かし始めてはいるのだが、どうにも思うように動いてくれない。一つ課題が解決すれば、また次の問題が生じるという状態で、苦しいことこの上ない。いかんせん、アルゴリズムそのものが複雑なのだから仕方がない。

ところで、今頑張って作っているロジックは、ウインドウ幅での行折り返しを実現するということと共に、複数の処理を並列で走らせて、処理効率を向上するという目的もある。とすると、何らかの方法で、スレッド間の排他制御を行い、矛盾が生じないようにしてやらなければならないはずである。しかも、処理効率向上を目的としているのだから、ごく単純に、あるスレッドがデータ構造にアクセスしようとする都度、データ全体に対して排他ロックを掛けると言うような方式を採用するわけには行かない。複数スレッドが矛盾が生じない限り、複数のスレッドが同時にアクセスできるような方式を考えなければならない。

しかしこれはこれで非常に難しい問題である。

直感的に言って、ツリー構造全体にロックをかけてしまうのが野蛮だというのであれば、ツリーの個々のノードに対してロックをかけるようにすればいいような気がし無くもない。そうすれば、少なくとも矛盾が生じることなく、かつ、複数スレッドで同時にデータ構造にアクセスすることができるようになるはずである。

しかし、その方式には大きな問題点がある。まず、各ノード間には複雑なデータの依存性があるという事だ。つまり、親ノードは子ノードに対するインデックスであるため、子ノードの情報を変更した場合はその変更が親ノードに反映されなければならない場合がある。そのため、単純に一つのノードをロックすると言っても、実際に排他をかけなければいけない範囲は、単一のノードよりもはもう少し広いということになる。そのため、ロックをかける範囲がはっきりせず、実装が困難だと思われる。

さらに、個々のスレッドがどのような順番でノードにアクセスするかが決められないため、場合によってはデッドロックに陥る危険性があるという問題がある。各スレッドの処理をACID特性に従ったトランザクションとして実装するのであれば、デッドロックが生じた場合には、それを検出して一方をロールバックするという方法も考えられる。だが、そこまでやるのは明らかに大仰過ぎる上に、処理速度的にも不利になる。だから、処理が途中で失敗したら元に戻せるような実装にすることはできない。すなわち、デッドロックから回復する術がないということであるため、そもそも、デッドロックが発生しないような、何らかの方法を考えなければならない。

デッドロックを防ぐためには、各リソースに対して、ロックをかける順番をあらかじめ決めておいてしまえばいい。そうすれば、理論上デッドロックは発生し得なくなる。しかし、今回はその方式を採用することはできない。

ツリー構造である都合上、同一の高さのノードを左右に移動するようなアクセスはあまり起こらないと考えられる。そうすると、ロックをかける順番を「上から」と「下から」のどちらかに限定しさえすれば、デッドロックを防ぐことができるような気がする。しかし、必ず上(ルート側)から順番にロックをかけるようにする、というルールを決めた場合、それは、アクセスする都度必ずツリー全体にロックをかけるという方式と同じになってしまう。なぜならば、ツリー構造である都合上、アクセスそのものが必ずルートから行われることになるためである。また、下(葉)から順番にロックをかけるというのも、同じ理由で成立し得ない。いきなり葉からアクセスすることはできないからだ。

また、この考えを延長して行くと、二層ロックを採用することも不可能という事になる。ツリー構造にアクセスするためには、まずルートにアクセスする必要があり、そのためにルートのノードに対してロックをかけることになる。その後、自分が一通りの処理を終えるまでずっとルートのノードを押さえ続けていたら、その間ずっと他のスレッドはツリー構造にアクセスすることができなくなってしまう。だから、どうしても処理途中であっても使わなくなったノードは解放してやるようにしてあげなければならない。

そう考えていくと、どうにも八方塞がりの様な気がしてくる。しかし、あまり汎用性のない、アプリケーション依存な方法を使うのであれば、全くやりようがないという事でもないようだ。まず、データ構造にアクセスするスレッドの種類・数・アクセスパターンは、あらかじめはっきりと判っている(何せ自分で作るのだから)。そこから、起こりうる競合を全て洗い出して、各競合に対してどのように対処すればいいかを一つずつ決めていけばいい。そうすれば、高い効率を維持したまま、矛盾やデッドロックを生じさせないようにすることが可能である。

とりあえず、考えた結果については、また今度気が向いたら書くことにしよう。

時間

2009/07/10

「主筆」の文字列を保持するデータ構造の実装を始めてからかなり時間が経つが、まだコーディングも終わっていない。そもそも、テキストファイルの読み込み/文字コードの変換/マルチバイト-ワイドバイトの変換/データ構造への格納/構文強調表示処理/文字の描画位置の確定/画面への文字列の描画という7種類の処理を全て並列に処理させようと言う野心的な目標なのだから、そう簡単に終わるものとは考えていない。その上、ウインドウ幅での行折り返しに対応させるために、いくつかの余分なデータも保持させなければならないのだから、ますます事態は複雑化し混迷を極めている。

しかし、「主筆」の開発を進める一方で技術士の受験勉強もしなければならない。気がついてみれば、試験日まであと一ヶ月を切っている。論文を書く練習なども、このところ少しさぼり気味だったから、また復活させなければならない。時間は限りなく無いと言える。

どうやらこれは、エロ画像の収集に精を出している場合ではなさそうだ。

共連れ

2009/06/12

ビューとドキュメントの分割に手を付けたのは良いのだが、それをやるためにはどうしてもドキュメント部分の内部構造に大幅に手を入れなければならないようだ。

当面の所は既存ロジックを極力残したまま分割だけを先にやってしまおうと考えていたのだが、やはりどうにも構造がクソで流用するのも難しいと判断したのだ。

そういうことで、ここ数日は文字列操作の要となるデータ構造をどうするかということについて死ぬほど考えていた。

データとして保持しなければならないのは、文字そのものと文字の色、文字の幅である。色は構文強調表示で必要となり、文字の幅はプロポーショナルフォントを取り扱う上で必要となる。でもって、下記の操作に対して最悪でもlog(n)の計算量で処理を完了するようにしなければならない。
 ・文字列の追加
 ・文字列の削除
 ・文字の検索

ここで文字の検索といっているのは、何らかの方法で指定された位置に存在する、とある一文字が格納されているメモリアドレスを求める事を言っている。でもって「何らかの方法」というのには下記のような方法が考えられる。
 ・(行折り返しを考慮しない)行番号と、行頭からの文字数
 ・(行折り返しを考慮した)行番号と、行頭からの文字数

先頭から数えた文字数を用いて、配列のようにアドレッシングを行う可能性は低そうである。どちらかといえば、「画面上のココ」という指定をされて、その文字がメモリ空間中のどこに存在するのかを求める事の方が重要であると思われる。

また、表示や編集の処理を考えた場合、アドレッシングを方法を相互変換する機能も必要になるのは明白である。すなわち、
 ・文字を示すメモリアドレスから、行折り返しを考慮しない行番号と、行頭からの文字数を求める
 ・文字を示すメモリアドレスから、行折り返しを考慮した行番号と、行頭からの文字数を求める
 ・行折り返しを考慮しない行番号と行頭からの文字数から、行折り返しを考慮した行番号と行頭からの文字数を求める
 ・行折り返しを考慮した行番号と行頭からの文字数から、行折り返しを考慮しない行番号と行頭からの文字数を求める
という処理である。

上記の処理はいずれも、一見すると難しいような気もするが、計算量を考慮しない限りそれ程難易度の高いものではない。例えば、文字列を単純に配列に格納して、必要な都度文字列の先頭から総ナメにして要求された値を算出するようにしてやれば、よほどの馬鹿でもない限り実装することは可能なはずである。

だが、問題はこれらの処理を、文字数に対してlog(n)の計算量で解かなければならない所に存在する。

現在で主筆で使用しているロジックは、与えられた文字列を改行コードで区切って部分文字列を構築し、それら部分文字列を指し示すポインタを、単純な配列に入れて管理している。

だから、それこそ何の考えもなしに単一の配列に押し込んでいるよりかは幾分マシだとは言え、本質的には計算量はnに比例する。だから、余り大きなファイルを開くと性能が著しく劣化する。更に、一行の長さがあまりに長くなると、それこそ応答が返ってこないという事態になりかねないため、一行の最大長を10KBにするという制約を設けている。よって、これらの問題をここで一気に解消したいと考えている。

では、どういうデータ構造にすればいいのか。というか、計算量がlog(n)などという、言ってみればデータ量が増えれば増えるほど一文字当たりの計算量が減少するなどという、ご都合主義的な方法が存在するのだろうか?

答えから言えば、方法は存在する。存在するからこそ、こうして俺はゴタクを並べてblogを書いている。

方法としては、B+木を用いればいいはずである。無論「一意に識別できる値を使ってレコードを識別する」という処理ではないため、アルゴリズムは多少変則的なものになるが、それでも不可能ではない。というか、以前、こういった問題について考えたことがあり、その結果をこのページに記述している。要は、これと同じ事をしてやればいいはずなのである。

とは言っても、やはりそれが難しい。

とりあえずは、具体的なデータ構造や値の検索・更新の方法について、ある程度の目処が立ったところではあるが、実装はまだ全く手が着いていない。このままでは第21版の公開は、かなり遠い未来のこととなるであろう。

偽物

2009/05/26

「主筆」のビューとドキュメントの分割に手を着ける前に、とりあえずフォルダ構成を見直しておくことにした。現時点でも、現在公開している第20版には存在しない共有ライブラリが増えているし、フォルダ名がいくつか気に入らない奴が有るため、今の内にきれいにしておくことにしたのだ。

また、生成された共有ライブラリと、その共有ライブラリを使用するために必要となるヘッダファイルが、その共有ライブラリを開発するためのフォルダ内に格納されたままだと何かと都合が悪いため、別途includeとlibというフォルダを用意して、コンパイル後にそのフォルダにシンボリックリンクを作成するようにしておいた。

つまり、たとえばTaEdit/FOOというフォルダを作って、その中でlibFOO.soというライブラリを構築するようにしたとする。そうすると、libFOO.soそのものと、それを使うためのヘッダファイル、たとえばfoo.hは、TaEdit/FOOフォルダの中に存在する事になる。となると、そのlibFOO.soを使うプログラムは、コンパイル時にヘッダファイルとライブラリの検索パスとして、TaEdit/FOOというフォルダのパス名を指定してあげなければならなくなる。

とりあえず、使用するライブラリが1つだけであれば、それは大した事ではない。だが、そういったライブラリがだんだん増えてくると、コンパイル時に指定しなければならなくなるパス名が増えてくることになる。まぁ、だとしても、指定すればいいだけの話だと言ってしまえばそれまでだが、やはりそれでは美しくないため、外部に公開する奴は「公開されるためのフォルダ」を作って、そこに格納するようにしたほうがいい。そうしておけば物事がわかりやすくなるから、コンパイルするときにヘッダファイルが見つからないだの、リンク時にシンボルが見つからないだのと言われる可能性を減らすことができるようになる。

フォルダ構成の整理は、基本的にはMakefileをいじるだけだからそう大した話ではない。もっとも、複数人で開発している場合は、逆にほとんど不可能に等しい荒技ということになるのだが。

今現在は、COMの偽物の仕様ついて考えている。WindowsのCOMの様なことをやりたいとはいっても、しかし、COMそのものを作るつもりはないし、COMと張り合おうというつもりもない。ただ、自分が作ったアプリケーションの範囲内だけでつかわれる、それっぽくモジュールを分割できるような仕掛けが有ればそれでいいのだ。

そうすると、もっともストイックな実装としては、ただ、純粋仮想クラスを継承したオブジェクトを生成して、そのインスタンスを返してよこすだけのライブラリというのが考えられる。すなわち、そのライブラリで提供される関数を一回呼び出してやれば、IDocumentとか何とか、そんな感じの純粋仮想クラスのポインタを返す、そういうライブラリにしておくということだ。

だが、それではちょっとありがたみが薄い。どうせなら、そのライブラリのインタフェース仕様(つまり関数の仕様)や、オブジェクトのインタフェースとなる純粋仮想クラスに一定の規約を当てはめ、その規約を強制するようなライブラリを一枚かぶせるようにした方がいい。そもそも、共有ライブラリの動的ロードや実行時に関数を検索する処理など、ライブラリや実装するオブジェクトによらずみんな同じになるのだから、どうせなら処理を統合した方がいい。

とすると、その規約なりライブラリなりで、どこまで何をサポートするのかが問題となる。とりあえず、純粋仮想クラスを継承したオブジェクトを生成するという機能と、ライブラリ自体がエクスポートする関数は完全にC言語の仕様に準拠していること等と言った物事は、そもそもの目的であることからして外すわけには行かない。

だが、IUnknown::AddRefやIUnknown::Releaseといったメソッドにより提供される、インスタンス管理の機能は必要なのだろうか? 難しいことをやりたいわけでもなし、とりあえずオブジェクトを使う側で間違えなければ、わざわざインスタンス管理の機能をここで実装してやる必要はないものと思われる。もし、参照カウンタなりガーベッジコレクタなりでメモリ管理を行う様にしたいので有れば、それは別の機能として実現すればいいまでの話だ。

また、オブジェクトが提供する別のインタフェースを取得する機能も必要ではない。そんなものは適用にやればいい。COMではGUIDによりインタフェースなどに一意な名前を採番するようにしているが、それも簡略化していいはずだ。どうで、1アプリケーションに閉じた世界の話なのだ。世界中で一意にに識別できなければならない必要性などない。

微妙なのは、インタフェースを実装するライブラリをどこかに登録しておいて、オブジェクト生成時に、自動的に目的となるライブラリを検索できるようにする仕掛けがいるかどうかだ。COMではインタフェースに割り当てられたGUIDとDLLのファイル名をレジストリに登録しておいて、オブジェクトを生成する際にはDLLのファイル名や物理的な場所については意識しなくてもいいようになっている。だが、今回俺が作ろうとしているものには、そのような機能は必要であろうか?

ビューの方から本物のライブラリ名を指定してオブジェクトを生成させるようにしたところで、あまり実害はなさそうな気がする。だが、ライブラリのファイル名とインタフェース名を事前に何かの設定ファイルに登録しておくようにすれば、アプリケーションでライブラリのファイルを保持する必要が無くなり、何か便利になるような気がする。

だが、それ以上の具体的な利点が見えない。必要だろうか? 不要だろうか? どっちでも良さそうな気がするが、きめなきゃ物事が進まない。どうしようか。