[ADP開発日誌]あるITエンジニアのコミュニケーション能力 について2011

以前からSourceForge.JPさんで、ドキュメント執筆者とテスト担当者を募集しているのですが、残念ながら良い人が来なくて、自己顕示欲の強いというか思い込みの激しい人が来て手間ばかりかかって結局ご遠慮頂きましたということでそのレポートを。
 
こんなことはわざわざ書かなくてもよいかとも思いますが、こちらもドキュメントを書いて欲しいため、チャットまでして説明した手間もありせっかくなのでネタにしたいというのもありますし、また変な人がこられても困るのでその予防線と、一応開発日誌と銘打っているブログなのでこういうマイナスなことも隠さずに書くのも面白いかと思ったので書いてみます。
 
その方(以下Aさんとします)は、某大手のIT企業に勤めているらしいのですが(わざわざご自身で大手IT企業と言ってしまうところはどうかと思ったのですが)、ご自身でもプログラミング言語を作成しているとのことで互いに勉強にもなるかとも思いました。
 
何回かメールでのやり取りで、簡単な自己紹介、技術概要、開発方針、ドキュメント作成のポイント等を説明し、チャットでさらに補足説明をしました。
で、ドキュメント作成を行わなければならないのですが、Aさんは片手間にしか参加できないとのことで、レビューをやってもらおうとその旨をお伝えしたところ、Aさんから
 
『後、気になっているのは(もしもですが)参加者がたくさん増えたときに大藤さんの心構えが実はできているか?です。』
 
とのコメントを頂きました。私はオープンソースに対する心構ができていないとのことなのですが、そもそも『心構え』ということが理解できなくて、真意を確かめることも含めてまずは今回はご遠慮いただく旨のメールを送りました。そうすると、
 
『確かにメール受け取りました。想定通りの回答です。』
で始まり、
『僕はオープンソースに上げてみようと思ったときに果たして他の人に触らせたり、色々言わせたりできるだろうかと言う質問を自分にしました。』
と来て、
『話をしていて、大藤さんはまだノーの様な気はしていたんです。』
『色々な人の意見を採り入れたいと言っていたが、まだその時期ではないのではと。』
 
と結論付けておられました。どう突っ込んだらよいのか困ったのですが、まぁ今回はご遠慮いただいてよかったかと思いました。
Aさんの勘違いを指摘しますと、私はADPをGPLで配布していますが、これは利用者が好き勝手にできることを私が認めたことになります。つまり、
『他の人に触らせること』
については私もライセンス上認めております。AさんはGPLをご存知ないのでしょうか。
また、『色々言われること』についてですが、実際にSkypeでAさんとチャットしているときも『Prologが解らない人向けのドキュメント作りを』と指摘されそりゃもっともだと思ったでのでSourceForgeのチケットにも登録しました。
もちろんですが、人の意見を聞きたいといっても、必然的に他の方の意見を取り入れる面と取り入れない面があります。その取捨選択はアーキテクトである私の仕事だと思っています。
もっともADPはプログラミングの初心者を対象としています。ので初心者の方の意見というは極力尊重したいです。ちなみにですが、PHPのようなお手軽な言語を目指しています。のでご意見どしどし受け付けています。
 
自分自身の若かりしころの反省も含めてITエンジニアの方にコメントしますと、他人とのコミュニケーションをとる上で相手の内面についての不用意な否定はやめた方がよろしいかと思います。Aさんは私に心構えという単語を使いましたが、根本的にオープンソースのプロジェクトをやろう!、という人間が心構えができていないことは、ほぼないです。
本当に心構えができていなくかつ教育が必要な新人を除いて、このような単語を使うことは相手を怒らせるくらいしかできません。もしくは相手から『こいつはコミュニケーション能力がない』と思われるでしょう。
これは仕事の面でもいえるかと思います。大手のIT企業に勤めていたら、出来の悪い協力会社の担当者に向かって思わず『やる気があるのか?』等、同様のことを言ってしまうこともあるかもしれませんが、そう思ったときはじっとこらえて『なぜ、私はこの人がやる気がないと感じたのか?』とじっくり自問自答しましょう。そのときに根拠となる理由が1つでは足りないですし、またその理由が思い込みではないと、確認する必要があります。
『僕はオープンソースに上げてみようと思ったときに果たして他の人に触らせたり、色々言わせたりできるだろうかと言う質問を自分にしました。』
『話をしていて、大藤さんはまだノーの様な気はしていたんです。』
私の話のどこにそう思ったのか不明ですが、私がソースをオープンにし、GPLでリリースした時点で、ノーということはありえません。このように多角的な検証が必要です。
 
