_
OK. Ich habe mir die Beispieldateien nochmal genau angeguckt und bin (endlich) von allein auf die Lösung gekommen. Die möchte ich allen Anfängern natürlich nicht vorenthalten.
Mein erstes Problem war, dass ich C++ und C Code in der main.cpp gemixt habe. CUDA will aber wohl nur reinen C Code sehen. Deshalb habe ich eine Schnittstellenklasse angelegt, in der ich die C-Funktionen, die ich vom C++ Teil aufrufe, exportiere.
Eine weitere Besonderheit ist, dass ihr nicht die kernel_vector_add Objektdatei linken dürft, da ihr sonst eine Fehlermeldung erhaltet, die sich über "duplicate symbol XXXVecAdd_KernelXXX" beschwert.
Summa summarum kommen die folgenden Dateien bei raus.
Makefile
PROJECT=VecAdd
CC=g++
NVCC=nvcc
WARNINGS=#-Wall
INCDIR=-I. -I/usr/local/cuda/include -I/Developer/GPU\ Computing/C/common/inc
LIBDIR=-L/usr/local/cuda/lib
LIBS=-lcublas -lcuda -lcudart -lcufft -ltlshook
OBJ=main.o cpp_kernel_interface.cu.o
$(PROJECT) : $(OBJ)
$(NVCC) -o $(PROJECT) $(OBJ) $(LIBDIR) $(LIBS)
cpp_kernel_interface.cu.o : cpp_kernel_interface.cu
$(NVCC) -c cpp_kernel_interface.cu -o cpp_kernel_interface.cu.o $(INCDIR)
main.o : main.cpp
$(NVCC) -c main.cpp $(WARNINGS) $(INCDIR) -o main.o
main.cpp
#include <iostream>
extern "C" void VecAdd (float *A, float *B, float *C, int numElements);
int main (int argc, char** argv) {
const unsigned int numElements = 100;
const unsigned int vecByteSize = numElements * sizeof(float);
unsigned int i = 0;
float* vecA = new float[vecByteSize];
float* vecB = new float[vecByteSize];
float* vecC = new float[vecByteSize];
for (i = 0; i < numElements; ++i) {
vecA[i] = 1.0f * i;
vecB[i] = 1.0f * i;
vecC[i] = 0.0f;
}
VecAdd(vecA, vecB, vecC, numElements);
for (i = 0; i < numElements; ++i) {
std::cout << vecA[i] << " + " << vecB[i] << " = " << vecC[i] << std::endl;
}
delete vecA;
delete vecB;
delete vecC;
return 0;
}
cpp_kernel_interface.cu
#ifndef __CPP_KERNEL_INTERFACE_CU__
#define __CPP_KERNEL_INTERFACE_CU__
#include <cuda.h>
#include <cutil_inline.h>
#include <kernel_vector_add.cu>
extern "C" void VecAdd (float *A, float *B, float *C, int numElements) {
unsigned int vecByteSize = numElements * sizeof(float);
float* dA = 0;
float* dB = 0;
float* dC = 0;
const int threadsPerBlock = 50;
const int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock;
cudaMalloc((void**)&dA, vecByteSize);
cudaMalloc((void**)&dB, vecByteSize);
cudaMalloc((void**)&dC, vecByteSize);
cudaMemcpy(dA, A, vecByteSize, cudaMemcpyHostToDevice);
cudaMemcpy(dB, B, vecByteSize, cudaMemcpyHostToDevice);
VecAdd_Kernel<<< blocksPerGrid, threadsPerBlock >>>(dA, dB, dC, numElements);
cudaThreadSynchronize();
cudaMemcpy(C, dC, vecByteSize, cudaMemcpyDeviceToHost);
cudaFree(dA);
cudaFree(dB);
cudaFree(dC);
}
#endif
kernel_vector_add.cu
#ifndef __KERNEL_VECTOR_ADD_CU__
#define __KERNEL_VECTOR_ADD_CU__
#include <cuda.h>
#include <cutil_inline.h>
__global__ void VecAdd_Kernel (float *A, float *B, float *C, int numElements) {
const int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < numElements) {
C[i] = A[i] + B[i];
}
}
#endif