GPU编程终瞥

到此,经由前三篇文章的说明,我们对gpu编程应该有了很大的认知,基本上可以完成一些简答的开发小任务了,其实cuda的功能还包括很多,这个系列就不一一介绍了,最终篇,我们介绍一下cuda GPU编程在实际工程中的代码调用吧。

cuda是由.cu文件保存的,g++和gcc都不能识别和编译这个,我们要么用nvcc编译,要么像前面一样,通过cmake文件来编译。即便如此,我们的.cu文件也不能直接被.cpp文件调用,我们需要对.cu文件中的函数进行包装,使其成为普通的c family函数,然后我们才能通过头文件在其他函数中调用包装过的函数,完成相应的任务。

接下来我们建立一个add_vector.h、add_vector.cu、 main.cpp、CMakeLists.txt等文件,来完成一个简单的功能。

add_vector.h:

#ifndef __VECTOR_ADD_H__
#define __VECTOR_ADD_H__
#include "cuda.h"
#define N 100

void kernel_wrapper(int *a, int *b, int *c);

#endif

add_vector.cu:

#include "vector_add.h"

__global__ void add(int *a, int *b, int *c){
    int tid = blockIdx.x;
    if(tid<N){
        c[tid] = a[tid] +b[tid];
    }
}

void kernel_wrapper(int *a, int *b, int *c){
    int *dev_a, *dev_b, *dev_c;
    cudaMalloc((void**) &dev_a, N*sizeof(int));
    cudaMalloc((void**) &dev_b, N*sizeof(int));
    cudaMalloc((void**) &dev_c, N*sizeof(int));
    cudaMemcpy(dev_a, a, N*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_b, b, N*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_c, c, N*sizeof(int), cudaMemcpyHostToDevice);

    add<<<N,1>>>(dev_a, dev_b, dev_c);
    cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost);

    cudaFree(dev_a);    
    cudaFree(dev_b);    
    cudaFree(dev_c);   
}

main.cpp:

#include "vector_add.h"
#include<iostream>
using namespace std;

int main(){
    int a[N], b[N], c[N];
    for(int i=0; i<N; i++){
        a[i] = i;
        b[i] = 2;
    }
    kernel_wrapper(a, b, c);
    for(auto item:c){
        cout<<item<<endl;
    }
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)
project(chapter0)

set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")

find_package(CUDA)
#1
CUDA_ADD_LIBRARY(add vector_add.cu)
CUDA_ADD_EXECUTABLE(g main.cpp)
target_link_libraries(g add)
#2
#CUDA_ADD_EXECUTABLE(g main.cpp vector_add.cu)
##target_link_libraries(g ${OpenCV_LIBS})

这里的关键就是.cu语言中对kernel函数的包装,使所有的cuda执行代码都包含在其中,只对外暴露*a、 *b、 *c三个普通的内存指针,伪装成了普通的c famliy函数,所以普通的函数调用它自然是很没问题的。

最后在cmake中,我们甚至可以将.cu函数编译成静态库或者共享库,然后来链接到主程序上。最后执行cmake文件,我们得到需要的二进制文件。

到此,本系列结束。

发表评论

电子邮件地址不会被公开。 必填项已用*标注