昔のプログラムをコンパイルしなおそうとしてハマったお話。
きっかけはメインPCの突然の故障。こんなタイミングでPCを買い替える羽目になった。新しいマシンは第11世代のCorei 7搭載。
そうだな、ベンチマークでもするか。... とはいえ、グラボではなくCPU内蔵のグラフィクスなので、FF14とかのゲームのベンチは意味ないし、そうだ円周率でも計算してみるか。ということで、昔書いたプログラムを発掘して試した。
100万桁が、2秒。 ... あれ? そんなもん? それにCPUの使用率がえらく低いし...
あぁ、そういえばこれ32bitコードだったっけ。20年前に書いたプログラムだものなぁ。当時はOSも32bit OSだし。CPUのコアは一つしか考えられなかった。
まずは、開発環境としてVisual Studio 2019 と Intelの oneAPI Toolkits をダウンロードしてインストール。
# あの頃は、Visual Studioも intelのコンパイラーも大枚はたいて買ったっけ。まったく良い時代になったものだ。
Visual Studioで作ったCUIのプログラムなので、リビルド一発かと思いきやコンパイルエラーが... 曰く、iostream.h なんてありません、cout ってなんですかぁ。.... そういえば、昔は名前空間なんてなかったよな。ということで言語の進化にまず躓く。まあ、機械的な修正で済むけど。
で、ビルドはできたけど、これはまだターゲットがx86のままの場合。で、ターゲットをx64に変更してリビルドをかけたら、またもやコンパイルエラー。曰く、インラインアセンブラは使えません! うぅぅむ。
C++での実装もコメントで残してあったので、そちらに切り替えてビルドする。結果は、100万桁が 3秒. 遅いぞ。
さてどうしたものかと、ググって対策を検討。インラインではなく、別ファイルに切り出した純粋のアセンブラコードにするという手もある様だが、組み込み関数 intrin.h を選択。やはりコンパイラーに最適化を頑張って欲しいし。
ということで、今度は 100万桁が 1秒。 ( 計測値が秒単位で荒いのは difftime( ) で値を出しているから。)
で、.... ここでめげた。 このプログラム、データのキャッシュを利かせるために再帰をループに換えていたり、小さなループを手で展開したり、といった細かい細工を積み重ねてできているのでコードがむちゃ汚い。
マルチコアとかSIMDといった現代のアーキテクチャを活かすように書き換えるなら、チューニングする前のアルゴリズムに忠実な実装を発掘しないとちょっとつらい。
ということで、Visual Studio で作ったCUIのプログラムだからリビルドは造作もないだろうと思いきや、しっかりハマったというお話でした。