「Rust」言語はCよりも遅いのか、研究者がベンチマーク結果を解説:モダンCPUでは性能低下は軽微
ミュンヘン工科大学の研究チームのメンバーはRust言語で開発したネットワークデバイスドライバの処理速度をC言語のものと比較した。その結果、Rust版の速度低下は最大でも数%にとどまっていた。なぜ処理性能がわずかに遅くなるのか、その理由も説明した。
「C」や「C++」に代わるシステムプログラミング言語として「Rust」が注目を集めている。メモリ安全性が高く、メモリ破壊バグといった脆弱(ぜいじゃく)性を作り込みにくいからだ(関連記事)。
ただし、システムプログラミング言語では、高い処理性能が必須条件であり、これがCやC++が使われ続けている理由となっている。Rustはどの程度「速い」のだろうか。
ドイツのミュンヘン工科大学で博士課程の学生であるポール・エメリク氏は2019年9月9日、Rustで作成したデバイスドライバの性能評価をGitHubで発表した。
同氏のグループはさまざまな言語で同じ機能を備えたデバイスドライバを記述し、性能を比較している。
Cで記述したデバイスドライバの処理性能が常に最も高いものの、ある条件を満たすとRustのコード(青)が同じ性能を発揮した(出典:ポール・エメリク氏の「Rust-vs-C-performance.md」)
何が性能低下を引き起こしているのか
性能評価用に作成したのは、Intelのイーサネットコントローラー向けのLinux用デバイスドライバだ(ixgbeタイプ)。
エメリク氏は解説の冒頭で研究に取り組んだ理由をはっきりと述べている。
「Rust版がC版より遅いのは、当然ながらRustの安全機能に起因する。だが、それを定量化できるのだろうか」
同氏によれば、Rustによる実装とCによる従来型の実装には大きな違いが2つしかないという。
- Rustは(配列へのインデックスアクセス時に)境界チェックを常に強制するが、Cの慣用的なスタイルでは境界チェックが含まれていない
- Cは、DMAバッファーのラッパーオブジェクトを必要とせず、全ての必要なメタデータをパケットデータの前に直接保存する。これはDMAバッファーと同じメモリ領域だ。だが、Rustのラッパーオブジェクトは、スタックに割り当てることができ、Cで使われるポインタをスマートポインタに効果的に置き換え、局所性によって生じるペナルティを軽減する
つまり、境界チェックが、Rustのパフォーマンス上の主なデメリットとなっているという。
CPUパフォーマンスカウンタで評価してみると
エメリク氏はRustが遅くなる理由を調べるため、デバイスドライバ動作時のCPUのパフォーマンスカウンタを調べた。次の表にある数字は言語ごと、パケットをまとめたバッチサイズごとのCPUの処理性能を示している。いずれもCPUのパフォーマンスカウンタを転送速度で割ったもの(イベント/パケット)。つまり、転送速度当たりのCPU性能である。なお、一般にバッチサイズが大きいほどネットワークコントローラーの処理性能は高くなるが、あまりにサイズが大きいとCPUキャッシュを使い切ってしまい、性能が低下する可能性がある。
全体の状況を見ると、Rustの高い処理性能が分かる。Rust版ではC版と比べて、転送パケット当たり65%多くの命令をCPUが実行できた。しかも、バッチサイズが32の場合、パケット当たりのサイクルの数は6%増にとどまっている(バッチサイズが8だと11%多い)。
エメリク氏はこのデータを評価して次のようにまとめている。
「スーパースカラーとアウトオブオーダーを備えたモダンなCPU(研究では『Intel XeonプロセッサーE5-2620 v3』を採用)であれば、Rustの安全チェックによるパフォーマンス上のハンデは隠れてしまう」
その一方で、CのコードはCPUの潜在力をフルに活用できていないという。研究チームが作成したデバイスドライバは、ノーマル実行時に境界チェックに違反しないので、CPUは正確に予測を行い(分岐予測ミス率は0.2〜0.3%)、正しいパスを投機的に実行できるという条件下の成績だからだ。キャッシュも、境界情報の追加的なロードが必要になったときに貢献している。このワークロードでは、L1キャッシュのヒット率は98%を超えている。
整数オーバーフローのチェックはほぼ無関係
Rustに備わっている安全機能は境界チェックだけではない。整数オーバーフローチェックがある(コンパイル時にフラグで明示的に有効にする必要がある)。
そこで、整数オーバーフローチェックによる性能低下についても調査した。バッチサイズが8よりも大きいとき、チェックを有効にしても性能に統計上有意な差は生じなかった。バッチサイズが8であっても、スループットは0.8%しか低下しなかった。
プロファイリングによれば、整数オーバーフローチェックによって、CPUが実行する命令がパケット当たり9個増え、このうち8個は分岐であることが分かった。分岐予測ミスの総数には影響がなく、分岐チェックはCPUによって常に正確に予測されていた。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- Rustコンパイラが「高速化」、Mozillaが比較データを公開
Mozillaは現在に至るまでRustコンパイラが順調に高速化していることを明らかにした。2019年の年初や2017年11月といった過去の時点のコンパイル時間と現在の性能を比較した。 - Microsoftが「Rust」言語を導入、安全性以外の理由あり(続報)
Microsoft Security Response Center(MSRC)は、C/C++に代わるシステムプログラミング言語の最有力の選択肢として「Rust」を挙げ、その理由を解説した。合わせてMicrosoftのような大規模なコードベースを持つ企業にとっての課題も示した。 - Microsoft、安全で高効率のプログラミング言語として「Rust」を高く評価
Microsoft Security Response Center(MSRC)は、ソフトウェアのセキュリティ確保と効率性の両方の要件を満たす最も有望なシステムプログラミング言語の一つとして、「Rust」を高く評価した。メモリ破壊バグをそもそも作り込まないことでセキュリティを確保できるという。