2013-07-19 5 views
5

私はアプリケーションの計算集約的な部分にC++クラス、C++ラッパー、およびFORTRANコードを使用する既存のアプリケーションを持っています。私は並列化を利用するためにCUDAでFORTRANの一部を実装したいと思いますが、私はまだサブルーチンのいくつかにアクセスしたいので、CUDA、C++、FORTRANのコードをリンクする必要があります。既存のC++クラスを使用するC++アプリケーションへのCUDAの統合

私は3つの質問を持っています: 1.すべてのオブジェクトファイルをLinux TerminalとMakefile(以下に含まれています)と正しくリンクするにはどうしたらいいですか? 2.コンパイラのデバイスとホストコードの認識を混乱させることなく、クラスヘッダのCUDA関数を参照する適切な方法は何ですか? 3.他の外部のCコードにクラスを渡すのと同じように、クラスをCUDAに渡していますか?

注:Makefileを除いて、完全なコードは含まれていません(かなり長いものもあります)。もっと含める必要がある場合は、教えてください。

.hファイル

#ifndef _DGCPM_H_ 
#define _DGCPM_H_ 

extern "C"{ 

#include <string.h> 
#include <zlib.h> 
#include <math.h> 

} 

/* Prototypes of Fortran subroutines */ 
extern "C" { 
    void initialize_(float *2Darray); 
    void advance_(float *2Darray); 
    //Want "advance" to be implemented in CUDA 
} 

/* Proper prototype of CUDA call? */ 
//extern "C" void cudaadvance(float *2Darray); 

class DGCPM{ 

public: 
    DGCPM(); /* Initialized with defaults setup */ 
    ~DGCPM(); /* Free memory */ 

    void advance(float dT); /* Advance model dT seconds */ 

private: 

    float **2Darray; 
    void initialize(float **2Darray); 

}; 

#endif 

.Cラッパー

#include "../include/DGCPM.h" 

DGCPM::DGCPM(){ 

    initialize(); 
} 


void DGCPM::advance(float dT){ 

    advance_(2Darray[0]); 
} 

MAIN.Cファイル

#include <stdlib.h> 
#include <stdio.h> 
#include <zlib.h> 

#include "../include/DGCPM.h" 

int main(){ 

    class DGCPM *model; 
    model=new class DGCPM(); 

//Write data to class from a file, then 

    for(int i=0;i<200;i++){ 
    printf("%d\n",i); 
    model->advance(3600); 
    //write model state to file; 
    } 

//Close file 

    return 0; 
} 

のMakefile(注: "PBO" はFORTRANコードである)

INSTALLDIR=../../lib/ 

FLAGS=-Wall -g -I ../../amj/include 
CFLAGS=$(FLAGS) 
CPPFLAGS=$(FLAGS) 
FFLAGS=$(FLAGS) 

CPP=g++ 
CC=gcc 
FC=g77 

PBO_PATH=../ober/for/ 
VPATH=$(PBO_PATH) 

DGCPM_OBJ=DGCPM.o pbo.o 
TESTDGCPM_OBJ=testDGCPM.o DGCPM.o pbo.o 

ALL_OBJ=$(TESTDGCPM_OBJ) 

install: all 
    mkdir -p $(INSTALLDIR) 
    cp libDGCPM.a $(INSTALLDIR) 

all: libDGCPM.a testDGCPM 

libDGCPM.a: $(DGCPM_OBJ) 
    ar rc [email protected] $^ 

testDGCPM: $(TESTDGCPM_OBJ) 
    $(CPP) -o [email protected] $^ -L ../../amj/lib -lamjMemory -lg2c -lz 

clean: 
    - rm $(ALL_OBJ) 
    - rm $(INSTALLDIR)/libDGCPM.a 
+0

3番目の質問について、私はC++で書かれたレガシーコードを使用していました。私は、GPU操作(カーネル、 'cudaMemcpy'など)にすべてのCPU操作(実行、メモリ移動など)を変更するだけで、コードを' CUDA'に移植することができました。 – JackOLantern

答えて

2

ここに解決策があります。CUDAコードを使用するために、私は、ヘッダファイルに、例えば、

extern "C" void myfunction_(void) 

でそれを参照し、IはEXTERN "C" プロトタイプで

void myfunction_(void); 

を加えます。私はC++ラッパーで

void mycudafunction(void); 

を追加したクラスの公開機能では、私は今の構文

model = new class DGCPM(); 
model->mycudafunction(); 
このタイプのメインプログラムから「MyFunctionを」を呼び出すことができます

void DGCPM::mycudafunction(){ 
myfunction_(); 
} 

を追加します

すべてのオブジェクトにmyfunction.oを追加して追加することで自分のMakefileを変更しました。

-L /usr/local/cuda/lib -lcuda -lcudart 

すべてのリンクの指示に。 、コンパイルCUDAオブジェクトファイル(myfunction.o)、およびリンクを作成し、Iは、端末でこれを入力する

.hファイル

:ここ

nvcc -c myfunction.cu 
make 

が変更されたコードであります

#ifndef _DGCPM_H_ 
#define _DGCPM_H_ 

extern "C"{ 

#include <string.h> 
#include <zlib.h> 
#include <math.h> 

} 

