toshiki

Rustのenumを64bitの数値に置き換えたら17%速くなった話

· Hacker News #130

Rustのenumが持つタグとパディングの分だけメモリが膨らむ。手書きの64bit表現に置き換えたらインタプリタが17%速くなった実測記録。

  • #rust
  • #performance
  • #interpreter
  • #memory-layout

#なぜ今日これを選んだか

Rustを「文法を覚える言語」として学んでいると、いつまでもJavaScriptの書き方をRustの構文でやっているだけになる。この記事はenumというRustらしい機能を、あえて手で64bitの数値に潰すという逆向きの話で、言語機能の裏側でメモリがどう並んでいるかを考えさせられる。ハードウェアに近づきたいなら、ここが入口になる。

#要点

  • Rustのenumは「どのバリアントか」を示すタグと、最大バリアントに合わせたサイズ+アライメントのパディングを持つため、値そのものより大きくなる
  • インタプリタの値型のように、何百万回もコピー・比較されるものでは、この数バイトの差がキャッシュミスとして効いてくる
  • 64bitの中にタグとペイロードを詰め込む表現(NaN boxing系の発想)に置き換えたところ、実測で17%高速化した
  • 一方で安全性はコンパイラから自分の手に移る。パターンマッチの網羅性チェックを失う代わりの速度である

#自分にとっての示唆

Rustを選んだ理由は「速いから」ではなく、速さの理由を説明できるエンジニアになりたいからだった。#130の先にあるのは外資での勝負で、そこで問われるのは書ける文法の数ではなく、なぜその設計にしたかを英語で説明できるかどうかだ。

明日からの具体的な一手は小さくていい。今日のRust 30分で、自分が書いた型に std::mem::size_of::<T>() を当ててみる。想像していたサイズと実際の値が違ったら、その差がパディングだ。それが分かるだけで、enumに何でも詰め込む書き方が変わる。

そしてこの記事は、最適化を先にやるなという教訓でもある。著者は17%を計測で確かめてから採用している。測らずに速そうな方を選ぶのは、ただの勘だ。