質問:
ソフトウェア業界のコンセンサスは、クリーンでシンプルなコードが、コードベースとそれを所有する組織の長期的な実行可能性の基本であるということです。これらのプロパティにより、メンテナンスコストが削減され、コードベースが継続される可能性が高まります。
ただし、SIMDコードは一般的なアプリケーションコードとは異なります。SIMDコードに特に適用されるクリーンでシンプルなコードに関して、同様のコンセンサスがあるかどうかを知りたいと思います。
私の質問の背景。
さまざまな画像処理および分析タスクのために、たくさんのSIMD(単一命令、複数データ)コードを作成します。最近、これらの関数のいくつかを、あるアーキテクチャ(SSE2)から別のアーキテクチャ(ARM NEON)に移植しなければなりませんでした。
このコードはシュリンクラップされたソフトウェア用に記述されているため、MATLABなどの無制限の再配布権がなければ、独自の言語に依存することはできません。
典型的なコード構造の例:
- 使用のOpenCVのマトリックスタイプ(
Mat
)すべてのメモリのため、緩衝液および寿命管理。 - 入力引数のサイズ(次元)を確認した後、ピクセルの各行の開始アドレスへのポインターが取得されます。
- ピクセルカウント、および各入力マトリックスからのピクセルの各行の開始アドレスは、いくつかの低レベルC ++関数に渡されます。
- これらの低レベルC ++関数は、SIMD組み込み関数(Intel ArchitectureおよびARM NEON用)を使用して、生のポインターアドレスからの読み込みと保存を行います。
- これらの低レベルC ++関数の特徴:
- 排他的に1次元(メモリ内で連続)
- メモリ割り当てを処理しません。
(一時を含むすべての割り当ては、OpenCV機能を使用する外部コードによって処理されます。) - シンボルの名前の長さの範囲(組み込み関数、変数名など)は約10〜20文字で、これは非常に過剰です。
(テクノバブルのように読みます。) - コンパイラは「単一割り当て」コーディングスタイルで記述されていないコードを正しく解析するのに非常にバグがあるため、SIMD変数の再利用は推奨されません。
(私はいくつかのコンパイラのバグレポートを提出しました。)
SIMDプログラミングのどの側面が議論を一般的な場合と異なるものにしますか?または、SIMDが異なるのはなぜですか?
初期開発コストの観点から
- 優れたパフォーマンスを備えたC ++ SIMDコードの初期開発コストは、カジュアルに記述された C ++コードと比較して、約10倍から100倍(マージンは大きい)であることはよく知られています。
- パフォーマンスと読み取り可能/クリーナーコードの選択の回答で述べたように?、ほとんどのコード(カジュアルに記述されたコードとSIMDコードを含む)は、最初はクリーンでも高速でもありません。
- (スカラーコードとSIMDコードの両方での)コードパフォーマンスの進化的な改善は推奨されません(ソフトウェアの一種と見なされるため)。コストと利点は追跡されません。
傾向の観点から
(例えば、パレート原理、別名80-20ルール)
- 画像処理がソフトウェアシステムの20%(コードサイズと機能の両方)のみで構成されている場合でも、画像処理は(CPU時間の割合として見た場合)比較的遅く、80%以上の時間がかかります。
- これは、データサイズの影響によるものです。典型的な画像サイズはメガバイト単位で測定されますが、非画像データの典型的なサイズはキロバイト単位で測定されます。
- 画像処理コード内で、SIMDプログラマーは、C ++コード内のループ構造を識別することにより、ホットスポットを含む20%コードを自動的に認識するように訓練されます。したがって、SIMDプログラマーの観点からは、「重要なコード」の100%がパフォーマンスのボトルネックです。
- 多くの場合、画像処理システムには複数のホットスポットが存在し、同等の割合の時間を消費します。たとえば、5つのホットスポットがそれぞれ合計時間(20%、18%、16%、14%、12%)を占める場合があります。高いパフォーマンスを実現するには、すべてのホットスポットをSIMDで書き換える必要があります。
- これは、バルーンをポップするルールとして要約されています。バルーンを2回ポップすることはできません。
- バルーンがいくつかあると仮定します。たとえば、そのうち5つです。それらを間引く唯一の方法は、それらを1つずつポップすることです。
- 最初のバルーンがポップされると、残りの4つのバルーンの合計実行時間の割合が高くなります。
- さらに利益を上げるには、別のバルーンをポップする必要があります。
(これは、最適化の80-20ルールに反します:ぶら下がりが最も少ない果物の20%が選ばれた後、良好な経済的結果を達成できます。)
読みやすさとメンテナンスの面で
SIMDコードは、明らかに読みにくいです。
- これは、すべてのソフトウェアエンジニアリングのベストプラクティス(ネーミング、カプセル化、const-correctness(および副作用の明確化)、関数の分解など)に従っても当てはまります。
- これは、経験のあるSIMDプログラマーにも当てはまります。
最適なSIMDコードは、同等のC ++プロトタイプコードと比較して、非常にゆがんでいます(注意を参照)。
- SIMDコードをゆがめる方法は数多くありますが、10回の試行のうち1回だけで許容可能な高速の結果が得られます。
- (つまり、高い開発コストを正当化するために、4倍から10倍のパフォーマンスゲインを調整します。実際には、さらに高いゲインが観察されています。)
(注釈)
これは MIT Halideプロジェクトの主要な論文です-論文のタイトルを逐語的に引用します:
「アルゴリズムをスケジュールから分離して、画像処理パイプラインを簡単に最適化する」
順応性の観点から
- SIMDコードは、単一のアーキテクチャに厳密に結び付けられています。新しいアーキテクチャ(またはSIMDレジスタの拡張)ごとに書き換えが必要です。
- ソフトウェア開発の大部分とは異なり、SIMDコードの各部分は通常、変更されない単一の目的のために作成されます。
(他のアーキテクチャへの移植を除きます。) - 一部のアーキテクチャは、完全な下位互換性を維持しています(Intel)。些細な量(ARM AArch64、置き換えることにより、いくつかの秋の短い
vtbl
とvtblq
)が、十分であり、いくつかのコードがコンパイルに失敗する原因になります。
スキルとトレーニングの観点から
- 新しいプログラマを適切にトレーニングしてSIMDコードを記述および保守するために必要な知識の前提条件は明らかではありません。
- 学校でSIMDプログラミングを学んだ大卒者は、それを非現実的なキャリアトラックとして軽deし、却下しているようです。
- 分解読み取りと低レベルのパフォーマンスプロファイリングは、高性能のSIMDコードを記述するための2つの基本的なスキルとして引用されています。しかし、プログラマーにこれら2つのスキルを体系的にトレーニングする方法は不明です。
- 最新のCPUアーキテクチャ(教科書で教えられているものとは大きく異なる)は、トレーニングをさらに困難にします。
正確性および欠陥関連コストの観点から
- 単一のSIMD処理関数は実際には十分に凝集性があるため、次の方法で正確性を確立できます。
- 正式な方法の適用(ペンと紙を使用)、および
- 出力プロトタイプ範囲の検証(プロトタイプコードを使用し、ランタイム外で実行)。
- ただし、検証プロセスは非常にコストがかかり(コードレビューに100%時間、プロトタイプモデルのチェックに100%時間を費やします)、SIMDコードの既に高価な開発コストを3倍にします。
- バグが何らかの形でこの検証プロセスをすり抜けた場合、疑わしい欠陥機能を置き換える(書き換える)ことを除いて、「修復」(修正)することはほぼ不可能です。
- SIMDコードは、C ++コンパイラー(コードジェネレーターの最適化)の欠陥の鈍さに苦しんでいます。
- C ++ 式テンプレートを使用して生成されたSIMDコードも、コンパイラの欠陥に大きく悩まされます。
破壊的イノベーションの観点から
学界から多くの解決策が提案されていますが、商業的に広く使用されているものはほとんどありません。
- MITハライド
- スタンフォードダークルーム
- NT2(数値テンプレートツールボックス)および関連するBoost.SIMD
商用利用が普及しているライブラリは、SIMDにあまり対応していないようです。
- オープンソースのライブラリは、SIMDには温かくないようです。
- 最近、バージョン2.4.9の時点で、多数のOpenCV API関数をプロファイリングした後、これを直接観察しました。
- 私がプロファイリングした他の多くの画像処理ライブラリも、SIMDを多用しないか、真のホットスポットを見逃しています。
- 商用ライブラリは、SIMDを完全に回避しているようです。
- いくつかのケースでは、画像処理ライブラリが以前のバージョンのSIMD最適化コードを後のバージョンの非SIMDコードに戻し、深刻なパフォーマンスの低下を引き起こすことさえ見ました。
(ベンダーの応答は、コンパイラのバグを回避する必要があったということです。)
- いくつかのケースでは、画像処理ライブラリが以前のバージョンのSIMD最適化コードを後のバージョンの非SIMDコードに戻し、深刻なパフォーマンスの低下を引き起こすことさえ見ました。
- オープンソースのライブラリは、SIMDには温かくないようです。
このプログラマーの質問: 低レイテンシーのコードは時々「ugい」必要がありますか? に関連しており、数年前に私の視点を説明するために以前にその質問への回答を書きました。
ただし、その答えは、「時期尚早な最適化」の観点、つまり次の観点に対する「緩和」です。
- すべての最適化は定義により時期尚早です(または、性質により短期的です)。
- 長期的なメリットがある唯一の最適化は、単純化に向けたものです。
SIMDコードは一般的なアプリケーションコードとは異なります。SIMDコードのクリーンでシンプルなコードの価値に関して、同様の業界コンセンサスがあるかどうかを知りたいと思います。