相手を批判する場合(相手の内面の場合は特に)、思い込みで論理を展開しないで自分の考えを吟味する必要があります。さらに、相手の置かれている立場や考え方も考慮に入れましょう。
  
私も若かりしころ上司から、『口のきき方が悪い』と怒られたりしたことがありましたが、そのときは何で怒られたかよく解っていませんでしたが、おそらくAさんのように思い込みが激しかったのかもしれません。
最近では、あまりこういう面で他人から指摘を受けることもなくなっていましたが、今度は自分が指摘をする番になったようです。

[ADP開発日誌]0.69リリース

前回のリリースから1週間ちょっとですが、はやくも0.69のリリースです。
前回からの修正が多かったので、バージョンをちょっと進めて0.70の0.01前で、0.69にしました。
 
先週のリリースからSourceForge強化週間ということで、 チケットシステムを使ってみました。これを使うとポイントがもらえてそのポイントが増えると活発なプロジェクトということで認定される仕組みです。
これがプロジェクト的にはヒットしまして、結構改修が進みました。
ちなみにマイルストーンも立てることが出来ますので次回のバージョン0.7も立ててます。
 
少々名称に納得できなかったライブラリですが、今回のリリースでライブラリの名称の整理を行いました。
これで停滞していたライブラリのドキュメントを充実させることが出来ます。
 
最後に2ヶ月ごしになりましたが以前からアナウンスしていました、Wordpressの高速ビューアーもリリースしています。

[ADP開発日誌]0.62リリース

約2ヶ月ぶりのリリースになります。
今回の修正は、
・sendmail述語の追加(メール送信)
・rkey述語の追加(ランダムなキーを取得する)
・乱数をメルセンヌツイスターを使用するように回収
・set_session_cookie述語の追加(セッションIDクッキーの、ドメイン、パス、有効期限、セキュリティを設定)
・now述語の変更(現在時+a秒の表示を行える)
・remap述語の追加(ハッシュキーの交換)
・keys述語の追加(ハッシュキーの一覧を返す)
・DB周りでエラーが発生し終了した場合、ODBCドライバ内で例外となるバグの修正
・?ポストフィックス(評価がfalseでもバックトラックしない)の追加、last述語(直前の?述語の評価結果を返す)の追加
と盛りだくさんになりました。
いろいろ追加・変更点がありますが、面白いのは、乱数のアルゴリズムを標準Cライブラリのものからメルセンヌツイスタ(MT)と呼ばれるものに変更した点です。
 
詳しくはホームページを見ていただければと思うのですが、かなり強力な乱数生成器のようで、perl や php にも導入されています。
ということで、我がADPでもMTを使用することにしました。
作者の松本先生に許可を取りましたところ快く了解いただきました。この場を借りてお礼を申し上げます。

MVCの議論でみるプログラミングパラダイムに対する距離のとり方

OpenBlocks600の記事で紹介しましたブログビューアーですが、その後、バグ修正やRSS関係の対応をしてから1週間経ち、apacheのエラーログにもエラーが出ていないので、そろそろリリースしようかなと思いソースを眺めていたのですが、あまり教示的なソースでなく『公開すべきか、せざるべきか・・・』と悩んでおったのですが、こういうときは他人はどうしているのかと、最近のWEBアプリの動向でも探ろうかとネットを検索しましたところ、面白い記事を見つけました。
 
http://satoshi.blogs.com/life/2009/10/rails_mvc.html Ruby on Railsの「えせMVC」の弊害
 
http://satoshi.blogs.com/life/2009/10/ormappingmvc.html O/Rマッピング技術の進化が皮肉にも助長している「えせMVC症候群」
  
ブログ主(Satoshi Nakajimaさん)の主張ですが、要するにモデルとコントローラの役割はきちんと分けようねということで、『ビジネスロジックをコントローラに書くのはNG』とのことのようです。
ちなみに私ですが、ちょい書きのアプリだとまぁコントローラでビジネスロジックどころか、SQLを書いたりします。またブログビューアーの構造も思いっきりMVCモデルから逸脱しているので・・・という訳でブログビューアーを書き直そうかなとか思ったのですが、もう少し調べてみようということで、以下、Rubyの作者のまつもとさんの記事を見つけました。
 
