2012-12-21 8 views
6

私は開始位置と終了位置を示す2つの符号なしショートのコンパクトな構造体を使用しています。
長さ(開始から終了までの差)がしきい値を超えているRangeオブジェクトがあるかどうかを素早く判断できる必要があります。ショートを含む条件付きのベクトル化

私はそれぞれ独自のRange配列を持つ膨大な数のオブジェクトを持っていますので、どのオブジェクトがしきい値を上回っているかをリストで確認することはできません。また、このコードは非常に頻繁に実行されるため(効率的である必要があるため、各アレイの1秒間に何度も実行されます)

struct Range 
{ 
unsigned short start; 
unsigned short end; 
} 

私はいつもRangeのサイズが2^nの配列を持ちます。スレッショルドを超えるとすぐに中止したいと思っていますが、ループ全体を単純化するか、最後にチェックする方が速いでしょう。それぞれのベクトルの結果の塊についてif文を書くことができれば、それは壮大なものになります。私のデータ型がない32または64ビット幅であるため、

size_t rangecount = 1 << resolution; 
Range* ranges = new Range[rangecount]; 

... 

bool result = false; 
for (size_t i = 0; i < ranges; ++i) 
{ 
result |= (range[i].end - range[i].start) > 4; 
} 

は驚くことではないが、自動ベクトライザーは、1202エラーが発生します。私は本当にデータサイズを倍にして各フィールドを符号なしintにしたくありません。だから、私はオートベクトル化のアプローチがこれに当てはまると推測しています。

16ビット変数を処理できるベクタ命令はありますか?もしあれば、どうすればループをベクトル化するためにC++でそれらを使うことができますか?

+0

必要がありますか?このルックアップを高速化する別のデータ構造に格納してみてはどうでしょうか? – loganfsmyth

+0

_ Rangeオブジェクトがリストのなかのスレッショルドを上回っているかどうかを追跡することは不可能です。あなたがしたいのは、ルールを破る範囲があるかどうかを判断し、それを追跡するだけです。あなたはそれを行うためにすべてのオブジェクトを追跡する必要はありません。 –

+0

どのくらいの頻度で 'end'を使いますか? '(start、end)'の代わりに '(start、size)'表現に切り替えることは可能でしょうか。もちろん、使用するたびに 'end'を計算する必要がありますが、' end'と 'size'の相対的な使用率が低い場合、それはまだ勝利に終わる可能性があります。 – twalberg

答えて

1

値が4より大きいかどうか疑問に思っていますか?

はい、このためのSIMD命令があります。自動ベクトル化がこのシナリオを処理できないことは残念です。

diff_v = end_v - start_v; // _mm_hsub_epi16 
floor_v = max(4_v, diff_v); // _mm_max_epi16 
if (floor_v != 4_v) return true; // wide scalar comparison 

利用_mm_sub_epi16構造体の配列と配列の構造や_mm_hsub_epi16と:ここではベクトル化アルゴリズムです。

実際にstartがメモリに格納されているので、start_v - end_vで作業するので、_mm_min_epi16とベクトル-4を使用してください。

各SSE3命令は、一度に8回の比較を実行します。ループするのではなく早く戻ることが最も速いでしょう。しかし、ループをもう少し広げておけば、さらにスピードを増やすことができます(最初の結果セットをパックミニ/マックス関数に渡して組み合わせる)。

だからあなたは(約)で終わる:あなたは、配列内の範囲の値を格納する

most_negative = threshold = _mm_set_epi64(0xFCFCFCFCFCFCFCFC); // vectorized -4 

loop: 
    a = load from range; 
    b = load from range; 
    diff = _mm_hsub_epi16(a, b); 
    most_negative = _mm_min_epi16(most_negative, diff); 

    // unroll by repeating the above four instructions 4 times or so 
    if (most_negative != threshold) return true; 
repeat loop 
+0

自動ベクトライザではできないことがありますが、それは簡単ですね! – user173342

+0

@ user173342:ちょうど2つのメンバーを持つインターリーブされた配列を扱うことは特殊なケースであり、自動ベクトル化はおそらく準備ができていないでしょう。 –