• トップ
  • G-DEPについて
  • ご購入ガイド
  • サポート
  • お問い合わせ

G-DEPトップ  >  G-DEPの高速演算記  >  高速演算記 第18回 CAPS社日本代理店 (株)JCCギミック 小野寺高之様

高速演算記 第18回 CAPS社日本代理店 (株)JCCギミック 小野寺高之様

高速演算記 第18回はCAPS社日本代理店 (株)JCCギミック 小野寺高之 様より、CUDAプログラミングの総合支援ツール、また、HMPPによるディレクティブベースのプログラミングとHMPP Wizardによるポーティング支援機能についてご寄稿頂きました。

CUDAプログラミング総合支援ツール、フランスCAPS社新製品”DevDeck”のご紹介

1. はじめに

 GPUを利用するアプリケーションを開発する場合,NVIDIA社のGPUを使っている多くの方がCUDA(もしくはOpenCL)でプログラミングで始められると思います.CUDAによるプログラミングは,CUDA APIを使うことで細かいところまでプログラムを書くことができる反面,CUDAカーネルのコード作成とデータ転送などを行うためのAPI関数の挿入が必要となります.そのためGPUの利用に興味をもっていても,時間的・労力的に導入をためらわれる方も少なくないと思われます.
GPUプログラミングを行う手法として,OpenMPのようにCPUコードにディレクティブを挿入することによってプログラミングを行うディレクティブベースのアプローチがあります.ディレクティブベースのプログラミングを行うことによって,HWA(ここではGPU)に固有のコード作成やAPI関数の挿入を行うことなく,GPUを利用したアプリケーションを作成することが可能です.このようなディレクティブベースのプログラミングの利点として以下のような点があげられます.

・CPUソースコードを保全することができるため,保守や将来的な拡張が容易

・一つの元になるソースコードから,若干の修正を施すことで異なるアーキテクチャ向けのコードを生成

・GPUアプリケーションを迅速かつインクリメンタルに作成できるため,開発時間を削減することが可能

一点目は,例えばGPUを利用するアプリケーションに新しい機能を追加するような場合,基本的にCPUコードを修正すれば良いため,CUDAプログラミング経験のない人でも短時間で意味を把握して作業を行うことができます.
二点目は,単一バージョンのソースコードからディレクティブベースの開発環境がサポートしている複数のターゲットアーキテクチャに向けたコードやオブジェクトを作成できることです.CAPS社のHMPPでは現在,CUDAとOpenCL向けのソースコードを作成することができます.さらに,これからリリース予定のIntelのMICアーキテクチャへの将来的な対応予定を発表しています.このようにアーキテクチャが変わったとしても,その度にアーキテクチャ固有のソースコードを一から作成する必要がありません.
三点目については,たとえばHMPPでは最低限2行のディレクティブによってGPUを利用したアプリケーションを作成することができます.その実行情報をベースにして,ディレクティブを使って高速化の妨げとなっている部分を段階的に最適化することができます.

 このように,ディレクティブを使ってGPUなどのmany-coreアーキテクチャのターゲットを利用するアプリケーションを作成するための開発ツールがCAPS Entreprise社のHMPP WorkbenchおよびDevDeckです.HMPP WorkbenchはGPUコードジェネレータを含んだディレクティブベースのmany-coreプログラミング環境です.DevDeckはAll-in-oneのソリューションとして,CAPS社のコンパイラHMPP Workbench, 開発支援ツールHMPP Wizard, 性能解析ツールHMPP Performance Analyzer,Allinea社のデバッガAllinea DDT,EMPhotonics社のGPU用線形代数ライブラリCULAが1つのパッケージに含まれています.これらのツールを使うことで,CUDAプログラミングの経験がない方でも手軽にGPUポーティングを始めることができます.
 

 


本稿ではHMPPによるディレクティブベースのプログラミングとHMPP Wizardによるポーティング支援機能を紹介します.

 

