ソフトウェア業界のコンセンサスは、クリーンでシンプルなコードが、コードベースとそれを所有する組織の長期的な存続可能性の基本であるということです。これらのプロパティにより、メンテナンスコストが削減され、コードベースが継続される可能性が高まります。
ただし、SIMDコードは一般的なアプリケーションコードとは異なり、特にSIMDコードに適用されるクリーンでシンプルなコードに関して同様のコンセンサスがあるかどうかを知りたいです。
質問の背景。
さまざまな画像処理および分析タスクのために、SIMD(単一命令、複数データ)コードをたくさん書いています。最近、これらの機能のいくつかを、あるアーキテクチャ(SSE2)から別のアーキテクチャ(ARM NEON)に移植する必要もありました。
コードはシュリンクラップされたソフトウェア用に記述されているため、MATLABなどの無制限の再配布権がない限り、独自の言語に依存することはできません。
典型的なコード構造の例:
Mat
) を使用して、すべてのメモリ、バッファ、およびライフタイムを管理します。SIMDプログラミングのどの側面が、一般的なケースとは異なる議論を引き起こしますか?または、なぜSIMDが異なるのですか?
初期開発コストに関して
傾向に関して
(例: パレート原理、別名80-20ルール )
読みやすさとメンテナンスの観点から
SIMDコードは、明らかに読みにくいです。
最適なSIMDコードは、同等のC++プロトタイプコードと比較して、(備考を参照)と非常に歪んでいます。
(備考)
これは MIT Halideプロジェクト -の主要な論文であり、論文のタイトルを逐語的に引用します:
「スケジュールからアルゴリズムを分離して、画像処理パイプラインを簡単に最適化する」
前方適用可能性の観点から
vtbl
をvtblq
で置き換えます)が、一部のコードのコンパイルが失敗するのに十分です。スキルとトレーニングに関して
正確性および欠陥に関連するコストに関して
破壊的イノベーションの観点から
アカデミアから多くのソリューションが提案されていますが、商業的に広く使用されているソリューションはほとんどありません。
商用利用が広まっているライブラリは、SIMDにあまり対応していないようです。
このプログラマーの質問: 低レイテンシコードは時々「醜い」でなければならないのですか? は関連していて、私は以前、その質問に対する回答を書いて、数年前の私の見解を説明しました。
ただし、その答えは、「時期尚早の最適化」の観点、つまり次のような観点に対するかなりの「緩和」です。
しかし、このような見方は、この ACM記事 で論争されています。
そのすべてが私に尋ねるように導きます:
SIMDコードは一般的なアプリケーションコードとは異なります。SIMDコードのクリーンでシンプルなコードの価値に関して同様の業界コンセンサスがあるかどうか知りたいのですが。
自分でSIMDコードを書くことはあまりありませんでしたが、数十年前にたくさんのアセンブラコードを書きました。 SIMD組み込み関数を使用するAFAIKは基本的にアセンブラープログラミングであり、「SIMD」を「アセンブリ」という単語に置き換えるだけで、質問全体を言い換えることができます。たとえば、あなたがすでに述べた点、
「高レベルのコード」よりもコードの開発に10倍から100倍かかります
特定のアーキテクチャに関連付けられている
コードが「クリーン」でもリファクタリングも簡単ではない
あなたはそれを書いて維持するための専門家を必要としています
デバッグと保守は難しく、進化は本当に難しい
sIMDにとって「特別」なわけではありません。これらの点はあらゆる種類のアセンブリ言語に当てはまり、それらはすべて「業界のコンセンサス」です。また、ソフトウェア業界の結論もアセンブラの場合とほとんど同じです。
必要がない場合は記述しないでください-可能な限り高水準言語を使用し、コンパイラにハードワークを任せます
コンパイラが十分でない場合は、少なくとも一部のライブラリに「低レベル」の部分をカプセル化しますが、プログラム全体にコードを分散することは避けてください
「自己文書化」アセンブラーまたはSIMDコードを作成することはほとんど不可能であるため、多くの文書でこれをバランスよく試してください。
もちろん、確かに「クラシックな」アセンブリまたはマシンコードの場合とは状況が異なります。今日、現代のコンパイラは通常、高水準言語から高品質のマシンコードを生成します。これは、手動で記述されたアセンブラコードよりも多くの場合最適化されています。現在人気のあるSIMDアーキテクチャーの場合、使用可能なコンパイラーの品質はAFAIKをはるかに下回っています。自動ベクトル化はまだ科学的研究のテーマであるため、到達することはおそらくありません。たとえば、コンパイラと人間の間の最適化の違いを説明する この記事 を参照してください。良いSIMDコンパイラを作成するのは非常に難しいかもしれないという考えを与えます。
あなたの質問ですでに説明したように、現在の最先端のライブラリには品質の問題もあります。だから私たちが期待できる最高のことは、今後数年でコンパイラとライブラリの品質が向上し、SIMDハードウェアがより「コンパイラフレンドリー」になるために変更しなければならないこと、多分簡単なベクトル化をサポートする専用のプログラミング言語(Halideなど)あなたは2度言及しました)より人気があります(それはすでにFortranの強みではありませんでしたか?)。 Wikipedia によると、SIMDは約15〜20年前に "大量生産品"になりました(ドキュメントを正しく解釈すると、Halideは3年未満です)。これを、成熟するために必要な「古典的な」アセンブリ言語のコンパイラと比較してください。 このWikipediaの記事 によると、コンパイラーが(非並列マシンコードの生成において)人間の専門家のパフォーマンスを超えるまで、約30年(〜1970年から1990年代の終わりまで)かかりました。したがって、SIMD対応のコンパイラに同じことが起こるまで、さらに10〜15年待つ必要があるかもしれません。
私の組織はこの正確な問題に対処しました。私たちの製品はビデオ分野にありますが、私たちが作成するコードの多くは、静止画像でも機能する画像処理です。
独自のコンパイラを作成することで、問題を「解決」しました(またはおそらく「対処する」)。これは、最初に聞こえるほどクレイジーではありません。入力の制限されたセットがあります。すべてのコードが画像、主にRGBA画像で機能していることはわかっています。入力バッファーと出力バッファーが重複しないように、ポインターのエイリアスが発生しないように、いくつかの制約を設定します。そういうもの。
次に、OpenGLシェーディング言語(glsl)でコードを記述します。スカラーコード、SSE、SSE2、SSE3、AVX、Neon、そしてもちろん実際のglslにコンパイルされます。新しいプラットフォームをサポートする必要がある場合は、そのプラットフォームのコードを出力するようにコンパイラを更新します。
また、画像のタイリングを行って、キャッシュの一貫性などを改善しています。しかし、画像処理を小さなカーネルに保ち、glsl(これはポインターもサポートしていません)を使用することで、コードのコンパイルの複雑さを大幅に軽減します。
このアプローチはすべての人に適しているわけではなく、独自の問題があります(たとえば、コンパイラーの正確さを確認する必要があります)。しかし、それは私たちにとってかなりうまくいきました。
より高水準の言語を使用することを検討しても、メンテナンスのオーバーヘッドがあまり増えないようです。
Vector<float> values = GetValues();
Vector<float> increment = GetIncrement();
// Perform addition as a vector operation:
List<float> result = (values + increment).ToList();
対
List<float> values = GetValues();
List<float> increment = GetIncrement();
// Perform addition as a monadic sequence operation:
List<float> result = values.Zip(increment, (v, i) => v + i).ToList();
もちろん、ライブラリの制限に直面する必要がありますが、それを自分で維持することはできません。メンテナンスコストとパフォーマンスの向上のバランスが取れている可能性があります。
http://blogs.msdn.com/b/dotnet/archive/2014/05/13/update-to-simd-support.aspx