HPC/並列プログラミングポータルでは、HPC(High Performance Computing)プログラミングや並列プログラミングに関する情報を集積・発信しています。

新着トピックス

 ここでさらに詳細を調べるために「BlurImageChannel」の列をダブルクリックしてみよう。すると、ソースコードとともにCPU_CLK_UNHALTED.COREやINST_RETIRED.ANYといったCPUの動作状況が表示される(図18)。ここから、「effect.c」中の964行以下の部分がCPUサイクルを多く消費していることが分かる。さらに、INST_RETIRED.ANYの値がCPU_CLK_UNHALTED.COREの値よりも大幅に小さいことから、CPUを効率的に利用できていない、ということも分かる。つまり、この部分がパフォーマンスのボトルネックとなっているということだ。

 このボトルネックとなっていると思われる部分は次のような処理だ。これは非連続なメモリ領域に連続してアクセスする処理で、このような処理はキャッシュミスが発生しやすく、そのためにパフォーマンスが低下する原因となる。

  for (i=0; i  (long) width; i++)
  {
    pixel.red+=(*k)*(p+i)-red;
    pixel.green+=(*k)*(p+i)-green;
    pixel.blue+=(*k)*(p+i)-blue;
    k++;
  }

 それでは、この問題を解決するにはどうすればよいだろうか。問題は非連続なメモリ領域へのアクセスにあるので、これを連続したメモリ領域へのアクセスに修正すれば、よりCPUを効率よく利用できると考えられる。そこで、この処理を行う前に連続したメモリバッファを確保し、非連続なメモリ領域に格納されているデータをそこにコピーしてから乗算・加算処理を行うように修正した。修正後のソースコードは下記のようになる。

  for (i=0; i  (long) width; i++ )
  {
    buf[i] = (p+i)-red;
  }
  for (i=0; i  (long) width; i++ )
  {
    pixel.red += (*(k+i)) * buf[i];
  }
  for (i=0; i  (long) width; i++ )
  {
    buf[i] = (p+i)-green;
  }
  for (i=0; i  (long) width; i++ )
  {
    pixel.green += (*(k+i)) * buf[i];
  }
  for (i=0; i  (long) width; i++ )
  {
    buf[i] = (p+i)-blue;
  }
  for (i=0; i  (long) width; i++ )
  {
    pixel.blue += (*(k+i)) * buf[i];
  }

 このように修正を加えたソースコードをインテル コンパイラーでコンパイルして変更前のバイナリと比較したところ、図19のような結果が得られた。修正前は59秒だった実行時間が修正後は44.2秒と、約3割もの高速化に成功している。

プログラム実行時の詳細なレポートでパフォーマンス改善

 以上、簡単ながらVTuneの利用例を紹介してきたが、いかがだっただろうか。今回の例のような、キャッシュミス等によるCPUの動作パフォーマンス低下は、ソースコードだけからではどこがボトルネックなのかを判断するのは難しく、CPUの内部動作情報までも取得できるVTuneは性能解析に非常に有用である。

 また、今回は使用しなかったが、VTuneではOSのコンテキストスイッチ数や空きメモリ容量の変化、ネットワークエラーの発生数といった統計情報を取得できる「Counter Monitor Collector」機能も備えている。これは、特定の条件で発生するような問題を解決する場合などに重宝する。

 VTuneは「作成したプログラムのパフォーマンスを改善したいがどこに問題があるか分からない」といった場合などに役立つ、非常に心強いツールといえるだろう。