10

Corei7アーキテクチャーでdouble/integersのベクトルの最小/最大の計算を高速化できるasm命令はありますか?

アップデート:

こんなに豊富な答えは期待していませんでした、ありがとうございます。したがって、最大/最小は分岐せずに実行できることがわかります。サブ質問があります:

配列内の最大のdoubleのインデックスを取得する効率的な方法はありますか?

4

6 に答える 6

13

SSE4にはPMAXSD、またはPMAXUD32ビットの符号付き/符号なし整数があります。これは便利な場合があります。

SSE2にはMAXPDMAXSDdoubleのペア間で比較されるため、1つのMAXSDでn / 2-1 MAXPDを追跡し、通常の負荷と操作のインターレースを使用して、nのベクトルの最大値を取得します。

上記に相当するMINがあります。

二重の場合、SSEモードの半ばまともなC++コンパイラよりもアセンブラでうまくいくことはおそらくないでしょう。

peregrino:$ g++ -O3 src/min_max.cpp -o bin/min_max
peregrino:$ g++ -O3 -msse4 -mfpmath=sse src/min_max.cpp -o bin/min_max_sse
peregrino:$ time bin/min_max
0,40

real    0m0.874s
user    0m0.796s
sys 0m0.004s
peregrino:$ time bin/min_max_sse 
0,40

real    0m0.457s
user    0m0.404s
sys 0m0.000s

ここで、min_maxは、単純なループを使用して、500の配列の最小値と最大値を100,000回2倍に計算します。

bool min_max ( double array[], size_t len, double& min, double& max )
{
    double min_value = array [ 0 ];
    double max_value = array [ 0 ];

    for ( size_t index = 1; index < len; ++index ) {
        if ( array [ index ] < min_value ) min_value = array [ index ];
        if ( array [ index ] > max_value ) max_value = array [ index ];
    }

    min = min_value;
    max = max_value;
}

パート2に対応して、max演算から分岐を削除する従来の最適化は、値を比較し、フラグを1ビット(0または1を与える)として取得し、1を減算(0または0xffff_ffffを与える)し、'および' 2つの可能な結果のxorであるため、。と同等の結果が得られます( a > best ? ( current_index ^ best_index ) : 0 ) ^ best_index )。SSEはタグ付きの値ではなくパックされた値を操作する傾向があるため、これを行う簡単なSSEの方法があるとは思えません。いくつかの水平インデックス操作があるので、最大値を見つけて、元のベクトルのすべての要素からそれを減算し、符号ビットを収集すると、ゼロ符号付きのものが最大値のインデックスに対応しますが、おそらくそれはショートまたはバイトを使用していない限り、改善にはなりません。

于 2009-12-28T15:01:23.907 に答える
4

SSEのMAXPSとMINPSはどちらも、パックされた単精度浮動小数点数で動作します。PMAXSW、PMINSW、PMAXUB、およびPMINUBはすべて、符号付きまたは符号なしのパックされた8ビットワードで動作します。これらは2つの入力SSEレジスタまたはアドレス位置を要素ごとに比較し、結果をSSEレジスタまたはメモリ位置に格納することに注意してください。

MAXPSおよびMINPSのSSE2バージョンは、倍精度浮動小数点数で動作するはずです。

どのコンパイラと最適化フラグを使用していますか?gcc 4.0以降では、ターゲットが操作をサポートしている場合、操作を自動的にベクトル化する必要があります。以前のバージョンでは、特定のフラグが必要になる場合があります。

于 2009-12-28T15:00:35.047 に答える
2

IntelのIPPライブラリを使用している場合は、ベクトル統計関数を使用して、ベクトルの 最小/最大を計算できます(特に)

于 2009-12-28T15:03:05.323 に答える
2

2番目の質問への回答:ほとんどのプラットフォームには、この操作(および他のほとんどの単純なベクトル操作)の最適化された実装がすでに含まれているライブラリがあります。 それらを使用してください

  • OS XにはvDSP_maxviD( )cblas_idamax( )Accelerate.frameworkがあります。
  • インテル®コンパイラーには、IPPおよびMKLライブラリーが含まれています。これらのライブラリーには、次のような高性能の実装があります。cblas_idamax( )
  • ほとんどのLinuxシステムはcblas_idamax( )BLASライブラリに含まれていますが、その出所に応じて適切に調整されている場合とされていない場合があります。パフォーマンスを気にするユーザーは、一般的に優れた実装を持っています(またはそれをインストールするように説得することができます)
  • 他のすべてが失敗した場合は、ATLAS(自動調整線形代数ソフトウェア)を使用して、ターゲットプラットフォームで適切なパフォーマンス実装を取得できます。
于 2009-12-29T22:31:43.513 に答える
1

更新:パート2で「ベクトル」ではなく「配列」と言っていることに気づきました。これは、役立つ場合に備えて、とにかくここに残しておきます。


re:パート2:SSEベクトルのmax / min要素のインデックスを見つけます:

  • 水平方向の最大値を実行します。double2要素の128bベクトルの場合、結果を両方の要素にブロードキャストするための1つのshufpd+です。maxpd

    その他の場合は、もちろん、より多くの手順を実行します。アイデアについては、 x86で水平フロートベクトルの合計を実行する最速の方法を参照してください。またはに置き換えaddpsてください。(ただし、SSE4を使用できるため、16ビット整数は特別であることに注意してください。最大の場合は、255から減算します)maxpsminpsphminposuw

  • ベクトルの元のベクトルとすべての要素が最大であるベクトルをパック比較します。

    pcmpeqq整数ビットパターンまたは通常のcmpeqpd両方がこのdouble場合に機能します)。

  • int _mm_movemask_pd (__m128d a)movmskpd比較結果を整数ビットマップとして取得します。
  • bsf(最初の)一致のためにビットスキャン( )します: index = _bit_scan_forward(cmpmask)。整数比較を使用した場合、cmpmask = 0は不可能です(少なくとも1つの要素がNaNであっても一致するため)。

これは、6つの命令(を含むmovapd)にのみコンパイルする必要があります。うん、Godboltコンパイラエクスプローラーをチェックしたところ、SSEでチェックした。

#include <immintrin.h>
#include <x86intrin.h>

int maxpos(__m128d v) {
  __m128d swapped = _mm_shuffle_pd(v,v, 1);
  __m128d maxbcast = _mm_max_pd(swapped, v);
  __m128d cmp = _mm_cmpeq_pd(maxbcast, v);
  int cmpmask = _mm_movemask_pd(cmp);
  return _bit_scan_forward(cmpmask);
}

_mm_max_pdNaN入力と可換ではないことに注意してください。NaNが可能で、Intel Nehalemのパフォーマンスを気にしない場合は、_mm_cmpeq_epi64ビットパターンの比較に使用することを検討してください。ただし、floatからvec-intへのバイパス遅延はNehalemの問題です。

NaN!= IEEE浮動小数点のNaNであるため_mm_cmpeq_pd、all-NaNの場合、結果マスクはすべてゼロになる可能性があります。

2要素の場合に常に0または1を取得するために実行できる別のことは、ビットスキャンを。に置き換えることですcmpmask >> 1。(bsfinput = all-zeroでは奇妙です)。

于 2017-08-07T07:58:33.617 に答える
-1

2番目の質問に答えて、このデータを収集および保存する方法について考えることは価値があるかもしれません。

データを常にソートされた状態に保つBツリーにデータを格納し、対数比較操作のみを必要とする場合があります。

そうすれば、いつでも最大値がどこにあるかがわかります。

http://en.wikipedia.org/wiki/B_tree

于 2012-02-16T03:26:58.863 に答える