【问题标题】:Integrating CUDA into a C++ application to use existing C++ class将 CUDA 集成到 C++ 应用程序中以使用现有的 C++ 类
【发布时间】:2013-07-23 05:16:06
【问题描述】:

我有一个现有的应用程序,它使用 C++ 类、C++ 包装器和 FORTRAN 代码来处理应用程序的计算密集部分。我想在 CUDA 中实现部分 FORTRAN 以利用并行化,但我仍然想访问一些子例程,因此我需要链接 CUDA、C++ 和 FORTRAN 代码。

我有三个问题: 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 $@ $^

testDGCPM: $(TESTDGCPM_OBJ)
    $(CPP) -o $@ $^ -L ../../amj/lib -lamjMemory -lg2c -lz

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

【问题讨论】:

  • 关于您的第三个问题,我有一个用 C++ 编写并使用类的遗留代码。通过将所有 CPU 操作(执行、内存移动等)更改为 GPU 操作(内核、cudaMemcpys 等),我已经设法将代码移植到 CUDA

标签: c++ cuda fortran


【解决方案1】:

您目前没有任何 CUDA 代码,所以我可能无法提供足够的详细信息。

对于您的问题:

  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

【讨论】:

  • 感谢您的回复,埃里克。它帮助我找到了解决方案。我在自己的答案中包含了我的解决方案的文档。
【解决方案2】:

这里是解决方案。为了使用 CUDA 代码,我引用它,例如,

extern "C" void myfunction_(void)

在头文件中,我添加

void myfunction_(void);

在外部“C”原型中。在我添加的类的公共函数中

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;
}

生成文件

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

这是我用来测试的简单 CUDA 程序。

#include <stdio.h>

__global__ void kernel( void ) {

}

extern "C" void myfunction_(void) {

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


}

【讨论】:

    猜你喜欢
    • 2021-11-21
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 2010-09-23
    • 2016-08-27
    • 1970-01-01
    • 2017-05-02
    相关资源
    最近更新 更多