http://itpro.nikkeibp.co.jp/article/COLUMN/20080610/307218/ まつもと直伝 プログラミングのオキテ 第20回 MVCとRuby on Rails
 
この記事の7ページ目の表2にRailsのMVCということで従来のMVCとの比較がありますが、その表から2パラグラフ目の説明を引用しますと
 

 一方,HTTPの性質によってUI部分の複雑さはWebブラウザに任せてしまっているWebアプリケーションでは,相対的にUI層が薄くなります。コントローラ相当はほぼ汎用品で十分ですし,モデルとビューのインタラクションも不要です。ですから,モデルをデータベース層とビジネス・ロジック層に分割して,下層をモデル,上層をコントローラと呼ぶようにしたのでしょう。

  
ということで、まつもとさんの説によるとビジネス・ロジック層はコントローラに記述することになるようです。
かの有名なRubyの作者のまつもとさんが、このように言っておられるのでこの勝負は『Railsでは、ビジネス・ロジック層はコントローラに記述する』で軍配が上がりそうですが、実は先のブログ主さん(Satoshi Nakajimaさん)も知る日とぞ知る方で、過去にマイクロソフト社に勤務されておりWindows95の開発では、Windows3.1との互換性を保つために尽力されたらしく、そのあたりの話はこちらで参照できます。また先の主張は、実際にRuby on Railsを使ったプロジェクト通して行き着いたようでしてそれなりに説得力があります。
 
このように著名なエンジニアの見解が異なる場合、どのように解釈すればよいのか悩ましいところですが、実行速度についてとか明確に白黒つく場合のように客観的に測定できる事実が無い場合、
『どちらでも良い』
というのが私の経験から来る見解になります。
この手の議論はエンジニアを引き付けるものがあり、熱くなったりするのですが、議論してもみのりは少なかったりします。
私も過去にこの手の議論に巻き込まれたことがあるのですが、特に個々のエンジニアが持つバックグランドが異なる場合、あまり前向きな議論にならなかったです。
今はインターネットがあるので様々なエンジニアの見解を比較することができるので、このように『他の人はどう考えているか?』というのをわざわざ議論しなくても解るので改めていい時代になったと思います。
 
というわけで、まぁブログビューアーは作り直さずに公開したいと思います。

[ADP開発日誌]0.61リリース OpenBlocks600D対応+WOL(Wake On Lan)

以前に、ADPをOpenBlocks600Dに対応させた話を書きましたが、予告(?)どおりADP 0.61のリリースを行います。ブログビューワーの方は後ほどということで・・・必要な方はコメント欄にほしいとリクエストください(気持ち急ぎます)。
 
OpenBlockS600Dのバイナリ版を実行させる場合は以下のパッケージがインストールされている必要があります。

  • libboost-regex1.35.0
  • openssl
  • unixodbc

場合によっては(ソースからコンパイルされる方は)さらに以下のパッケージが必要です。

  • libboost1.35-dev
  • libssl-dev
  • unixodbc-dev

 
ちなみにWindows版のバイナリは、特に依存関係はないので、そのまま実行できます。
 
0.60でパフォーマンスを上げたのですが、バグがぼろぼろ出まして修正しました。だいぶ品質が向上したかと思います。もっとも、もっと本格的なテストプログラムを記述しないとダメだと思いますが・・・そのノウハウの蓄積は今後に期待ですね・・・。
ただ一部の修正(メモリの管理関係)でパフォーマンスが下がったのでこのあたりはまた変更する必要があります。オープンソース&マイナープロジェクトの良いところはバグを恐れずにガシガシ修正できるところですね、お金を頂戴するプロジェクトではここまで冒険はできません・・・。
 
また、今回のリリースではwol(Wake On Lan)述語(関数)も追加しています。文字通りWOLパケットを送出する述語です。
何でこんな述語を追加したのかと言いますと、前回の記事のとおり最近モバイル環境を構築したのですが、これに加えてVPNを構築すると外部からイントラ環境にログオンすることができ、そうするとリモートディスクトップで私のマシンにログオンしたくなるのですが、ログオンするためには電源が入っていなければならず、とは言っても何時ログオンするかどうか解らないマシンの電源を入れっぱなしにする訳にもいかない、という訳でWOLで電源を入れることになり述語を追加しました。
WOLを送信するマシンは、LED電球並の消費電力のOpenBlocks600Dにすればよろしいでしょう。外部からはウエブから入るようにします。つまりブログビューアと同様にADPでWEBページをホストします。
というわけで、以下、WOLのコードになります。
 
