2013-07-19 44 views
5

我有一個現有的應用程序,它使用C++類,C++包裝器和FORTRAN代碼作爲應用程序的計算密集型部分。我想在CUDA中實現部分FORTRAN以利用並行化,但我仍然想訪問一些子例程,所以我需要鏈接CUDA,C++和FORTRAN代碼。將CUDA集成到C++應用程序中以使用現有的C++類

我有三個問題: 1.我如何正確鏈接所有目標文件與Linux終端和Makefile(下面包含)? 2.在類頭中引用CUDA函數的正確方法是什麼,而不會混淆編譯器對設備和主機代碼的識別? 3.將類傳遞給CUDA就像將類傳遞給其他任何外部C代碼一樣?

注意:除了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

關於你的第三個問題,我用C++編寫了一個遺留代碼並使用類。通過將所有CPU操作(執行,存儲器移動等)更改爲GPU操作(內核,'cudaMemcpy'等),我設法將代碼移植到'CUDA'。 – JackOLantern

回答

2

這是解決方案。要使用CUDA代碼,我引用它,例如,

extern "C" void myfunction_(void) 

在頭文件,我在外部的 「C」 的原型添加

void myfunction_(void); 

。在類的公共職能,我添加

void mycudafunction(void); 

在C++包裝,我想補充

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

我現在可以叫「myfunction的」主程序這種類型的語法

model = new class DGCPM(); 
model->mycudafunction(); 

我修改了我的Makefile,將myfunction.o添加到我的所有對象中,然後添加

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

到我所有的鏈接指令。

要編譯,創建CUDA對象文件(myfunction.o)和鏈接,我在終端輸入:

nvcc -c myfunction.cu 
make 

這裏是修改後的代碼:

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); 
    /*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的:

  1. 鏈接對象文件,包括CUDA代碼需要nvcc compiler driver。你可以先編譯代碼的文件有獨立的編譯,即gcc.cg++.cppg77.fnvcc.cu。然後你可以使用nvcc鏈接所有的目標文件.o;
  2. 主機和設備代碼在.cu文件中明確聲明爲__host____device__。您有責任不從其他主機代碼調用設備代碼;
  3. 爲什麼你要通過CUDA課程?如果您想用CUDA替換fortran代碼,則只需調用C++包裝類中的CUDA函數,調用CUDA API函數就會使用與調用C++函數相同的語法。

這是我的項目的一個例子。可執行文件使用1 .cu,1 .cpp,幾個外部文件.a以及一些.so。對於.cpp我使用英特爾的編譯器icpc而不是默認的g++。請注意我的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。它幫助我找到了解決方案。我在自己的答案中包含了我的解決方案的文檔。 –

相關問題