2011-12-29 16 views
3

私は非常に新しいプログラマーです。私はIntelの例にいくつか問題があります。最も基本的なループがtbbでどのように実装されているかを知ることができれば役に立ちそうです。TBBを使用した非常に基本的なループ

for (n=0 ; n < songinfo.frames; ++n) { 

     sli[n]=songin[n*2]; 
     sri[n]=songin[n*2+1]; 

} 

ここでは、オーディオデータのデインターリーブに使用しているループを示します。このループはtbbの恩恵を受けるでしょうか?あなたはそれをどのように実装しますか?

+1

"非常に新しいプログラマー"と "*スレッディング*"という言葉は、同じ文章には現れてはなりません。あなたが「非常に新しいプログラマー」であれば、スレッディングはあなたが心配する必要があるものではありません。今は、 'if'と' for'文がどのように動作するかを知る必要があります。どのように機能し、いくつかの基本的なメモリ管理。オブジェクトの作成と管理方法。 TBBはスレッディングを簡単にしますが、スレッディングは初心者ではありません。 –

+0

私は新しいですが、実際に私の自由な時間は、月に何時間も勉強していますので、私は基本がたくさんあると思います。学習プロジェクトとして、私はサウンド処理を実験しています。私のプロジェクトは基本的に完了しているので、次のステップを踏み、マルチスレッドを追加してコードの速度を上げようとしています。 p – MVTC

答えて

6

まず、あなたのarraysmytype*であると仮定します。それ以外の場合は、コードを変更する必要があります。あなたは、ライブラリを初期化する必要があり

まず:さらに、私はあなたの範囲が重複しないことを前提とし、それ以外の場合は並列化attempsは、あなたがTBBにそれを求めているので

(少なくともないより作業をせずに)正しく動作しませんどこかで(通常main)。コードについては、using namespace tbbをどこかに置くと仮定します。

int main(int argc, char *argv[]){ 
    task_scheduler_init init; 
    ... 
} 

次に、あなたがあなたの配列をキャプチャし、forloopのボディを実行ファンクタ必要があります。今、あなたはこのループを並列化するためにparallel_forを使用することができます

struct apply_func { 
    const mytype* songin; //whatever type you are operating on 
    mytype* sli; 
    mytype* sri; 
    apply_func(const mytype* sin, mytype* sl, mytype* sr):songin(sin), sli(sl), sri(sr) 
    {} 
    void operator()(const blocked_range<size_t>& range) { 
     for(size_t n = range.begin(); n !=range.end(); ++n){ 
     sli[n]=songin[n*2]; 
     sri[n]=songin[n*2+1]; 
     } 
    } 
} 

を:

size_t grainsize = 1000; //or whatever you decide on (testing required for best performance); 
apply_func func(songin, sli, sri); 
parallel_for(blocked_range<size_t>(0, songinfo.frames, grainsize), func); 

(私が正しく覚えていれば、しばらくの間、tbbを見ていないので、小さな間違いがあるかもしれない)。 あなたがC++ 11を使用する場合は、lambdaを使用してコードを単純化することができます

​​

TBBは、私は新しいプログラマのための推薦正確ものではありません言われていること。私は本当に並列化することをお勧めします。これは並列化するのが簡単なコードだけです。これについては、を使用することをお勧めします。これは、tbbで始めるのが少しシンプルですが、多くのものを並列化するのにはまだ強力です(しかし、それをサポートするコンパイラによって異なります)。あなたのループのために、それは次のようになります。

#pragma omp prallel for 
for(size_t n = 0; n < songinfo.frames; ++n) { 
    sli[n]=songin[n*2]; 
    sri[n]=songin[n*2+1]; 
} 

を次にあなたがコンパイルするコンパイラに指示する必要がありとのOpenMPとのリンク(gccのための-fopenmp/openmpのVisual C++用)。あなたが見ることができるように、それはかなり簡単です(そのような簡単な用途のために、より複雑なscenariousは別の問題です)。tbbそしてopenmpまたはtbbをサポートしないworkingon plattformの追加の利点を持っています(#pragmasコンパイラによって無視されます)。個人的に私はオープンソースライセンスを使用することができなかったのでいくつかのプロジェクトのためのtbbを好むopenmpを使用しています。そして、tbbを購入することはプロジェクトのためにちょっとしたものでした。

ここでは、ループをパラレル化する方法があるので、それが価値があるかどうか質問に出ます。これは本当に簡単には答えられない質問です。処理する要素の数とプログラムが実行されるプラットフォームの種類に完全に依存するためです。あなたの問題は非常に帯域幅が重いので、私はパフォーマンスの大幅な向上は期待していません。

  • 1000要素のみを処理する場合、並列バージョンのループは、オーバーヘッドのためにシングルスレッドバージョンよりも遅くなる可能性が非常に高いです。
  • データがキャッシュにない場合(適合しないため)、システムの帯域幅が非常に枯渇していると、多くのメリットは得られません(ただし、メリットはあるものの、
  • 追加transfercostsによる、お使いのシステムは、ccNUMA(マルチソケット・システムの可能性が高い)であれば、あなたのパフォーマンスは関係なく、要素の量の低下することがあります
  • )supprisedそのは1.Xのためにあなたはプロセッサの多くを使用している場合でも場合コンパイラがポインタエイリアシングに関する最適化を見逃している可能性があります(ループ本体が別の関数に移動されるため)。 __restrictを使用すると(gccの場合、vsのヒントはありません)、その問題の解決に役立ちます。個人的に
  • ...

私はあなたのシステムがどのためのデータセットのフィットのL3-キャッシュに、単一のマルチコアCPUを持っている場合は、パフォーマンスの大幅な増加を参照してくださいする可能性が最も高い状況があると思います(個々のL2キャッシュではありません)。より大きなデータセットの場合、パフォーマンスはおそらく増加しますが、それほど多くはありません(正しくプリフェッチを使用すると、同様の利益が得られる可能性があります)。もちろんこれは純粋な投機である。

+0

偉大な答え。本当にありがとう。 – MVTC

関連する問題