web-dev-qa-db-ja.com

Rustの配列境界チェックはパフォーマンスに影響しますか?

私はC出身ですが、Rustの境界チェックがパフォーマンスに影響するかどうか疑問に思います。おそらく、アクセスごとに追加のAssembly命令が必要になるため、大量のデータを処理するときに問題が発生する可能性があります。

一方、プロセッサのパフォーマンスでコストがかかるのはメモリであるため、算術アセンブラー命令の数が多くても問題はないかもしれませんが、キャッシュラインが読み込まれた後のシーケンシャルアクセスは非常に高速であることが重要です。

誰かがこれをベンチマークしましたか?

16
Jounathaen

残念ながら、境界チェックのコストは簡単に見積もることができません。それは確かに「チェックごとに1サイクル」ではなく、コストを推測するのも簡単ではありません。それは影響がゼロですが、影響は重要ではありません

理論的には、Rustを変更して無効にし、大規模なエコシステムテストを実行することで、Vecのような基本タイプの境界チェックのコストを測定することができます。これにより、ある種の経験則を示しますが、これを行わないと、これがオーバーヘッドの10%と10%のどちらに近いかを知るのは非常に困難です。

ただし、タイミングや推測よりも優れた方法がいくつかあります。これらの経験則は、主にデスクトップクラスのハードウェアに適用されます。ローエンドのハードウェアまたは異なるニッチを対象とするものは、異なる特性を持っています。

インデックスがコンテナーサイズから派生している場合コンパイラーが境界を排除できる可能性は十分にあります完全にチェックします。この時点で、リリースビルドでの境界チェックの唯一のコストは、最適化に断続的に干渉することです(これはできませんでしたが、通常は妨げません)。その他の最適化。

コードが分岐している場合、メモリアクセスが重いか最適化が困難であり、チェックする境界が簡単にアクセスできる場合境界チェックがCPUの予備の帯域幅で発生する可能性が高い、特に分岐予測が役立ちます。この場合、特に残りのコードのコストと比較して、全体的なコストは特に小さくなります。

チェックする境界がポインターのいくつかのレイヤーの背後にある場合メモリレイテンシの問題が発生するのはもっともらしいです。それに応じて苦しむでしょう。ただし、CPUの投機および予測機構がこれをなんとか隠してしまうことも考えられます。これは非常に状況に依存します。境界チェックと同時にデータを逆参照するのではなく、内部のデータを参照している場合、このリスクは拡大します。

境界チェックがコアを飽和させないタイトな算術ループにある場合他のコンパイラの最適化を妨げない限り、スループットを直接損なう可能性はほとんどありません。ただし、他のコンパイラーの最適化を妨げることは、違いがないことからSIMDを防ぎ、ファクター10のスローダウンを引き起こすことまで、任意に悪い場合があります。

境界チェックがを実行するタイトな算術ループ内にある場合コアが飽和します上記のリスクおよびは、境界チェックごとに約半分のサイクルの直接実行ペナルティがあります。

コードが命令キャッシュに負荷をかけるのに十分な大きさの場合次に、コードサイズへの影響を心配する必要があります。これは通常は控えめですが、実行時の影響を測定することは特に困難です。

Peter Cordesはコメントにいくつかのポイントを追加しています。まず、境界チェックはロードとストアを意味するため、問題/名前の変更でボトルネックになる可能性が最も高い混合ロードを実行します。第2に、並列に実行される予測された分岐でさえ、予測子からリソースを取得するため、他の分岐が予測を悪化させる可能性があります。

これは恐ろしいように見えるかもしれませんが、そうです。そのため、自分と自分のコードに関連するレベルでパフォーマンスを測定して理解することが重要です。

Rustは境界チェックで「生まれた」ので、普及したゼロコスト参照、イテレータ(吸収するが、実行しない)などのコストを削減する手段を生み出したtは実際に削除し、境界チェックを行います)、Niceユーティリティ関数の異常なセットです。病理学的なケースに遭遇した場合、Rustも安全でないエスケープハッチを提供します。

34
Veedrac