wol.awp

#!/bin/adp -
<%;
+keycode("password");	# パスワードを指定
+machines("00-11-22-33-44-55", "machine1");	# MACアドレスとマシン名(適当でよい)を指定
+machines("66-77-88-99-aa-bb", "machine2"); # 複数あるときは同じように複数行にわたって記述する
+baddr("192.168.1.255"); # ブロードキャストアドレスを指定
,query("KEY").keycode, $mac =query("MAC"), wol($mac, =baddr);
%>
<html>
<head>
<meta http-equiv="Content-Language" content="ja">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ネットワークブート</title>
</head>
<body>
ネットワークブート
<%,query("MAC",$mac),%><%=$mac%>BOOT中<%;%>
<br>
<form action="wol.awp" method="post" OnSubmit="return confirm('起動しますか?')">
キーコード:<input type="text" name="KEY" value=""><br>
起動マシン:
<select name="MAC">
	<%,machines($mac, $name) ,%>
		<option value="<%=$mac%>"><%=$name%>
	<%,next;%>
</select>
<input type="submit" value="boot">
</form>
</body>
</html>

※2012/05/21 Ver 0.81のリリースにあわせて更新
 
ファイル名はwol.awpとします。form actionの引数を変えればファイル名自体はなんでも構いません(まぁ解らないようにした方がよい)が、拡張子はawpにする必要があります。
awpとは「Adp Web Page」の略で、ADPでWEBページをホストするモード(AWPモード)の拡張子になります。
Ver0.61では、拡張子がawpまたはcgiのみAWPモードになります。
 
これをApacheでcgiスクリプトとして、ホストすればOKなのですが、その前にスクリプト使い方の説明を、
先頭の3行目から6行目が設定になります。最低限のセキュリティということで、
パスワードの指定(3行目)と起動対象のマシンのMACアドレスと名前(4,5行目)と
起動対象のマシンがあるブロードキャストアドレスを指定(6行目)になります。
 
スクリプトの動作環境の設定ですが、PerlやPHPのCGIと同様にセットアップして頂けれたよいのですが、以下、apacheでのセットアップを簡単に説明します。
adpの実行ファイルを、/bin に保存します。/binがダメな方は、上記のスクリプトの1行目でadpのパスを指定します。
apacheのconfファイルですが、DirectoryのOptionsにExecCGIを追加し、AddHandlerで .awpを追加します。
以下、サンプルを載せます。

    <Directory "/var/www/html">
        Options FollowSymLinks ExecCGi +Includes
        DirectoryIndex index.html index.php index.awp
        AddHandler  cgi-script .awp
        AddHandler  cgi-script .cgi
        AllowOverride None
        Order allow,deny
        Allow from all
    </Directory>

Windows+IISでも動作可能です・・・設定方法は・・・まぁがんばってみて下さい。
(ご要望がありましたら設定方法を記載します・・・)

OpenBlockS 600

Windows7,2008R2に引き続き、これまた1年越しの作業になりましたが、我がohfuji.nameをホストするマシンをOpenBlockS 600(正確にはOpenBlockS 600D相当)に置き換えました。
 
OpenBlockS 600とは、ぷらっとホーム社さんが製造・販売しているマイクロサーバーで、こちらが製品情報になります。ちなみに2月現在キャンペーンをやっておられます。
 
OpenBlockS 600自体の解説はいろいろな場所で行われているので、そちらにおまかせしますが、特質すべきは、抜群の低消費電力で、私がエコワットで測定した結果は9Wでした。またファンレスでストレージはコンパクトフラッシュを使うので音が出なくてかつ障害に強く、商業利用はもちろん、自宅サーバーとしても重宝するかと思います。
 
OSですが、OpenBlockS 600はSSD Linuxがプリインストールされています。また600DはDebianがプリインストールされています。メモリは1GB積んでいますのでDNSサーバーやメールサーバーとしては申し分ないスペックです。
難点が、CPUにPOWER-PCを使用しているところで、私のようなプログラミングをする人間にとっては開発環境を別途用意しないといけないのと、さらにそのCPUの動作周波数が600MHzとお世辞にも速いと言えないところで、Apacheで静的なページを運用するならともかく動的なページは難があるかと思います。特に普通のサーバーでも重たいWordpressをOpenBlockS 600で運用するのは厳しいかと思います。
 