/* Prototypes of Fortran subroutines */ 
extern "C" { 
    void initialize_(float *2Darray); 
    void advance_(float *2Darray); 
    /*CUDA prototype, can be changed to "cudaadvance" or the like*/ 
    void myfunction_(void); 

} 

class DGCPM{ 

public: 
    DGCPM(); /* Initialized with defaults setup */ 
    ~DGCPM(); /* Free memory */ 

    void advance(float dT); /* Advance model dT seconds */ 
    void mycudafunction(void); 
private: 

    float **2Darray; 
    void initialize(float **2Darray); 

}; 

#endif 

.Cラッパー

#include "../include/DGCPM.h" 

DGCPM::DGCPM(){ 

    initialize(); 
} 


void DGCPM::advance(float dT){ 

    advance_(2Darray[0]); 
} 

void DGCPM::mycudafunction(){ 
    myfunction_(); 
} 

のmain.cファイル

#include <stdlib.h> 
#include <stdio.h> 
#include <zlib.h> 

#include "../include/DGCPM.h" 

int main(){ 

    class DGCPM *model; 
    model=new class DGCPM(); 

//Write data to class from a file, then 

    for(int i=0;i<200;i++){ 
    printf("%d\n",i); 
    model->mycudafunction(); 
    model->advance(3600); 
    //write model state to file; 
    } 

//Close file 

    return 0; 
} 

Makefileの

INSTALLDIR=../../lib/ 

FLAGS=-Wall -g -I ../../amj/include 
CFLAGS=$(FLAGS) 
CPPFLAGS=$(FLAGS) 
FFLAGS=$(FLAGS) 

CPP=g++ 
CC=gcc 
FC=g77 

PBO_PATH=../ober/for/ 
VPATH=$(PBO_PATH) 

DGCPM_OBJ=DGCPM.o pbo.o myfunction.o 
TESTDGCPM_OBJ=testDGCPM.o DGCPM.o pbo.o myfunction.o 

ALL_OBJ=$(TESTDGCPM_OBJ) 

install: all 
    mkdir -p $(INSTALLDIR) 
    cp libDGCPM.a $(INSTALLDIR) 

all: libDGCPM.a testDGCPM 

libDGCPM.a: $(DGCPM_OBJ) 
    ar rc [email protected] $^ 

testDGCPM: $(TESTDGCPM_OBJ) 
    $(CPP) -o [email protected] $^ -L ../../amj/lib -lamjMemory -lg2c -lz -L /usr/local/cuda/lib -lcuda -lcudart 

clean: 
    - rm $(ALL_OBJ) 
    - rm $(INSTALLDIR)/libDGCPM.a 

は、ここで私がテストするために使用される単純なCUDAプログラムです。

#include <stdio.h> 

__global__ void kernel(void) { 

} 

extern "C" void myfunction_(void) { 

    kernel<<<1,1>>>(); 
    printf("Hello, World!\n"); 
    return; 


} 
2

現在、CUDAコードはありませんので、詳細を十分に伝えられない場合があります。あなたのQsのために

:CUDAコードを含むオブジェクトファイルをリンクする

  1. nvcc compiler driverが必要です。あなたは、まず個々のコンパイラ、つまり.cためgccg++.cppため、g77.f用と.cuためnvccを使用してコードファイルをコンパイルすることができます。次に、nvccを使用して、すべてのオブジェクトファイルをリンクすることができます.o;
  2. ホストコードとデバイスコードは、__host____device__の.cuファイルで明示的に宣言されています。他のホストコードからデバイスコードを呼び出さないようにするのはあなたの責任です。
  3. CUDAにクラスを渡すのはなぜですか? FortranコードをCUDAに置き換える場合は、C++ラッパークラスでCUDA関数を呼び出すだけで、CUDA API関数を呼び出すと、C++関数を呼び出すのと同じ文法が使用されます。

ここは私のプロジェクトの例です。実行可能ファイルは、1 .cu,、いくつかのextern .aと同様に.soで構築されています。 .cppについては、デフォルトのg++以外のインテルのコンパイラicpcを使用します。私のmain().cuファイルにあります。

# Compile : bin.cu/b-rbm-gpu.cu 
nvcc -ftz true -ccbin icpc -Xcompiler "-Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237" -O3 -Xcompiler "-O3" -gencode arch=compute_20,code=sm_20 -Ilib -c -o bin.cu/b-rbm-gpu.o bin.cu/b-rbm-gpu.cu 
# Compile : lib/KTiming.cpp 
icpc -Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237 -O3 -MMD -Ilib -c -o lib/KTiming.o lib/KTiming.cpp 
# Link : bin.cu/b-rbm-gpu 
nvcc -ftz true -ccbin icpc -Xcompiler "-Wall -Wno-long-long -ansi -pedantic -ansi-alias -parallel -fopenmp -openmp-link=static -static-intel -wd10237" -O3 -Xcompiler "-O3" -Ilib -Llib bin.cu/b-rbm-gpu.o lib/KTiming.o -lpthread -lm /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_intel_lp64.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_intel_thread.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_core.a /opt/intel/composer_xe_2013.1.117/mkl/lib/intel64/libmkl_core.a -lcublas -lcurand -lcusparse -o bin.cu/b-rbm-gpu 
+0

応答をありがとう、Eric。それは私が解決策に到達するのを助けました。私自身の答えに私の解決のためのドキュメントを含めました。 –

関連する問題