2

私は、可能な絶対最大速度で、ベクトルの合計を散在するメモリ位置にストリーミングするプログラムを作成する任務を負っています。入力データは目的地 ID と XYZ float ベクトルなので、次のようになります。

[198, {0.4,0,1}],  [775, {0.25,0.8,0}],  [12, {0.5,0.5,0.02}]

そして、次のようにそれらをメモリに合計する必要があります。

memory[198] += {0.4,0,1}
memory[775] += {0.25,0.8,0}
memory[12]  += {0.5,0.5,0.02}

問題を複雑にするために、複数のスレッドが同時にこれを実行し、異なる入力ストリームから読み取りますが、同じメモリに合計します。同じメモリ ロケーションに対して多くの競合が発生するとは考えていませんが、競合が発生する可能性はあります。データ セットは非常に大きくなります。可能な限り最高の読み取り帯域幅を得るために、複数の SSD から同時にストリーミングする 10 GB 以上の複数のストリームです。数学的には SSE を想定していますが、必ずしもそうである必要はありません。

結果はしばらく使わないのでキャッシュを汚す必要はないのですが… ただ書くだけでなくメモリに集計しているのでMOVNTPSとか使えないですよね?しかし、スレッドはお互いにそれほど踏み込むことはないので、多くのロック オーバーヘッドなしでこれを行うにはどうすればよいでしょうか? メモリフェンシングでこれを行いますか?

助けてくれてありがとう。それが違いを生むなら、私はNehalem以上を想定できます。

4

2 に答える 2

0

プログラムのパフォーマンスはメモリ帯域幅によって制限されます。マルチ CPU (マルチコアだけでなく) システムを使用していない限り、マルチスレッドによる大幅な速度の向上は期待できません。

CPU ごとに 1 つのスレッドを開始します。これらのスレッド間で宛先データを静的に分散します。そして、各スレッドに同じ入力データを提供します。これにより、NUMA アーキテクチャをより有効に使用できます。また、スレッド同期のための余分なメモリ トラフィックを回避します。

シングル CPU システムの場合、宛先データにアクセスするスレッドは 1 つだけ使用します。

おそらく、CPU でより多くのコアを実際に使用する唯一の方法は、追加のスレッドで入力データをロードすることです。

明らかな最適化の 1 つは、宛先データを 16 バイトずつアラインすることです (1 つのデータ要素にアクセスする際に 2 つのキャッシュ ラインに触れないようにするため)。

SIMD を使用して加算を実行するか、コンパイラーがコードを自動的にベクトル化できるようにするか、この操作を完全に最適化しないままにしておくことができます。メモリ帯域幅の問題に比べれば、問題ではありません。

出力データによるキャッシュの汚染に関しては、MOVNTPS はここでは役に立ちませんが、PREFETCHNTA を使用して、キャッシュの汚染を最小限に抑えながら、出力データ要素を数ステップ先にプリフェッチすることができます。パフォーマンスが向上するか、低下するかはわかりません。キャッシュの破棄を回避しますが、ほとんどのキャッシュを未使用のままにします。

于 2012-01-29T11:12:04.223 に答える
0

配列要素 (ID ごとに 1 つ) への同期アクセスにはスピン ロックを使用し、合計には SSE を使用できます。C++ では、コンパイラによっては、 Visual C++ のストリーミング SIMD 拡張機能InterlockExchangeなどの組み込み関数が利用できる場合があります。

于 2012-01-29T00:09:20.957 に答える