では、このブログ(Wordpressなんですが・・)はどうしているのかと言いますと、このページはADPで作成したブログビューアーで表示しています。我がADPもOpen BlockS 600Dに移植しまして、このとおり動作しておる次第です。このページを頻繁に訪問される方は気がついておられたかと思いますが、最近Wordpressが重くなっていたので、どげんかせんといかんと思っておったところです。このような厳しい条件を克服するのはソフトウェアエンジニアとしてロマンを感じたりします。
しばらく運用してみてOKであれば、OpenBlockS 600D版のADPと共にブログビューアー(Adp WorPdress bLOG viewer - AWPLOG)のソースを公開しようかと思っております。

2011/06/23 追記:節電の為、自宅サーバー類は仮想マシンとして別のサーバーに集約しましたので、現在このサーバーはOpenBlocks 600D上では動作していません。

[ADP開発日誌]SQL(JOIN)の実行パフォーマンスについて2011

以前に書いたこの記事に関してコメントをもらいちょうど記事にしようかと思っていたところでしたので、ADPのキャッシュ機能を使い、この記事の実験をADPでやったらどうなるかみてみます。
 
SQLでjoin(結合)と言えばSQLに慣れた方にとっては馴染み深いものですが、初心者にとっては一種の登竜門のようで、joinを避けたコードを見かけたりすることがあります(まぁ私も十数年前にはこのような理由でjoinを避けたコードを書いた記憶があります)。また、O/Rマッパーではテーブル毎にクラスを対応させる関係で、joinの取扱がややこしかったりします。
それ以外でも、私の場合になりますが、過去にパフォーマンス上の理由からjoinを行わなかったことがあります。
今回は、前回の実験と同様に
・SQLでjoinさせる。
・ADPでjoinさせる。
でパフォーマンスの違いについていくつかの実験を行い計測します。

実験環境

JOINのパフォーマンス実験環境はこちらに記述しています。
 

実験1 素直にSQL側でjoinをさせたものを実行

例により、SQLで素直にjoinさせてみます。以下のようなコードになります。

,$db = "DSN=Trade"
,$str = "SELECT Price.CODE, RDATE, OPEN, CLOSE, NAME FROM Price "
        "INNER JOIN Company ON (Price.CODE = Company.CODE)"
,sql@($db,$str,[]).csv.prtn,next;

 
少しコードの説明を、
1行目の、$db=~ の部分は、ODBCの接続文字列を指定します。上記のコードは、ODBCのデータソース名Tradeを指定している接続文字列になっています。
2,3行目の、$strの部分はSQL文を変数$strに代入しています。本来は1行で書けますが、wordpressで見やすいように2行で書いています。
4行目の
,sql@($db,$str,[]).csv.prtn,next;
sqlは組み込みの述語で、「ODBC-APIを使いsqlを実行し、結果を配列(@)で受け取り、csvに変換し、prtnで画面に出力し、nextで全ての結果を出力する」というコードになります。
自画自賛になりますが、必要最低限の情報だけで簡単にSQLが発行できているので、ADPの開発目標の一つである「SQLとの親和性が高い言語を目指す」を具現している例だと思います。
 
実行時間ですが、

D:\>adp -t sql_test_1.p > sql_test1.txt
time is 119192ms.

 
で、約119秒となりました。
 

実験2-A ADP側でjoin(ネステッドループ)

続いて、ADP側でネステッドループjoinさせてみましょう。
 

,$db = "DSN=Trade"
,$price = "SELECT CODE,RDATE,OPEN,CLOSE FROM Price"
,$company = "SELECT NAME FROM Company WHERE CODE = ?"
,sql( $db, $price, [], @rec)
 ,sql( $db,$company, [$rec[0]], $name)
  ,csv($rec,$name).prtn,next;

 
ADPのDBライブラリは、前に紹介しましたODBCライブラリがベースになっていますので、ODBCのパラメータクエリが使えます。
5行目のコードがパラメータクエリを使っています。

実行時間ですが、

D:\>adp -t sql_test_2.p > sql_test2.txt
time is 1717284ms.

 
で、約1717秒となりました。実験1と比べて約14倍の実行時間です。
 

実験2-B ADP側でjoin(ネステッドループ&キャッシュ)

さらに続いて、ネステッドループjoinをADPのキャッシュ機能を使って高速化をはかります。
 

