C++ AMPによるGPGPU入門 まえがきと環境構築【UNIX/Windows】

More than 1 year has passed since last update.


GPGPUとは

本来3Dグラフィックス用のマシンパーツであるグラフィックボードの計算ユニットのGPUを数値計算に利用しようという技術です.

GPUが数値計算に使えると何が嬉しいのかというと、CPUはシーケンシャルな処理に特化していてif文とかの多い複雑な処理は得意でも、マルチメディア処理のような物量で殴るような処理はとても苦手。そこでその辺りの処理を並列処理専門のGPUにやらせようっていう話。

「計算順序に制限がなく」「単純な演算」であればGPUはそのパフォーマンスをフルに生かすことができます。

GPUの得意な処理といえば例えば,頂点シェーダとかの処理とかを思い浮かべると分かりやすいでしょうか。4*4の行列演算を延々と繰り返すアレですが、やってることは結局要素同士をかけ合わせてるだけですね。しかも順序に依存しない。一行目と二行目の計算順序を逆にしても結果は変わりません。


GPUのすごいところ

1.メモリバンド幅がすごい

2.コア数・スレッド数がすごい

3.演算密度(if文等の少なさ)の高い処理でのパフォーマンスがすごい


GPGPUのつらさ

CUDAやOpenCLなどが有名なGPU APIですが、非常にローレベルな記述になってしまい、デバイスとの通信を意識したプログラムになってしまいます。アクセラレータの抽象度は低く、中々敷居が高いと言えるでしょう。

また、現在はどうか知りませんがC言語のAPIですので、むき出しのメモリを弄り、サイズをとって読み取るようなことが日常茶飯事のように発生します。昔ながらの職人プログラマはそんなもの苦でもないのかもしれませんが、C++で育ち甘やかされた私のような人間にはつらさしかありません。


C++AMPとは

Microsoftが開発したGPGPU向けライブラリです。OpenCLやCUDAのラッパーライブラリのような存在であり、非常に高い抽象度をもってプログラムを記述することができます。

C++11に対応しており、使い慣れたラムダ式をもってGPUにカーネル(GPUで動かすプログラム)を転送することができます。ローカル変数の転送も容易く,GPUに転送するラムダ式でコピーキャプチャ([=])をするだけでGPUにデータを転送することができます(というよりも,関数オブジェクトを丸ごと渡すことができます)。もちろんポインタは無効なため生配列を扱うことはできませんが、多次元配列用のGPU向けのコンテナが用意されており、非常に簡単な記述でカーネルを実行することができます。


C++AMP環境構築


Windows

Windowsの方は喜びましょう。Visual Studioのコンパイラmsvnに最初から組み込まれています。言語拡張も含まれていてAMP専用の構文があるのですが、それらを全て特殊な操作を必要とすることなく実行できます。


UNIX

UNIXベースのOSの方は、kalmarを噛ませることでAMPを利用することが出来ます。

kalmar


Ubuntu

Download



kalmar-<ver>-.deb

licxxamp-<ver>-.deb



を落として

sudo dpkg -i libcxxamp-<version>-Linux.deb kalmar-<version>-Linux.deb

を実行するだけです。簡単。

cmakeやgit等に依存しているぽいので入ってない人はいれておきましょう。

普通のプログラマなら当たり前のように入ってるものばかりです。


MacOSX

brew install http://raw.github.com/ijsung/homebrew/master/Library/Formula/clamp.rb --HEAD

でインストールできるらしい。

私はできませんでした(makeで死ぬ)。OS X Mervericsと書いてあるので、El Capitanの私は無理なのか。


C++ AMP実行

Windowsの方はほんとにいつも通り実行するだけで動くので、UNIXの方向けにkalmar環境下で説明していきます。

まず多分kalmarは/optの下にインストールされてるはずです。

ですので、/opt/kalmar/binにPATHを通してください。このとき優先度が高くないと普通のclang++と競合するかもしれません。

/opt/kalmar/bin/clang++

が目的のコンパイラです。

コンパイルは以下のようにします。

clang++ `clamp-config --install --cxxflags --ldflags` -o test.out test.cpp

clamp-configも/opt/kalmar/binの中にあります。オプションを与えるとコンパイルに必要なオプションを羅列してくれます。

じゃ、お馴染みハローワールドいきましょう。

#include <iostream>

#include <amp.h>
using namespace concurrency;
int main() {
int v[11] = {'G', 'd', 'k', 'k', 'n', 31, 'v', 'n', 'q', 'k', 'c'};

array_view<int> av(11, v);
parallel_for_each(av.get_extent(), [=](index<1> idx) restrict(amp) {
av[idx] += 1;
});

for(unsigned int i = 0; i < av.get_extent().size(); i++)
std::cout << static_cast<char>(av(i));
return 0;
}

文字全体をGPUで並列化してインクリメントしてます。無駄な処理ですが、まあ。

サンプルもkalmarのcppsandboxから引用しました

sample codes

追記:

せっかくなので最低限のCMakeLists構成も置いておきます。

cmake_minimum_required(VERSION 2.8)

SET( CMAKE_CXX_COMPILER /opt/kalmar/bin/clang++)
SET( CMAKE_CXX_FLAGS "-std=c++amp -L/opt/kalmar/lib -Wl,--rpath=/opt/kalmar/lib -lc++ -lcxxrt -ldl -lpthread -Wl,--whole-archive -lmcwamp -Wl,--no-whole-archive -std=c++amp -I/opt/kalmar/include -I/opt/kalmar/include/c++/v1")
add_executable(Main.out
main.cpp
/*ゆっくり増やしていってね!*/
)

実行出来たら今回は終了。

また次回。