2013-07-19 45 views
5

Tôi có ứng dụng hiện có sử dụng lớp C++, trình bao bọc C++ và mã FORTRAN cho các phần tính toán chuyên sâu của ứng dụng. Tôi muốn thực hiện các phần của FORTRAN trong CUDA để tận dụng lợi thế của song song, nhưng tôi vẫn muốn truy cập một số chương trình con, vì vậy tôi cần phải liên kết mã CUDA, C++ và FORTRAN.Tích hợp CUDA vào ứng dụng C++ để sử dụng lớp C++ hiện có

Tôi có ba câu hỏi: 1. Làm cách nào để liên kết chính xác tất cả các tệp đối tượng với Thiết bị đầu cuối Linux và với tệp Makefile (được bao gồm bên dưới)? 2. Cách thích hợp để tham chiếu hàm CUDA trong tiêu đề lớp mà không gây nhầm lẫn cho việc nhận dạng trình biên dịch của thiết bị và mã máy chủ là gì? 3. Chuyển một lớp tới CUDA giống như chuyển một lớp tới bất kỳ mã C bên ngoài nào khác?

Lưu ý: Tôi chưa bao gồm mã đầy đủ (một số trong số đó là khá dài) ngoại trừ Makefile. Nếu tôi cần bao gồm nhiều hơn, vui lòng cho tôi biết.

.h tập tin

#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 wrapper

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

DGCPM::DGCPM(){ 

    initialize(); 
} 


void DGCPM::advance(float dT){ 

    advance_(2Darray[0]); 
} 

tập tin 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 (Lưu ý: "PBO" là mã 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

Liên quan đến câu hỏi thứ ba của bạn, tôi đã có một mã kế thừa được viết bằng C++ và sử dụng các lớp học. Tôi đã quản lý để chuyển mã sang 'CUDA' bằng cách thay đổi tất cả các hoạt động của CPU (thực thi, chuyển động bộ nhớ, vv) thành các hoạt động GPU (hạt nhân,' cudaMemcpy ', vv). – JackOLantern

Trả lời

2

Đây là giải pháp.Để sử dụng mã CUDA, tôi tham khảo nó với, ví dụ,

extern "C" void myfunction_(void) 

Trong tập tin tiêu đề, tôi thêm

void myfunction_(void); 

trong extern nguyên mẫu "C". Trong các chức năng công cộng của lớp tôi đã thêm

void mycudafunction(void); 

Trong C++ wrapper, tôi thêm

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

bây giờ tôi có thể gọi là "myfunction" từ chương trình chính với loại hình này cú pháp

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

Tôi đã sửa đổi Makefile của mình bằng cách thêm myfunction.o vào tất cả các đối tượng của tôi và thêm

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

cho tất cả các hướng dẫn liên kết của tôi.

Để biên dịch, tạo ra các tập tin CUDA đối tượng (myfunction.o), và liên kết, tôi gõ này trong terminal:

nvcc -c myfunction.cu 
make 

Đây là mã chỉnh sửa:

.h tập tin

#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 Wrapper

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

DGCPM::DGCPM(){ 

    initialize(); 
} 


void DGCPM::advance(float dT){ 

    advance_(2Darray[0]); 
} 

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

main.c tập tin

#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 

Đây là chương trình CUDA đơn giản tôi đã sử dụng để kiểm tra.

#include <stdio.h> 

__global__ void kernel(void) { 

} 

extern "C" void myfunction_(void) { 

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


} 
2

Bạn hiện không có bất kỳ mã CUDA nào, vì vậy tôi không thể cung cấp đủ chi tiết.

Đối Qs của bạn:

  1. Linking file đối tượng bao gồm cả mã CUDA đòi hỏi nvcc compiler driver. Trước tiên, bạn có thể biên dịch các tệp mã của mình với các trình biên dịch riêng lẻ, tức là gcc cho .c, g++ cho .cpp, g77 cho .fnvcc cho .cu. Sau đó, bạn có thể sử dụng nvcc để liên kết tất cả các tệp đối tượng .o;
  2. mã máy chủ và thiết bị được khai báo rõ ràng trong tệp .cu với __host____device__. Trách nhiệm của bạn là không gọi mã thiết bị từ mã máy chủ khác;
  3. Tại sao bạn đi qua lớp học đến CUDA? Nếu bạn muốn thay thế mã fortran bằng CUDA, bạn chỉ cần gọi các hàm CUDA trong lớp trình bao bọc C++ của bạn và gọi các hàm CUDA API sử dụng cùng một ngữ pháp như gọi các hàm C++.

Đây là ví dụ từ dự án của tôi. Tệp thi hành được xây dựng với 1 .cu, 1 .cpp, một số extern .a cũng như một số .so. Đối với .cpp tôi sử dụng trình biên dịch của Intel icpc khác với mặc định g++. Xin lưu ý số main() của tôi nằm trong tệp .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

Cảm ơn bạn đã trả lời, Eric. Nó đã giúp tôi đến một giải pháp. Tôi đã bao gồm các tài liệu cho giải pháp của tôi trong câu trả lời của riêng tôi. –