,$db = "DSN=Trade"
,$price = "SELECT CODE,RDATE,OPEN,CLOSE FROM Price"
,$company = "SELECT NAME FROM Company WHERE CODE = ?"
,sql( $db, $price, [], @rec)
 ,sql$( $db,$company, [$rec[0]], $name)
  ,csv($rec,$name).prtn,next;

 
呼び出し述語名の後ろに$をつければキャッシュ機能がONになります。上記のコードでは5行目の sql$ がキャッシュ機能を使用しています。
では、実行時間をみてみましょう。
 

D:\>adp -t sql_test_2.p > sql_test2.txt
time is 116770ms.

 
で、約117秒となりました。
実験2-Aと比べるとかなり高速化がはかられたかと思います。キャッシュのこのような使い方は、かなり有効だとうことが解るかと思います。繰り返しになりますが、ADPならお手軽にキャッシュ機能を使うことができます。

実験3 ADP側でjoin(事前にマップ作成)

ちなみに、ADPでも事前にマップを作成し、joinを行うことができます。
以下、コード例です。

,$db = "DSN=Trade"
,@tbl = {}
,sql($db, "SELECT CODE,NAME FROM Company",[], @r)
 ,@tbl = @tbl + [ $r["CODE"] | $r["NAME"] ]
 ,next
,sql($db, "SELECT CODE,RDATE,OPEN,CLOSE FROM Price",[],@rec)
 ,$key == $rec["CODE"].str
 ,csv($rec,$tbl[$key]).printn,next;

 
前回の記事ではC++でハッシュjoinを行うと書いたので『ハッシュJOINを言語で再開発するのは非効率』とコメントをもらいました。
コードを良く読んで頂ければ解るかと思いますが、実はC++の例でもjoin自体はプログラミング言語(ライブラリ)の機能を使っており、取り立てて複雑なことはしていません。 
やっていることを説明しますと、マスターテーブル用のマップを事前に作成し、それを使ってjoinを行っています。慣れていない人にとっては難しいかもしれませんが、古くはperlの連想記憶、最近(これも古いが)の例ではVBScriptのディクショナリに相当します。DBMSを使わないで日常的にファイル処理を行っている方にとっては日常的なコードかと思います。
 
ちなみに、ADPのコード例ですが非常にすっきりとしているかと思います。C++の例と比べると本来やろうとしていることが明確になっているかと思います。
実行時間は、
 

D:\>adp -t sql_test_3.p > test3.txt
time is 110988ms.

 
で、約111秒とやはり実験1より速くなっていることが解ります。
こうしてみると、実験2-Bが思いのほか速くなっていないと思わるでしょう。
これはSQLの実行回数に関係しています。
 
各実験のSQLの実行回数を見てみましょう。

SQLの実行回数
実験1 1回
実験2-A 約470万回(Priceテーブルの行数+1)
実験2-B 約2000回(Companyテーブルの行数+1)
実験3 2回

 
になります。実験2のコードではテーブルの行数に比例した数だけSQLを実行することになります。実験2-Bが実験2-Aより速いのは、Priceテーブルの行数よりComapnyテーブルの行数が圧倒的に少ないから、つまり1対nの結合を行っているからで、仮に1対1の結合では速くならないということになります。
 
実験3がなぜ実験1より速いかですが、DBMS側から転送されるデータ量が違います。
以下、CSVファイルの先頭5行を表示します。
 

1717,2005-05-10 00:00:00.000,21251,3522,明豊ファシリティワークス(株)
1717,2005-05-11 00:00:00.000,21251,3522,明豊ファシリティワークス(株)
1717,2005-05-12 00:00:00.000,21251,3522,明豊ファシリティワークス(株)
1717,2005-05-13 00:00:00.000,21251,3522,明豊ファシリティワークス(株)
1717,2005-05-16 00:00:00.000,21251,3522,明豊ファシリティワークス(株)

 
企業名の『明豊ファシリティワークス(株)』が重複して余分なデータとなっています。実験1のコードではDBMSから言語側にこのように重複したデータが来ます。各実験で転送されるデータ量を見てみましょう。
 

結果データの転送量(CSVファイルベース)
実験1 約256MB
実験2-A 約256MB
実験2-B 約184MB
実験3 約184MB

 
実は、DBMSから言語側へ転送されるデータ量自体は、実験1より実験2-Bの方が少なくなります。そのような関係で、実験1より実験2の方が早くなっています。SQLの実行回数(実験1の方がよい)とデータ転送量(実験2の方がよい)になりますが、このあたりはハードウェアの環境やDBMSによって結果が変わってくるでしょう。
この2つのデータから実験3は、なるべく少ないSQLの実行回数で少ないデータ量を転送しているということが解るかと思います。

