3

私は Xeon Phi を初めて使用するので、ベクトル レジスタを使用して Phi のパフォーマンスを向上させる方法を理解しようとマニュアルを調べています。

[0,1]この質問の最後にある、リーマン和を使用して曲線 4/(1+x^2) の下の面積を計算する短いコードを考えてみましょう。分析的な答えは pi = 3.14159....

コードは基本的に、OpenMP を使用して 4 つのスレッドを使用して答えを計算する2つのほぼ同一のコード チャンクで構成されます。唯一の違いは、2 番目の チャンクでは、ベクトル化された関数__sec_reduce_add()を使用して、スレッドに与えられた [0,1] のサブドメインのリーマン和を計算していることです。

コードの最初のチャンクのタイミングは0.0866439 sで、2 番目の (ベクトル化された) チャンクのタイミングは0.0868771 s

これらの両方がほぼ同じタイミングをもたらしたのはなぜですか。ベクトル レジスタを使用すると、パフォーマンスが大幅に向上すると考えていたでしょう。

これをicc -mmic -vec-report3 -openmpフラグでコンパイルしました

[注: rptrpt=0 と rpt=1 は「ウォームアップ」ループであり、タイミングが多少高くなるため、2 つのセクションにわたって変数を使用して for ループを配置しました。rpt=3 で 2 つのセクションのタイミングを指定しました]

#include <iostream>
#include <omp.h>
using namespace std;

int main (void)
{
  int num_steps     = 2e8           ;
  double dx        = 1.0/num_steps ;
  double x         = 0.            ;
  double* fn = new double[num_steps];

  // Initialize an array containing function values
  for(int i=0 ; i<num_steps ;++i )
    {
      fn[i] = 4.0*dx/(1.0 + x*x);
      x += dx;
    }


for(size_t rpt=0 ; rpt<4 ; ++rpt)
{
  double start = omp_get_wtime();
  double parallel_sum = 0.;
  #pragma omp parallel num_threads(4)
  {
    int threadIdx = omp_get_thread_num();
    int begin = threadIdx * num_steps/4 ; //integer index of left-end  point of sub-interval
    int end   = begin + num_steps/4     ;// integer index of right-end point of sub-interval
    double dx_local = dx                ;
    double temp = 0                     ;
    double x    = begin*dx              ;

    for (int i = begin; i < end; ++i)
      {
        temp += fn[i];
      }
    #pragma omp atomic
    parallel_sum += temp;
  }
  double end   = omp_get_wtime();
  std::cout << "\nTime taken for the parallel computation: "    << end-start << " seconds";


  //%%%%%%%%%%%%%%%%%%%%%%%%%

  start = omp_get_wtime();
  double parallel_vector_sum = 0.;
  #pragma omp parallel num_threads(4)
  {
    int threadIdx = omp_get_thread_num();
    int begin = threadIdx * num_steps/4 ; //integer index of left-end  point of sub-interval
    int end   = begin + num_steps/4     ;// integer index of right-end point of sub-interval
    double dx_local = dx                ;
    double temp = 0                     ;
    double x    = begin*dx              ;

    temp = __sec_reduce_add( fn[begin:end-begin+1]   );
    #pragma omp atomic
      parallel_vector_sum += temp;
  }
  end   = omp_get_wtime();
  std::cout << "Time taken for the parallel vector computation: "    << end-start << " seconds"  ;


 }// end for rpt
  return 0;
}
4

0 に答える 0