1

内部ループで std::max の呼び出し回数を減らそうとしています。これは、何百万回も呼び出しているため (誇張ではありません!)、並列コードの実行速度が順次コードよりも遅くなっているためです。基本的な考え方 (はい、これは割り当てのためのものです) は、最大変化が特定の非常に小さな数値 (0.01 など) を超えないようになるまで、コードが特定のグリッドポイントでの温度を反復ごとに計算することです。新しい温度は、そのすぐ上、下、および横のセルの温度の平均です。結果として、各セルには異なる値があり、グリッドの特定のチャンクの任意のセルで最大の変化を返したいと考えています。

コードは動作していますが、内側のループで std::max を大量に (過度に) 呼び出しており、O(n*n) であるため、処理が遅くなります。1D ドメイン分割を使用しました

注: tdiff は、マトリックスの内容以外には依存しません。

リダクション関数の入力はラムダ関数の結果です

diff は、1 回の反復におけるグリッドのそのチャンク内の単一セルの最大の変化です

ブロックされた範囲は、コードの前半で定義されています

t_new はそのグリッド ポイントの新しい温度、t_old は古い温度です。

max_diff = parallel_reduce(range, 0.0,
        //lambda function returns local max
        [&](blocked_range<size_t> range, double diff)-> double
        {
            for (size_t j = range.begin(); j<range.end(); j++)
            {
                for (size_t i = 1; i < n_x-1; i++)
                {
                    t_new[j*n_x+i]=0.25*(t_old[j*n_x+i+1]+t_old[j*n_x+i-1]+t_old[(j+1)*n_x+i]+t_old[(j-1)*n_x+i]);
                    tdiff = fabs(t_old[j*n_x+i] - t_new[j*n_x+i]);
                    diff = std::max(diff, tdiff);
                }   
            }
            return diff;    //return biggest value of tdiff for that iteration - once per 'i'
        },
        //reduction function - takes in all the max diffs for each iteration, picks the largest
        [&](double a, double b)-> double
        {
            convergence = std::max(a,b);
            return convergence;
        }
    );

コードをより効率的にするにはどうすればよいですか? std::max の呼び出しを減らしたいのですが、正しい値を維持する必要があります。gprof を使用すると、次のようになります。

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 61.66      3.47     3.47  3330884     0.00     0.00  double const& std::max<double>(double const&, double const&)
 38.03      5.61     2.14     5839     0.37     0.96  _ZZ4mainENKUlN3tbb13blocked_rangeImEEdE_clES1_d

ETA: コードの実行に費やされた時間の 61.66% が std::max 呼び出しに費やされ、300 万回以上呼び出されます。reduce 関数はラムダ関数の出力ごとに呼び出されるため、ラムダ関数で std::max の呼び出し回数を減らすと、reduce 関数の呼び出し回数も減ります

4

2 に答える 2

0

私はparallel_forを使用することになりました:

parallel_for(range, [&](blocked_range<size_t> range)
        {
            double loc_max = 0.0;
            double tdiff;
            for (size_t j = range.begin(); j<range.end(); j++)
            {
                for (size_t i = 1; i < n_x-1; i++)
                {
                    t_new[j*n_x+i]=0.25*(t_old[j*n_x+i+1]+t_old[j*n_x+i-1]+t_old[(j+1)*n_x+i]+t_old[(j-1)*n_x+i]);
                    tdiff = fabs(t_old[j*n_x+i] - t_new[j*n_x+i]); 
                    loc_max = std::max(loc_max, tdiff); 
                }   
            }
            //reduction function - takes in all the max diffs for each iteration, picks the largest
            {
                max_diff = std::max(max_diff, loc_max);
            }
        }
    );

そして今、私のコードは 8000x8000 グリッドで 2 秒以内に実行されます :-)

于 2013-05-23T02:09:41.057 に答える