追記:コメント欄での指摘およびテスト再現性を考慮してテスト環境を整備して再度計測しています。

[ADP開発日誌]Ver0.60アルファ版のリリース(フィボナッチ数例を求めるプログラムの実行速度の改善)

バージョンが0.5Xから0.6に変わりましたが、機能的には特に変わりません。
前回のリリースから継続的に実行性能の強化をしてまして、だいぶ速くなったので一旦リリースします。
 
どこまで速くなったかですが、ADP 0.60と各ブラウザとのフィボナッチ数列を求めるプログラムの実行時間の比較を行います。
ちなみに、JavaScriptのコードですが、こちらにあるコードを使わせていただきました。
ADP側のコードは、以下のとおりです(高速化のためには元のソースも変更する必要がありましたので前とは若干変わっています)。

+fib(0,0),!;
+fib(1,1),!;
+fib($x,$y),fib($x - 1, $f1),fib($x - 2, $f2), $y == $f1 + $f2, !;
,fib(28).printn;

 
◆マシン
・CPU  Core i7-980X
・メモリ 24GB(DDR3-1066 4GB × 6)
・OS   Windows 7 Ulitimate (x64)
 
◆結果

28のフィボナッチ数列を求める時間
IE8(64ビット版) 368ミリ秒
FireFox 3.6.13 167ミリ秒
Google Chrome 8.0.552.224 9ミリ秒
ADP 0.60 226ミリ秒

 
ADP 0.60の結果ですが、IE8以上、FireFox3.6未満という結果になりました。個人的にはまだまだ不満足ですが、競争が激しくなったブラウザのJavaScriptとそう遜色がない結果になっているのでひとまず納得しておきます。
またGoogle Chromeの結果が突出していますが、これはJITコンパイラが利いているかと思います。この手のベンチマークの結果を誤解してほしくないので書いておきますとどんなプログラムも常にGoogle Chromeが突出して速いと言っているわけではござませんので結果を丸々鵜呑みにしないように注意してください
(実際の体感速度は皆様が使ってみて判断してください・・・)。

で、ここまでくると
『いったいどこまで速くなるのか?』
と疑問に思われるでしょう。というわけで、アセンブラ(正確にはインラインアセンブラ)のコードと実行結果を載せます。

#include <iostream>
using namespace std;

#if 0
int __fastcall fib(int f)
{
	if ( f == 0 ) return f;
	if ( f == 1 ) return f;
	return fib(f-1) + fib(f-2);
}
#else
extern "C" {
int __declspec(naked) __fastcall fib(int f)
{
	__asm push	esi
	__asm mov	eax, ecx
	__asm cmp	ecx, 0
	__asm je	_return
	__asm cmp	ecx, 1
	__asm je	_return
	__asm dec	ecx
	__asm call  fib
	__asm mov   esi, eax
	__asm dec	ecx
	__asm call	fib
	__asm add	eax, esi
	__asm add	ecx, 2
_return:
	__asm pop	esi
	__asm ret
}
}
#endif

int main(int argc, _TCHAR* argv[])
{
	clock_t c = clock();
	cout << "fib = " << fib(28) << endl;
	cout << "Execute time is = " << (clock()-c)*1000.0/CLOCKS_PER_SEC << endl;
	return 0;
}

 
プリプロセッサでアセンブラコードが動くようにしていますが、コードはC言語との比較もできるようにCのコードも掲載しています。Visual Studio 2008でコンパイル実行できます。実行時間は4m秒でした。ちなみに、フィボナッチ数例自体を高速に求める方法は他にあります。以前の例のようにADPキャッシュを使えば数ミリ秒になります。ここでは再起関数の呼び出し回数を変えないようにして各プログラミング言語自体が持つ基本的な速度について比較できるようにしています。

[ADP開発日誌]Ver 0.57 アルファ版リリース(性能強化)

キャッシュ機能の用例を書こうかと思っていましたが、前回のリリースからバグやらその他修正したい点がありましたので、修正版をアップしました。
バグフィックスの他に、以下の2点の強化を行っています。
 
