Rustのenumを64bitの数値に置き換えたら17%速くなった話
Rustのenumが持つタグとパディングの分だけメモリが膨らむ。手書きの64bit表現に置き換えたらインタプリタが17%速くなった実測記録。
#なぜ今日これを選んだか
Rustを「文法を覚える言語」として学んでいると、いつまでもJavaScriptの書き方をRustの構文でやっているだけになる。この記事はenumというRustらしい機能を、あえて手で64bitの数値に潰すという逆向きの話で、言語機能の裏側でメモリがどう並んでいるかを考えさせられる。ハードウェアに近づきたいなら、ここが入口になる。
#要点
- Rustのenumは「どのバリアントか」を示すタグと、最大バリアントに合わせたサイズ+アライメントのパディングを持つため、値そのものより大きくなる
- インタプリタの値型のように、何百万回もコピー・比較されるものでは、この数バイトの差がキャッシュミスとして効いてくる
- 64bitの中にタグとペイロードを詰め込む表現(NaN boxing系の発想)に置き換えたところ、実測で17%高速化した
- 一方で安全性はコンパイラから自分の手に移る。パターンマッチの網羅性チェックを失う代わりの速度である
#自分にとっての示唆
Rustを選んだ理由は「速いから」ではなく、速さの理由を説明できるエンジニアになりたいからだった。#130の先にあるのは外資での勝負で、そこで問われるのは書ける文法の数ではなく、なぜその設計にしたかを英語で説明できるかどうかだ。
明日からの具体的な一手は小さくていい。今日のRust 30分で、自分が書いた型に std::mem::size_of::<T>() を当ててみる。想像していたサイズと実際の値が違ったら、その差がパディングだ。それが分かるだけで、enumに何でも詰め込む書き方が変わる。
そしてこの記事は、最適化を先にやるなという教訓でもある。著者は17%を計測で確かめてから採用している。測らずに速そうな方を選ぶのは、ただの勘だ。