C言語で書いた世界のナベアツに実行速度で勝った話

何があったか

過去に書いた『世界のナベアツをnasmアセンブリで実装してやろう』という記事があったのですが、そこで書いたコードには大きな問題がありました。 akakou.hatenablog.com github.com ※リンク先は最新のコミットです

なんと実行速度が…

C言語で書いたサンプル(-O9で最適化)

real   0m3.794s
user    0m0.591s
sys 0m1.679s

それに対してnasmで書いた方は

real   0m4.459s
user    0m0.508s
sys 0m1.716s

f:id:akakou:20180107174418p:plain

ということがあったんです… 流石に諦めがつかず…

もう一戦して見ました!

改めてルール

  • 1~1000000までの数字をカウントし、標準出力として表示すること。
  • カウントする際は、毎回改行すること。
  • カウントした数が3で割り切れる数または3のつく数なら、任意別の文字列も表示すること。
  • この文字列が毎回一致すること。

勝つためにどうしたか

  • 極力クロックサイクルの小さそうな命令を(偏見で)選ぶようにした。
    • ビット演算、シフト演算
    • インクリメント、デクリメント
  • メモリアクセスは避けた。
    • 極力レジスタだけでうまく回す。
    • 今回メモリアクセスは文字列格納のところだけなはず。
  • ライブラリ関数(printfというチート)を使うのをやめた。
    • システムコール直接投げ込もう。
    • フォーマット指定ができないので、カウント用のレジスタBCDでのカウント用のレジスタでカウントさせて、表示の際にはBCDの方から1桁取り出して0x30を足すという処理を回して実装した。
  • 祈った。
    • 神頼み大切()。

結果

C言語のサンプル

real   0m4.080s
user    0m0.633s
sys 0m1.856s

nasmのナベアツ

real   0m3.575s
user    0m0.239s
sys 0m1.613s

f:id:akakou:20180107180049p:plain

念願の勝利でした!やったね。

まとめ&感想

  • 途中でmovするレジスタの大きさ間違えて、気づかずにめちゃくちゃ苦しい思いをした。
    • 後にQiitaあたりに載せるかもしれない。
  • しばらくアセンブリ書きたくない。
  • すごい生産性のない時間を過ごした気がする。
    • 多分気がするだけではないのだろう。
  • 正直おすすめはしません!