CUDAをCから呼び出す方法


はじめに

自作ISLispインタプリタ・コンパイラにGPGPUの機能を追加しようとしています。float型の配列データを行列とみなしたCUDA利用の乗算と加算の関数が機能するようになりました。この間、CからCUDAを呼び出す方法について試行錯誤しました。わかったことを書き留めます。

プラットホーム

現在利用している環境はLinux Mint 20.1 です。使用しているNVCCとGCCのバージョンは下記の通りです。

$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2020 NVIDIA Corporation
Built on Mon_Nov_30_19:08:53_PST_2020
Cuda compilation tools, release 11.2, V11.2.67
Build cuda_11.2.r11.2/compiler.29373293_0

externが鍵

Lisp本体が記述されているCコードは従来通り、GCCでコンパイルします。CUDAコードはnvccでコンパイルします。最終的にリンクするときにはnvccをリンカとして使用します。cublasライブラリを使うファイル、後述する 'NVCC'ディレクティブを使うCファイルはnvccでコンパイルしてます。

ポイントはextern宣言です。呼び出される側のCUDAコードにexternを記述します。

kernel.cu  cuda-file
extern "C" void cuda_add(float *a, float *b, float *c, int n);

ifdefの利用

__NVCC__

これが使えます。これによりnvccでコンパイルされているのか、GCCでコンパイルされているのかを判定しつつGPUのために必要なコードを生成しています。

シームレス

Lisp処理系自体にCUDAコードを埋め込んでしまいます。ですから、データ転送のためのタイムロスがありません。ElixirやRuby、Pythonから他言語呼び出しを使う場合には少なからずタイムロスが生じます。Easy-ISLispの場合には処理系をCUDAでコンパイルしてしまいますのでこうした問題が生じません。CUDAをお手軽に利用することができます。これとLispのもつ柔軟性、生産性の高さが合わさるとDeep-Learningの計算実験にいくらかでも寄与できるのではないかと期待しています。

Github

ソースコードはここにおいてあります。gpgpu.cとkernel.cu がGPU利用のためのものです。
https://github.com/sasagawa888/eisl