Upload
nvidia-japan
View
2.126
Download
0
Embed Size (px)
Citation preview
C#, C++/CLI と CUDA による
画像処理ことはじめεπιστημη [email protected]
・Microsoft MVP
for Visual C++ Jan.2004~for Visual Studio and Development Technologies Oct.2015~
・NVIDIA Ambassador for CUDA Apr.2015~
MAXWELL ARCHITECTUREGEFORCE GTX800/900 SERIESGEFORCE GTX750, TEGRA X1
Streaming Multiprocessor■ 128 CUDA-cores
■ L1-cache
■ shared memory
■ …and more
GPU
GPU
memory
L2 cache
PCI
bus
V
I
D
E
O
(だいたいあってる) グラボ の なかみ
Giga Thread Engine
※ ココ↑はそんなに速くない
native(C++) application
NATIVE はフツーにCUDAを呼べるけど…
host
memorydevice
memory
PCI
native app.
コレな。
仲介役
managed
⇔native
managed(C#) application
↑ コレが必要
MANAGED は NATIVE を直接呼べない
host
memorydevice
memory
PCI
CLR
managed app.
コレな。
MANAGED と NATIVE の仲介役
host
memorydevice
memory
PCI
CLR
managed app.
native assembly
call
C++/CLI で作る「仲介役」
見た目(インタフェース)はmanaged
ナカミ(実装)はnative
native assembly
CUDAプログラミングで用意するもの
Graphic-cardNVIDIA-GPU を積んだやつなら大抵OK
Visual Studio 2013 (Community edition でも無問題)
2015はCUDA Toolkitが未対応 (´・ω・`) ショボーン /
CUDA Toolkit 7.5コンパイラ(nvcc)+runtime, ライブラリ, profiler etc. / Visual Studio の add-on
HOST CODE と DEVICE CODE
__host__ __global__ __device__
※ __global__ : host から呼べる device 側の関数
Host(CPU) で動く関数 Device(GPU) で動く関数
CUDAのコードはHOST/DEVICE混在(1)__device__ int device_increment(int n) { return n+1; }
__global__ void kernel_increment(int* data, unsigned int size) {
unsigned int i = blockDim.x * blockIdx.x + threadIdx.x;
if ( i < size ) {
data[i] = device_increment(data[i]);
}
}
__host__ void launch_increment(int* data, unsigned int size) {
kernel_increment<<<2000,100>>>(data, size);
} 100スレッドを1ブロックとして2000ブロック分着火せよ!
CUDAのコードはHOST/DEVICE混在(2)int main() {
vector<int> array; // host-memory
…
size_t bytesize = array.size()*sizeof(int);
int* d_array; // device-memory
cudaMalloc(&d_array, bytesize); // allocate device-memory
// host→device , launch kernel , device→host
cudaMemcpy(d_array, array.data(), bytesize, cudaMemcpyHostToDevice);
launch_increment(d_array, array.size());
cudaMemcpy(array.data(), d_array, bytesize, cudaMemcpyDeviceToHost);
…
cudaFree(d_array); // deallocate device-memory
}
コンパイルのからくり
device
host
nvcc
Visual
C++
PTX
OBJ
~.cu ~.obj
GPU機械語
CPU機械語
Link
CUDA runtime ~.exe
WRAPPERのつくりかた 1: CLR クラスライブラリ
WRAPPERのつくりかた 2: ビルド カスタマイズ
WRAPPERのつくりかた 3: CUDA RUNTIME
WRAPPERのつくりかた 4: 64BIT-BUILD
C++/CLI によるwrapper
• constructor
• allocate device-mem
• methods
• pin managed (raw)
• copy raw → device-mem
• launch kernel
• copy device-mem → raw
• un-pin managed (raw)
• destructor
• deallocate device-mem
managed(C#) application
public ref class Wrapper {
private:
managed側には見せたくない/見せる必要のないもの
public:
// コンストラクタ
Wrapper() { 前準備 }
// デストラクタ
~Wrapper() { this->!Wrapper(); }
// ファイナライザ
!Wrapper() { あとしまつ }
void do_something() {
nativeなナニかを操作する
}
};
public ref class Wrapper {
private:
float* data_; // device-memory
int size_;
public:
// コンストラクタ
Wrapper(int n) : size_(n) {
float* ptr;
cudaMalloc(&ptr, size_*sizeof(float));
data_ = ptr;
}
// デストラクタ
~Wrapper() { this->!Wrapper(); }
// ファイナライザ
!Wrapper() {
cudaFree(data_);
}
…
たとえば…こんなコード。
public ref class Wrapper {
// method
void do_something(cli::array<float>^ buffer) {
if ( buffer->Length <= size_ ) {
pin_ptr<float> pin = &buffer[0];
cudaMemcpy(data_, pin, …); // host -> device
launch_kernel(…); // launch kernel
cudaMemcpy(pin, data_, …); // device -> host
}
}
たとえば…こんなコード。
おまけ: C++/CLIがめんどくせーならこんなのも
http://kunzmi.github.io/managedCuda/
JCuda の .NET 版
DEMO
画像をキャプチャし 処理を施して Windowに表示
Camera Capture
Image Processing
C++/CLI wrapper-1
CUDA
OpenCV
WPF Application
C++/CLI wrapper-2
C#
BGR BGR Gray Gray
SobelV
SobelH
floatuchar3 ucharuchar3
float
float
NPP
cudaMemcpy
BGR
uchar3
THANK YOU, LET’S ENJOY CUDA!
επιστημη
mail: [email protected]
blog: http://blog.zaq.ne.jp/fareastprogramming/
facebook: https://www.facebook.com/cppepisteme
twitter: @epitwit