2015年03月18日

windowsでGPGPUの環境設定

このエントリーをはてなブックマークに追加
follow us in feedly
まずGPUコンピューティングで何が出来るのかというと、
グラフィックボードを並列汎用計算ユニットとして利用する事でCPUでの演算よりも処理を高速化出来ます。これをGPGPU(General-purpose computing on graphics processing units)と言います。

GPUで高速計算させるためにはソフトウェアとハードウェアの深い知識が必要です。条件分岐などがない単調なアルゴリズムを実行する...そういう風にアルゴリズムを組んで大量の演算を行わせるのが正しい使い方であるようです。
ちょっと簡単な処理では高速化が分かるようにはなりません。





また、デバイスとドライバもGPUに対応してる必要があります。


windowsではGPUのハードウェアは、
スタートメニュー「コンピュータ」を右クリック
「管理」をクリック
デバイスマネージャ―> ディスプレイアダプタ

で、確認できます。








環境は色々あります。



CUDA

CUDA TOOLKIT
Developer Drivers for WinVista and Win7 64-bit
CUDA Toolkit
GPU Computing SDK - complete package including all code samples
CUDA Toolkit 4.0 Build Customization BUG FIX Update Fixes

これらをインストールします。

Visual Studio 2008 以上が必要です。



インストールが全部出来ていれば、デスクトップにショートカット NVIDIA GPU Computing SDK 4.0 Browserがあるはずです。
このサンプルが実行出来れば、CUDAの環境が出来ています。



CUDAではvisualstudioではなくプロンプトからコンパイル→実行が出来るのですが

NVIDIA GPU Computing Toolkit\CUDA\v4.0\bin\nvcc.profile
に、
INCLUDES += "-I$(TOP)/include" -I"cuda/C/common/inc" -I"cuda/C/common/lib/Win32" -I"cuda/C/common/bin" -I"cuda/C/common/lib/x64" -I"cuda/shared/inc" $(_SPACE_)

こういう感じに追加します。絶対パスの方が良いかも知れません。

nvcc fatal : Visual Studio configuration file '(null)' could not be found for installation at

これは、単に
nvcc --machine 32 hello_world.cu -o hello_world.exe

こうすればよいのかもしれません。





基本的に、GPGPUプログラムでは、
・カーネル関数の宣言
・デバイスに変数渡
・デバイスから変数受け取り

を明記します。






ソースコードですが、

カーネル関数はこのように起動します。
func<<<grid, block>>>(A , B , C ) ;
カーネル関数が全て終了するには、このように待ちます。
cudaThreadSynchronize();
カーネル関数に渡す変数は、あらかじめデバイス側でメモリを確保しなければいけません
cudaMalloc((void**)&A, matrixSize);

そしてデバイスメモリへ値を渡し
cudaMemcpy(tA, A, matrixSize, cudaMemcpyHostToDevice);
カーネル関数が終わったら、デバイスメモリから値を返します。
cudaMemcpy(hC, C, matrixSize, cudaMemcpyDeviceToHost);


カーネル関数は宣言で __global__を付けます。
__global__ void func( int* A , int* B , int* C){

カーネル関数内の変数 blockIdx blockDim threadIdx から、このブロック、スレッドが何番目なのであるかを識別します。













C++ AMP
これがおそらく設定も実行も一番簡単です。

Visual Studio 2012以降がインストールされていればそれだけで使えるはずです。

ソースファイルからamp.hをインクルードします。
#include <amp.h>

これが、C++AMPのヘッダーファイルです。これだけで、使えます。




array_view< int, 2> a( N, LEN , A), b( N, LEN , B );
GPUへ渡すデータはarray_viewオブジェクトを通します。

extent<2> ex(thread , thread );
exこれをやらないと並列化出来ないです。


parallel_for_each(c.extent.tile< TILE, TILE >(), [=](tiled_index idx) restrict(amp)
parallel_for_each で、並列計算を実行します。 この中に直接コードを書き込みます。

parallel_for_each の前後で変数渡しと受け取りに
c.discard_data(); と
c.synchronize(); が必要ですが、時間計測してるとこれにずいぶん時間かかってるみたいです。











OpenCL
OpenCLが、一番、設定もコードも面倒なので、使いたくないです。

Visual Studio 2012以降が必要です。
https://software.intel.com/en-us/intel-opencl からintel_sdk_for_ocl_applications_2014.....を、ダウンロードしてインストールします



ソリューションエクスプローラのプロジェクト名を右クリック
「プロパティ」
構成プロパティ → C/C++ → 全般 →追加のインクルードディレクトリ
に、 opencl\include を、追加

構成プロパティ → リンカー → 全般 →追加のライブラリディレクトリ
に、opencl\lib\x86

構成プロパティ → リンカー → 入力 →追加の依存ファイル
に、OpenCL.lib; を追加



ソースの方は、
Win32コンソールアプリケーション → 空のプロジェクト
#include<CL/cl.h>

これを入れます。

なんでそういうことしてるのか良くわからないのですが、カーネルコードを外部のテキストファイルに記述する方式です。
__kernel void function(size_t n, __global float* z,__global float* x, __global float* y){
int gid = get_global_id(0);
というカーネルを文字列でファイルに書いて、そのファイルを
こうやって呼び出します。

int main(void){
const char filename[] = "./kernel.cl"; //カーネルファイル
..........
FILE* fp;
fopen_s(&fp, filename, "r");
..........
char* source_str = (char*)malloc(MAX_SOURCE_SIZE);
std::size_t source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp);
..........
program = clCreateProgramWithSource(context, 1, (const char**)&source_str,(const size_t*)&source_size, &ret);
//Compile of kernel's source code
ret = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);
//Create Kernel object
kernel = clCreateKernel(program, "function", &ret);





ret = clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL);

で、並列処理を実行に移してます?

cl_int clEnqueueNDRangeKernel(
cl_command_queue command_queue,
cl_kernel kernel,
cl_uint work_dim,
const size_t *global_work_offset,
const size_t *global_work_size,
const size_t *local_work_size,
cl_uint num_events_in_wait_list,
const cl_event *event_wait_list,
cl_event *event
)

command_queueは実行を受け持つコマンドキューです。(ですから、直ちには実行されません。)
kernelは実行するカーネル関数です。
work_dimは実行するスレッド群の次元です。1~CL_DEVICE_MAX_WORK_ITEM_DIMENSIONSまでの値を取ることが出来ます。
global_work_offsetはグローバルIDのオフセットです。NULLでも構いません。
global_work_sizeは全スレッドの量を表します。
local_work_sizeは1グループのスレッドの量を表します。
num_events_in_wait_listとevent_wait_listは、この実行コマンドを実行にうつす前にすでに起きていなければいけないイベントのリストを表します。
eventは、このコマンドが実行されたことを知らせるイベントを返します。NULLでも構いません。



トラックバックURL

コメントする

名前:
URL:
  情報を記憶: 評価:  顔   星
 
 
 
サイト内検索
にほんブログ村 科学ブログへ
にほんブログ村
adsense
Archives
amazon
blogchart
QRコード
QRコード
Recent Comments