■メモリ使用効率の改善(メモリマネージャの追加)
バックトラック時に不要なオブジェクトを解放していますが、多くの場合すぐに同じオブジェクトを使用することになります。このために不要なオブジェクトを直ぐに解放せずにリサイクルするようなメモリマネージャを追加しました。
将来的にはメモリマネージャとキャッシュ機能を連動させ、メモリ不足状態の時はキャッシュで使用しているメモリを解放するという使い方も想定しています。
(現在のバージョンではキャッシュしたメモリはプログラムの終了時まで解放されません)。
 
■パフォーマンスの改善
前回、0.56のリリースで、フィボナッチ数列の値を求めるサンプルを示しましたが、JavaScriptのコードを見つけ、IE8で実行させるとそこそこのスピードで動作しました。キャッシュ機能を使わない生のADPの数値演算の性能がJavaScriptの数値演算の性能に負けているということですが、こりゃいかんということで若干ですがパフォーマンスを改善しています。それでもまだJavaScriptの方が速いのですが、今後もぼちぼち改善していきます。

[ADP開発日誌]Ver 0.56 アルファ版リリース

 前回のリリース告知からはや2ヵ月半が過ぎやっと述語キャッシュ機能を付けました。
キャッシュ機能ですが、同一の関数(述語)の呼び出し(評価)を行う場合に、1回目の呼び出しの結果を保存しておき、2回目の呼び出しでは1回目の呼び出し結果を使います。同一の判定ですが、述語名と引数の値が同じならキャッシュします。変数に関しては、値があればその値が同じか比較し、値がなければ同一とみなします(変数名が違っていてもキャッシュが有効になります)。
なので、printn関数のように副作用がある場合やrand関数のように毎回異なる値になることを期待する述語の場合はキャッシュ機能を使うとバグリます。つまりprintnの場合は2回目の画面出力が行われなくなり、rand関数の場合は同じ値を返して乱数でなくなります。
 
以下、フィボナッチ数例の値を求めるサンプルを例に、使い方を示します。
 
まずはキャッシュなし版のコード(fib1.p)で、

+fib(0,0);
+fib(1,1);
+fib($x,$y),fib($x - 1, $f1),fib($x - 2, $f2), $y == $f 1+ $f2;
,fib(25).printn;

以下、私のマシン(Core i7-920)での実行結果です。

D:>adp -t fib1.p
75025
time is  1538ms.

 
以下、キャッシュあり版のコード(fib2.p)で、

+fib(0,0);
+fib(1,1);
+fib($x,$y),fib$($x - 1, $f1),fib$($x - 2, $f2), $y == $f 1+ $f2;
,fib(25).printn;

以下、私のマシン(Core i7-920)での実行結果です。

D:>adp -t fib2.p
75025
time is     3ms.

 
キャッシュあり版のコードですがぱっとみた感じ違いが解らないかもしれませんが、fib述語を呼び出している部分『fib$($x – 1, $f1)』で、fib$ と述語名の終わりに $ が付いています。つまり、
 述語名の後に $ をつけるとキャッシュ機能が有効になります。
キャッシュあり版となし版で、速度を比較しますとあり版が激速になっていることが分かるかと思います。
fib1.pフィボナッチ数例のコードですが、良く見るコードだと思いますが、このサンプルは実行速度の面で問題があります。2回再帰関数を呼び出しているので実行時間は、入力する値が大きくなると指数関数的に増えて行きます。
fib2.pの例で、キャッシュ機能を使いますと、再帰呼び出しが事実上1回になりますので、入力値が大きくなっても実行時間が指数関数的には増えなくなります。
キャッシュは万能でないので、fib2.pの例では、再帰関数を使う別の問題(大きな数を計算させるとスタックがあふれる)は解決できませんが、ADPのキャッシュ機能を使えば、コードを若干修正するだけでそこそこの性能が得られるので適用対象によっては有効な武器となるでしょう。
(ちなみにですが、フィボナッチ数例を求める実用的なコードではもっと別の実装を選択します。)
 
通常プログラムを高速化したいときですが、プログラマは追い込まれており、出来るだけお手軽にキャッシュ機能をつけたいと思います。また、不具合が出たときに取り外すのも手軽にやりたいと思います。このようなコンセプトの元、
 ADPでは、関数(述語)の呼び出しそのものをキャッシュする機能
としてキャッシュ機能を実装しています。これは、なかなか便利だと思います。

次回は、別の例でキャッシュ機能を紹介します。