CUDA 10.1をインストールし、サンプルプログラムをビルドしてみました。
CUDA プログラミング CUDA 10.1のインストールと付属サンプルのビルド&実行実際にプログラムを作成してみます。
こちらを参考に「Hello World」を表示してみます。
Tutorial 01: Say Hello to CUDAnvcc
コンパイルには「nvcc」というコマンドを実行します。
実体は「/usr/local/cuda-10.1/bin/nvcc」
パスが通っていなかったので設定しておきました。
$ vi ~/.bash_profile
内容は
https://docs.nvidia.com/cuda/cuda-quick-start-guide/index.html上記の記載に従います。
export PATH=/usr/local/cuda-10.1/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-10.1/lib64\${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
内容を反映。
$ source ~/.bash_profile
これで準備完了です。
Hello World
チュートリアルに、C言語との比較が掲載されています。
・C言語
- void c_hello(){
- printf("Hello World!\n");
- }
- int main() {
- c_hello();
- return 0;
- }
・CUDA
- __global__ void cuda_hello(){
- printf("Hello World from GPU!\n");
- }
- int main() {
- cuda_hello<<<1,1>>>();
- return 0;
- }
「__global__」はGPU呼び出し。
「<<<...>>>」の部分は次節で説明とのことなので、そういうものだと思っておきます。
「main」がkernelsと呼ばれる部分での実行になるとのこと。
https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.htmlここの解説を見ると、kernelsからGPU関数の呼び出しが行われるようです。
CUDA Tutorialこちらを見ると、kernelsはhost(≒CPU)で実行されるという理解で良いのかもしれません。
CUDAのサンプルプログラムを「hello.cu」という名前で保存します。
・hello.cu
- #include <stdio.h>
- __global__ void cuda_hello(){
- printf("Hello World from GPU!\n");
- }
- int main() {
- cuda_hello<<<1,1>>>();
- return 0;
- }
nvccでコンパイル。
$ nvcc hello.cu -o hello
実行してみます。
$ ./hello
...が何も表示されず。
特にエラーも表示されないので、これが正しい実行結果なのでしょうか。
とりあえずチュートリアルを先に進めます。
GPUによる演算
同じ長さの2つの配列の中身を加算し、1つの配列にまとめる処理をサンプルとします。
・vector_add.c
- #include <stdio.h>
- #include <stdlib.h>
- #define N 10000000
- void vector_add(float *out, float *a, float *b, int n) {
- for(int i = 0; i < n; i++){
- out[i] = a[i] + b[i];
- }
- }
- int main(){
- float *a, *b, *out;
- // Allocate memory
- a = (float*)malloc(sizeof(float) * N);
- b = (float*)malloc(sizeof(float) * N);
- out = (float*)malloc(sizeof(float) * N);
- // Initialize array
- for(int i = 0; i < N; i++){
- a[i] = 1.0f; b[i] = 2.0f;
- }
- // Main function
- vector_add(out, a, b, N);
- printf("%f\n", out[0]);
- }
ビルドして実行
$ g++ vector_add.c -o vector_add_c
$ ./vector_add_c
3.000000
このプログラムをGPU版に変更してみます。
・vector_add.cu
- #include <stdio.h>
- #include <stdlib.h>
- #include <cuda.h>
- #include <cuda_runtime.h>
- #define N 10000000
- __global__ void vector_add(float *out, float *a, float *b, int n) {
- for(int i = 0; i < n; i++){
- out[i] = a[i] + b[i];
- }
- }
- int main(){
- float *a, *b, *out;
- float *d_a, *d_b, *d_out;
- // Allocate memory
- a = (float*)malloc(sizeof(float) * N);
- b = (float*)malloc(sizeof(float) * N);
- out = (float*)malloc(sizeof(float) * N);
- // Initialize array
- for(int i = 0; i < N; i++){
- a[i] = 1.0f; b[i] = 2.0f;
- }
-
- // Allocate device memory
- cudaMalloc((void**)&d_a, sizeof(float) * N);
- cudaMalloc((void**)&d_b, sizeof(float) * N);
- cudaMalloc((void**)&d_out, sizeof(float) * N);
- // Transfer data from host to device memory
- cudaMemcpy(d_a, a, sizeof(float) * N, cudaMemcpyHostToDevice);
- cudaMemcpy(d_b, b, sizeof(float) * N, cudaMemcpyHostToDevice);
- // Executing kernel
- vector_add<<<1,1>>>(d_out, d_a, d_b, N);
- // Transfer data back to host memory
- cudaMemcpy(out, d_out, sizeof(float) * N, cudaMemcpyDeviceToHost);
- printf("%f\n", out[0]);
- // Deallocate device memory
- cudaFree(d_a);
- cudaFree(d_b);
- cudaFree(d_out);
- // Deallocate host memory
- free(a);
- free(b);
- free(out);
- }
ビルドと実行
$ nvcc vector_add.cu -o vector_add_cuda
$ ./vector_add_cuda
3.000000
あまり意味のない計算ですが、動いてくれたようです。
なんとなく理解したことは
・devide(GUP)で演算に使用するメモリは「cudaMalloc」で確保する。
・メモリの開放は「cudaFree」
・cudaMemcpyで、kernel領域のメモリをdevice領域にコピーして利用する。
・deviceの演算結果はcudaMemcpyでdevice領域からkernel領域にコピーして利用する。
次回はもう少し実用的な演算を試してみたいと思います。
【参考URL】
Tutorial 01: Say Hello to CUDACUDA Tutorialhttps://docs.nvidia.com/cuda/cuda-c-programming-guide/index.htmlhttps://docs.nvidia.com/cuda/cuda-samples/index.htmlhttps://docs.nvidia.com/cuda/cuda-quick-start-guide/index.html