問題タブ [fma]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
floating-point - 浮動小数点計算による浮動小数点から 10 進数への変換
浮動小数点の倍精度値x
を 12 (正しく丸められた) 有効数字の 10 進数に変換しようとしています。x
10 ^ 110 と 10 ^ 111 の間にあり、10 進表現が の形式になると想定していx.xxxxxxxxxxxE110
ます。そして、楽しみのために、浮動小数点演算のみを使用しようとしています。
すべての演算が倍精度演算である以下の疑似コードにたどり着きました。表記1e98
は、数学的な 10^98 に1e98_2
最も近い double であり、数学的な減算 10^98- の結果に最も近い double1e98
です。表記は、オペランド、、fmadd(X * Y + Z)
を使用した融合乗算加算演算用です。X
Y
Z
上記の疑似コードに混乱が広がっていることをお詫びしますが、まだあまり明確ではないため、次の質問があります。
最初の fmadd は (1e98 * (除算中に発生したエラー) を計算するために) 意図したとおりに機能しますか?
しるし。彼らが正しいと自分に言い聞かせることはできません。しかし、私は彼らが間違っていると自分自身に納得させることもできません.
このアルゴリズムが間違った結果を生成する可能性がある頻度についての考え、おそらく議論はありますか?
まったく機能する場合、「q = y / 1e98」を「q = y * 1e-98」に変更しても(他のすべての命令は同じままにして)、アルゴリズムが引き続き機能する可能性はありますか?
このアルゴリズムはテストしていません。fmadd命令を備えたコンピューターはありませんが、上記を実行できるコンピューターを見つけたいと思っています。
c++ - GCC で AVX を使用する: __builtin_ia32_addpd256 が宣言されていません
#include <immintrin.h>
このエラーが発生した場合:
エラー: '__builtin_ia32_addpd256' はこのスコープで宣言されていません
AVX を利用可能にするマクロを定義__AVX__
しましたが、明らかにこれだけでは不十分です。マクロの代わりに__FMA__
コンパイラ フラグを使用してもエラーは発生しませんが、その解決策は受け入れられません。-mavx
では、AVX を使用するには他に何を定義すればよいでしょうか?
c++ - GCC での FMA3: 有効にする方法
AVX2 と FMA3 を搭載した i5-4250U を持っています。私が書いたLinux上のGCC 4.8.1でいくつかの密な行列乗算コードをテストしています。以下は、私がコンパイルする 3 つの異なる方法のリストです。
SSE2版とAVX版は明らかに性能が違います。ただし、AVX2+FMA は AVX バージョンより優れているわけではありません。私はこれを理解していません。FMA がないと仮定すると、CPU のピーク フロップの 80% を超える値を取得できますが、FMA を使用するとさらに改善できるはずです。行列乗算は、FMA から直接恩恵を受けるはずです。私は基本的に、AVX で一度に 8 つのドット積を実行しています。チェックすると、次のmarch=native
ようになります。
したがって、有効になっていることがわかります(追加し-mfma
たことを確認するためですが、違いはありません)。 ffast-math
緩和された浮動小数点モデルを許可する必要がありますSSE/AVX で融合積和 (FMA) 命令を使用する方法
編集:
Mysticial のコメントに基づいて、_mm256_fmadd_ps を使用したところ、AVX2+FMA バージョンの方が高速になりました。 なぜコンパイラがこれをしないのかわかりません。 現在、1000x1000 を超える行列で約 80 GFLOPS (FMA を使用しない場合のピーク フロップの 110%) を取得しています。誰かが私のピーク フロップ計算を信用しない場合のために、ここで私が行ったことを示します。
両方のコアを使用するときのターボ モードの CPU は 2.3 GHz です。Ivy Bridge は 1 つの AVX 乗算と 1 つの AVX 加算を同時に実行できるため、ILP は 2 になります (これを確実にするためにループを数回展開しました)。
ピーク フロップの約 55% しか得られません (FMA を使用)。理由はわかりませんが、少なくとも今は何かが見えています。
副作用の 1 つは、信頼できるとわかっている単純な行列乗算アルゴリズムと比較すると、小さなエラーが発生するようになったことです。これは、FMA の丸めモードが通常は 2 つではなく 1 つしかないためだと思います (皮肉なことに、IEEE の浮動小数点の規則に違反している可能性があります)。
編集:
誰かがやり直す必要が ある 1 サイクルあたり 4 FLOP という理論上の最大値を達成するにはどうすればよいですか? ただし、Haswell では、1 サイクルあたり 8 つの倍精度浮動小数点 FLOPS を実行します。
編集
実際、Mysticial は FMA3 をサポートするようにプロジェクトを更新しました (上記のリンクで彼の回答を参照してください)。MSVC2012 を使用して Windows8 で彼のコードを実行しました (Linux バージョンは FMA サポートでコンパイルされなかったため)。これが結果です。
これは、二重浮動小数点の FMA3 で 69.38 GFLOPS です。単一の浮動小数点の場合、2 倍にする必要があるため、138.76 SP GFLOPS になります。私の計算では、ピークは 146.2 SP GFLOPS です。 それはピークの 95% です! 言い換えれば、GEMM コードをかなり改善できるはずです (ただし、Eigen よりもかなり高速です)。
fortran - gfortran または ifort コンパイラは、2 つの配列の積を合計するときに SIMD 命令を賢明に使用しますか?
numpy で書かれたコードがいくつかあり、パフォーマンスを向上させるために Fortran に移植することを検討しています。
私が何度か行う操作の 1 つは、2 つの配列の要素ごとの積を合計することです。
融合された乗加算命令がこれに役立つようです。現在のプロセッサはこれらの命令をサポートしていないため、まだテストできません。ただし、FMA3 (Intel Haswell プロセッサ) をサポートする新しいプロセッサにアップグレードする可能性があります。
「-march=native」(または相当する ifort) を使用してプログラムをコンパイルするだけで、コンパイラ (gfortran または ifort) が SIMD 命令を賢く使用してそのコードを最適化するのに十分かどうか、誰にもわかりますか?コンパイラやコードを赤ちゃんにする必要がありますか?
c++ - パフォーマンスのために複数の fma 操作を連鎖させる方法は?
T fma( T a, T b, T c )
一部の C または C++ コードで、1 つの乗算と 1 つの加算を実行するという名前の関数があると仮定し( a * b ) + c
ます。複数のmul & addステップを最適化するにはどうすればよいですか?
たとえば、私のアルゴリズムは 3 つまたは 4 つの fma 操作を連鎖させて合計する必要があります。これを効率的に記述するにはどうすればよいでしょうか。また、構文またはセマンティクスのどの部分に特に注意を払う必要がありますか?
CPUパイプラインのフラッシュを避けるために、CPUの丸めモードを変更しないでください。しかし+
、複数の呼び出し間の操作を使用してfma
それを変更するべきではないと確信しています。これをテストするための CPU が多すぎないため、「確かに」と言っています。いくつかの論理的な手順に従っているだけです。 .
私のアルゴリズムは、複数の fma 呼び出しの合計のようなものです
c - L1 キャッシュで Haswell のピーク帯域幅を取得: 62% しか取得できません
Intel プロセッサで次の関数を実行するために、L1 キャッシュで全帯域幅を取得しようとしています。
これはSTREAMの triad 関数です。
この機能を備えた SandyBridge/IvyBridge プロセッサ (NASM によるアセンブリを使用) で、ピークの約 95% を取得します。ただし、Haswell を使用すると、ループを展開しない限り、ピークの 62% しか達成できません。16 回アンロールすると、92% になります。私はこれを理解していません。
NASM を使用してアセンブリで関数を記述することにしました。アセンブリのメイン ループは次のようになります。
Agner Fog の Optimizing Assembly マニュアルの例 12.7-12.11 で、彼はy[i] = y[i] +k*x[i]
Pentium M、Core 2、Sandy Bridge、FMA4、および FMA3 に対してほぼ同じこと (ただし を除く) を行っていることがわかりました。私は彼のコードを多かれ少なかれ自力で再現することができました (実際、彼はブロードキャスト時に FMA3 の例に小さなバグを持っています)。彼は、FMA4 と FMA3 を除く各プロセッサの命令サイズ数、融合演算、実行ポートを表に示します。FMA3 用にこのテーブルを自分で作成しようとしました。
サイズは命令の長さをバイト単位で示します。add
and命令が μop の半分を持っている理由はjne
、それらが 1 つのマクロ op に融合され (まだ複数のポートを使用する μop 融合と混同しないでください)、ポート 6 と 1 つの μop しか必要としないためです。 命令はポート 0 またはポート 1 を使用できます。ポート 0 を選択しました。負荷はポート 2 または 3 を使用できます。ポート 2 を選択し、ポート 3 を使用しました。Agner Fog のテーブルと一貫性を保つために、異なるポートに行くことができる命令は 1/2 の確率で各ポートに等しく行くと言う方が理にかなっていると思うので、ポートに 1/2 を割り当てて、vfmadd231ps
vmovaps
vfmadd231ps
vmovaps
行くvmadd231ps
ことができます。に。
この表と、すべての Core2 プロセッサがクロック サイクルごとに 4 つの μops を実行できるという事実に基づくと、このループはクロック サイクルごとに可能であるように見えますが、私はそれを得ることができませんでした。アンロールしないと、Haswell でこの関数のピーク帯域幅に近づけない理由を誰か説明してもらえますか? これは展開せずに可能ですか?この関数の ILP を最大化しようとしていることをはっきりさせておきます (最大帯域幅だけが必要なわけではありません)。それが、展開したくない理由です。
編集: Iwillnotexist Idonotexist が IACA を使用して、ストアがポート 7 を使用しないことを示したので、ここに更新があります。アンロールせずに 66% バリアを破り、アンロールせずに反復ごとに 1 クロック サイクルでこれを行うことができました (理論的には)。まず、店舗の問題を解決しましょう。
[base + offset]
Stephen Canon はコメントで、ポート 7 のアドレス生成ユニット (AGU) はや notなどの単純な操作しか処理できないと述べ[base + index]
ました。Intel 最適化リファレンス マニュアルで見つけたのは、port7 に関するコメントで、「Simple_AGU」と書かれており、simple の意味が定義されていませんでした。しかし、その後 Iwillnotexist Idonotexist は、IACA のコメントで、この問題は 6 か月前に Intel の従業員が 2014 年 3 月 11 日に書いた記事で既に言及されていることを発見しました。
Port7 AGU は、単純なメモリ アドレス (インデックス レジスタなし) を持つストアでのみ機能します。
Stephen Canon は、「ストア アドレスをロード オペランドのオフセットとして使用する」ことを提案しています。私はこのようにこれを試しました
これにより、実際にストアはポート 7 を使用します。ただし、vmadd231ps
IACA からわかるように負荷と融合しないという別の問題があります。また、cmp
私の本来の機能にはなかった命令も追加で必要です。そのため、ストアで使用する micro-op は 1 つ少なくなりますが、(cmp
マクロが と融合するため) にはもう 1 つ必要です。IACA は、1.5 のブロック スループットを報告しています。実際には、これはピークの約 57% しか得られません。add
cmp
jne
しかし、vmadd231ps
命令を負荷と融合させる方法も見つけました。これは、このようにアドレス指定 [絶対 32 ビット アドレス + インデックス] を使用する静的配列を使用してのみ行うことができます。Evgeny Kluev オリジナルはこれを提案しました。
src1_end
、src2_end
、およびは、静的dst_end
配列の終了アドレスです。
これは、私が予想した 4 つの融合マイクロオペレーションを使用して、質問の表を再現しています。これを IACA に入れると、1.0 のブロック スループットが報告されます。理論的には、これは SSE および AVX バージョンと同様に機能するはずです。実際には、ピークの約 72% を取得します。これで 66% の壁は破れましたが、16 回アンロールした 92% にはほど遠い状態です。したがって、Haswell では、ピークに近づくための唯一のオプションは展開することです。これは Ivy Bridge 経由の Core2 では必要ありませんが、Haswell では必要です。
編集終了:
これをテストするための C/C++ Linux コードを次に示します。NASM コードは、C/C++ コードの後に掲載されています。変更する必要があるのは、周波数番号だけです。行のdouble frequency = 1.3;
1.3 を、プロセッサの動作 (公称ではない) 周波数に置き換えます (BIOS でターボが無効になっている i5-4250U の場合は 1.3 GHz です)。
でコンパイル
C/C++ コード
System V AMD64 ABI を使用した NASM コード。
triad_fma_asm.asm:
triad_ava_asm.asm:
triad_sse_asm.asm:
floating-point - fma() の実装方法
ドキュメントによると、 にはfma()
関数がありmath.h
ます。それはとてもいいことです。私は FMA がどのように機能し、何に使用するかを知っています。しかし、これが実際にどのように実装されているかはよくわかりません。私は主にx86
とx86_64
アーキテクチャに興味があります。
おそらく IEEE-754 2008 で定義されているように、FMA 用の浮動小数点 (非ベクトル) 命令はありますか?
FMA3 または FMA4 命令は使用されていますか?
精度が信頼されている場合、実際の FMA が使用されていることを確認するための組み込み関数はありますか?
c++ - C ++で積和を使用する簡単な方法はありますか?
c++AMP ライブラリの mad 関数を使用することで、パフォーマンスが大幅に向上しました。通常のC++ 11に同様の機能があるかどうか疑問に思っていましたか? 私がグーグルで見つけたのはAVX組み込みに関するものだけでしたが、それらは普遍的にサポートされていないため、避けたいと思います。
また、それらはすべて同時に4つ以上の狂った操作を処理するように作られているようで、実際にそれらの1つを使用するだけでそれが発生する環境を構築することが効率的であるかどうかはわかりません.