この年末、年始で、我が社のデスクトップPCが、ほぼWindows7へ移行した。
あわせて、
以前の記事で言っていました私のセカンドノートもWin7のネットブックへ移行しました(その記事は後ほどまた書きます)。
後はサーバーをWin2008R2へすれば、我が社のパソコンがWin7系に移行するのですが、ここまでのOSのマイグレーションは我が社始まって以来かもしれない。
とまぁ大がかりな移行を行っているのですが、ご多分にもれず我が社もVista飛ばしを行ってWin7へ移行したのですが、そのせいかもう歳なのか何なのかわからないのだが、Win7のデスクトップに慣れるまで時間がかかっていた。私がWin7を使いだしてから1年が経つので移行計画も1年越しということになる。
ただ、同い年の我が社の社長があっさりと使いこなしているところを見て年明け早々、自分の適用力が落ちたことにショックを受けたりしてます。
バージョンが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キャッシュを使えば数ミリ秒になります。ここでは再起関数の呼び出し回数を変えないようにして各プログラミング言語自体が持つ基本的な速度について比較できるようにしています。
あけましておめでとうございます。
今年はウサギ年で飛躍の年ということで不況から脱出するとよいですね(と同時に私の株も上がって欲しい・・・)。
去年の年末から失速感のあるブログですが、心新たにぼちぼち更新します。
いろいろネタには尽きないはずなのですが、一発目はどうしてもこれを書きたいので、書きます。
一つ目の看板は、これです。

電話がまだ普及していなかった頃のものでしょうが、子供の頃にみたことがあるくらいでお世話になったことはありません。
二つ目は、これです。

こちらは、子供のころにも見たことがありません。専売公社の頃の看板でしょうが塩って私が子供の頃(30年程前)から普通にスーパーで売っていた記憶があります。字も旧字体なのでもっと前のものでしょう。
ちなみに、この2つの看板は我が家の近くの同じ建物(店)にあったのですが、ここに引っ越してきて5年半になりますが、まったく気がつきませんでした・・・。もっともそのお店と思われるところが開いているところもみたことがないので、だいぶ前から閉まったままだと思います。まぁよく今まで残っていたものだと思います。
キャッシュ機能の用例を書こうかと思っていましたが、前回のリリースからバグやらその他修正したい点がありましたので、修正版をアップしました。
バグフィックスの他に、以下の2点の強化を行っています。
■メモリ使用効率の改善(メモリマネージャの追加)
バックトラック時に不要なオブジェクトを解放していますが、多くの場合すぐに同じオブジェクトを使用することになります。このために不要なオブジェクトを直ぐに解放せずにリサイクルするようなメモリマネージャを追加しました。
将来的にはメモリマネージャとキャッシュ機能を連動させ、メモリ不足状態の時はキャッシュで使用しているメモリを解放するという使い方も想定しています。
(現在のバージョンではキャッシュしたメモリはプログラムの終了時まで解放されません)。
■パフォーマンスの改善
前回、0.56のリリースで、フィボナッチ数列の値を求めるサンプルを示しましたが、JavaScriptのコードを見つけ、IE8で実行させるとそこそこのスピードで動作しました。キャッシュ機能を使わない生のADPの数値演算の性能がJavaScriptの数値演算の性能に負けているということですが、こりゃいかんということで若干ですがパフォーマンスを改善しています。それでもまだJavaScriptの方が速いのですが、今後もぼちぼち改善していきます。
前回のリリース告知からはや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では、関数(述語)の呼び出しそのものをキャッシュする機能
としてキャッシュ機能を実装しています。これは、なかなか便利だと思います。
次回は、別の例でキャッシュ機能を紹介します。