2. HMPPによるプログラミング

 HMPPでのプログラミングはCPUコードにcodeletとcallsiteの二種類のディレクティブを入れることから始まります.GPUで実行させたい関数の直前にcodeletディレクティブを挿入し,codeletディレクティブで宣言した関数の呼び出し部分にcallsiteディレクティブを挿入します.codeletで宣言された関数はCUDAカーネルを含むCUDAコードとして生成されることになります.ただし,GPUで実行できないような処理(IO関数の呼び出しなど)を含んでいるとCUDAコードを作成できず,また並列性の検出できないループについてはカーネルに変換することができないためCPU上で実行されることになります.

 この二つのディレクティブを挿入したソースコードをHMPPでコンパイルすることによって,codeletで宣言された関数についてのGPUバージョンのコードとオブジェクトファイルが作成され,CPUオブジェクトも含めて実行ファイルとして生成されます.
codeletとcallsiteの2行を挿入することでCUDAカーネルとしてGPU上で実行させることができますが,それだけではGPUを利用しても高速にならない場合が多いと思います.これはcodeletの呼び出しのたびに自動的にメモリの割り当てやデータ転送が行われることによるもので,実際にはそうした処理を適切な位置で実行させる必要があります.メモリ割り当てやデータ転送もディレクティブで明示的に行うことができるため,全てを最初からプログラミングせずとも段階的に最適化の検討を行うことができます.

 OpenMPのように並列化可能な部分に対してディレクティブで囲めば高速化できるというイメージをもたれる方もいらっしゃるかもしれませんが,(1) GPUデバイスが独自にメモリを所有しているためメモリの割り当てやデータ転送が必要, (2)アーキテクチャと並列処理の実行モデルがCPUと違う,という点を考慮しないと性能が発揮できないことを認識する必要があります.
環境によっては複数のGPUを使いたい場合や,クラスタ上の各ノードでGPU計算を実行させたい場合があります.HMPPはOpenMPやMPIと組み合わせて使用することが可能であり,マルチGPUへの移行やGPUクラスタ向けのアプリケーションを開発する場合にも複雑なプロセスを経ずにアプリケーションを作成することができます. 

 

