Интеграция CUDA в приложение C++ для использования существующего класса C++
У меня есть существующее приложение, которое использует класс C++, оболочку C++ и код FORTRAN для вычислительно интенсивных частей приложения. Я хотел бы реализовать части FORTRAN в CUDA, чтобы воспользоваться преимуществами распараллеливания, но я все равно хотел бы получить доступ к некоторым подпрограммам, поэтому мне нужно связать код CUDA, C++ и FORTRAN.
У меня есть три вопроса: 1. Как правильно связать все объектные файлы с терминалом Linux и с файлом Makefile (входит в комплект ниже)? 2. Как правильно ссылаться на функцию CUDA в заголовке класса без путаницы в распознавании компилятором кода устройства и Хоста? 3. Является ли передача класса в CUDA такой же, как передача класса в любой другой внешний код C?
Примечание: Я не включил полный код (некоторые из них довольно длинные), за исключением файла Makefile. Если мне нужно включить больше, пожалуйста, дайте мне знать..H file
#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]);
}
Главная.C file
#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("%dn",i);
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
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 $@ $^
testDGCPM: $(TESTDGCPM_OBJ)
$(CPP) -o $@ $^ -L ../../amj/lib -lamjMemory -lg2c -lz
clean:
- rm $(ALL_OBJ)
- rm $(INSTALLDIR)/libDGCPM.a
2 ответа:
В настоящее время у вас нет кода CUDA, поэтому я не могу дать достаточно подробностей.
Для вашего Qs:
Вот пример из моего проекта. Исполняемый файл построен с помощью 1
- связывание объектных файлов, в том числе технологии CUDA код требует драйвер компилятора nvcc. Вы можете сначала скомпилировать файлы кода с помощью отдельных компиляторов, т. е.
gcc
для.c
,g++
ибо.cpp
,g77
для.f
иnvcc
для.cu
. Затем вы можете использоватьnvcc
для связывания всех объектных файлов.o
;- код узла и устройства явно объявляется в файле. cu с помощью
__host__
и__device__
. Вы несете ответственность за то, чтобы не вызывать код устройства из другого кода хоста;- Почему вы передаете класс CUDA? Если вы хотите заменить код fortran на CUDA, вам нужно только вызвать функции CUDA в классе-оболочке C++, и вызов функций API CUDA использует ту же грамматику, что и вызов функций c++.
.cu
, 1.cpp
, несколько внешних.a
, а также некоторые.so
. Для.cpp
I используйте компилятор Intelicpc
, отличный от стандартного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
Вот решение. Чтобы использовать код CUDA, я ссылаюсь на него, например,
extern "C" void myfunction_(void)
В заголовочном файле я добавляю
void myfunction_(void);
В прототипах extern "C". В публичных функциях класса I добавлено
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 file
#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_(); }
Главная.C file
#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
Вот простая программа CUDA, которую я использовал для тестирования.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 $@ $^ testDGCPM: $(TESTDGCPM_OBJ) $(CPP) -o $@ $^ -L ../../amj/lib -lamjMemory -lg2c -lz -L /usr/local/cuda/lib -lcuda -lcudart clean: - rm $(ALL_OBJ) - rm $(INSTALLDIR)/libDGCPM.a
#include <stdio.h> __global__ void kernel( void ) { } extern "C" void myfunction_(void) { kernel<<<1,1>>>(); printf( "Hello, World!\n" ); return; }