3. ポーティング例

 Phase Field法による2次元スピノーダル分解のシミュレーションに関するアプリケーションをHMPPでポーティングした例を紹介します.このアプリケーションは京都工芸繊維大学の高木知弘先生と東京工業大学の山中晃徳先生によって作成されたもので,Webに公開されているソースコードについて許可を得てポーティングを行いました(公開元のwebサイト:http://www.cis.kit.ac.jp/~takaki/phase-field.html).

 このアプリケーションは関数Kernelが実行時間のほぼ99%を占めていますので,この関数の直前にcodeletディレクティブを挿入し,main関数内の関数Kernel呼び出しの直前にcallsiteディレクティブを挿入します.また,codeletディレクティブで宣言された関数Kernel内の2Dループでは誘導変数を使って1次元配列にアクセスしていることから自動的にグリッド化されないため,明示的にグリッド化を指示するための”gridify”ディレクティブをループの前に挿入します.main関数内の時間進行ループの内側で毎回メモリの割り当て/解放を行う必要がないことが明らかなので,それらの処理をループの外で行うように”allocate”と”release”というディレクティブを挿入します. 

 #pragma hmpp k1 codelet, target=CUDA, &
 #pragma hmpp k1    args[fn].io=out
 void Kernel ( float *f,  float *fn, ・・・)  {
   int j, jx, jy;
   ・・・

   #pragma hmppcg gridify(jx,jy)
 for(jx=0; jx<nx; jx++) {
     for(jy=0; jy<ny; jy++) {
         ・・・
         }
   }

 int main(int argc, char** argv) {
  ・・・
   #pragma hmpp k1 allocate, args[f,fn].size={nx*ny}

   for(nstep=0; nstep<=nend ; nstep++){
     #pragma hmpp k1 callsite
     Kernel(f,fn,nx,ny,rr,temp,L0,kapa_c,da,db,dt,dx);
        ・・・
   }
  #pragma hmpp k1 release
  ・・・
 }

  このようにCPUソースコードを保ったままで5箇所にディレクティブを挿入してHMPPによるコンパイルを行い,アプリケーションをNVIDIA GeForce 460上で実行を行うことによって,CPU 1コアの場合に比べてアプリケーションの実行時間が約12.8倍高速化されました.このような高速化の効果については元になるコードの品質,使用するCPUのコア数,データサイズ,ハードウェア環境に大きく依存するため参考程度にしかなりませんが,ディレクティブを5行追加するだけである程度の性能が得られ,またGPUを利用したときの実行情報を得られることは非常に大きなメリットです.
目的の関数がGPUで実行できるようになったら最適化を検討します.最適化はCUDAと同様,例えばデータ転送,メモリアクセスパターンの改善,CUDAブロックサイズの最適化,非同期処理,共有メモリ使用などがあげられますが,これらは様々なディレクティブの使用やCPUコードの見直しによって行うことができます.このようなチューニングを行うことによって,今回紹介した性能を大きく改善できる余地があります.

 

4. HMPP Wizardによるポーティング支援

 前節では並列処理可能でGPU上で実行しやすい関数を含んだアプリケーションに対してのポーティングについて説明しました.しかし,実際のアプリケーションにはcodelet内に並列化できないループがあったり,ループのストライドや配列へのアクセスパターンが規則的でないアプリケーションもあります.そのようなソースコードに関するポーティングを支援するためのツールがHMPP Wizradです.

 HMPP WizardにはCPU用ソースコードの静的解析を行ってアドバイスを提示する機能が備わっています.たとえばGPUで実行することができないループの特定や,GPUで実行できるループに対するメモリアクセスパターンや計算密度に関する改善点などについてのアドバイスを提示します.

 以下にアンローリングを行っているCPUコードについて解析した結果を示します.このソースコードを使ってそのままHMPPでコード生成を行うと,配列Aのデータについてコアレスなメモリアクセスにならないために性能が出ません.Wizardはこの配列Aのアクセスに関するストライドを減らすようにアドバイスを提示してくれます.

 

 
      ソースコードの解析結果とアドバイス

 このようにHMPP WizardはHMPPでGPUポーティングする際に,GPUで実行できない点あるいはカーネル性能向上に必要な修正点などを提示してくれます.最低限のGPUアーキテクチャとプログラミングモデルについての知識さえあれば,これに沿ってCPUソースコードを修正していくことで,CUDAのプログラミングを覚えることなくGPUの性能を活かしたアプリケーションを作成することができます.また,アドバイスに関する詳しい情報はCAPSの専用WebサイトMyDevDeckにアクセスすることで閲覧することができるため,アドバイス内容を理解しながらポーティングを進めることができます.

 

5. おわりに

 HMPPによるディレクティブベースでのプログラミングと開発支援ツールHMPP Wizardを紹介しましたが,このようなディレクティブベースのプログラミングによりCUDAプログラミングに比べて迅速にアプリケーションを開発することができます.特にGPUで実行させるカーネルが大きい場合には,CUDAでのコーディングと比べて大幅に作業を減らすこと可能です.
昨年のSC11において,GPUを利用するためのディレクティブベースの並列プログラミング標準規格OpenACCがアナウンスされました.OpenACCは,GPUを使用可能なディレクティブベースのプログラミング環境を提供しているCAPS社,PGI社,Cray社の3社とNVIDIA社によって作られた標準規格で,このOpenACCによる標準化によってこれまでネックとなっていた移植性についてカバーされるため非常に期待されています.このようなディレクティブベースによるGPUのようなmany-coreアプリケーション開発は,これからますます盛り上がるものと思われます.