У меня есть проект c ++, в котором я вызываю ядро cuda с помощью функции-оболочки.
Мой файл c ++ выглядит следующим образом (это extern.cc ):
#include "extern.h"
#include "qc/operator.h"
#include "qc/quStates.h"
#include "gpu.h"
...
ROUTINE(ext_bit) {
int i;
quState *qbit;
PAR_QUSTATE(q,"q");
opBit *op;
tComplex I(0,1);
tComplex sg= inv ? -1 : 1;
char c=(def->id())[0];
if(def->id().length()!=1) c='?';
switch(c) {
case 'H': op=new opBit(1,1,1,-1,sqrt(0.5)); break;
case 'X': op=new opBit(0,1,1,0); break;
case 'Y': op=new opBit(0,-I,I,0); break;
case 'Z': op=new opBit(1,0,0,-1); break;
case 'S': op=new opBit(1,0,0,sg*I); break;
case 'T': op=new opBit(1,0,0,sqrt(0.5)+sg*sqrt(0.5)*I); break;
case '?':
default: EXTERR("unknown single qubit operator "+def->id());
}
// This is where I call my wrapper function
// the error that I get is: expected primary-expression before ',' token
gpucaller(opBit, q);
qcl_delete(op);
return 0;
}
где "gpucaller" - это моя функция-оболочка, которая вызывает ядро, оба определены в cuda_kernel.cu :
/* compiling with:
nvcc -arch sm_11 -c -I"/home/glu/NVIDIA_GPU_Computing_SDK/C/common/inc" -I"." -I"./qc" -I"/usr/local/cuda/include" -o cuda_kernel.o cuda_kernel.cu
*/
#ifndef _CUDA_KERNEL_H_
#define _CUDA_KERNEL_H_
#define MAX_QUBITS 25
#define BLOCKDIM 512
#define MAX_TERMS_PER_BLOCK (2*BLOCKDIM)
#define THREAD_MASK (~0ul << 1)
// includes
#include <cutil_inline.h>
#include "gpu.h"
__constant__ float devOpBit[2][2];
__global__ void qcl1(cuFloatComplex *a, int N, int qbCount, int blockGrpSize, int k)
{
//int idx = blockIdx.x * BLOCKDIM + threadIdx.x;
//int tx = threadIdx.x;
cuFloatComplex t0_0, t0_1, t1_0, t1_1;
int x0_idx, x1_idx;
int i, grpSize, b0_idx, b1_idx;
__shared__ cuFloatComplex aS[MAX_TERMS_PER_BLOCK];
...
}
void gpucaller(opBit* op, quBaseState* q) {
// make an operator copy
float** myOpBit = (float**)op->getDeviceReadyOpBit();
unsigned int timer = 0;
cuFloatComplex *a_d;
long int N = 1 << q->mapbits();
int size = sizeof(cuFloatComplex) * N;
// start timer
cutilCheckError( cutCreateTimer( &timer));
cutilCheckError( cutStartTimer( timer));
// allocate device memory
cudaMalloc((void**)&a_d,size);
// copy host memory to device
cudaMemcpy(a_d, q->termsarray, size, cudaMemcpyHostToDevice);
// copy quantic operator to constant memory
cutilSafeCall( cudaMemcpyToSymbol(devOpBit, myOpBit, 2*sizeof(float[2]), 0) );
printf("Cuda errors: %s\n", cudaGetErrorString( cudaGetLastError() ) );
// setup execution parameters
dim3 dimBlock(BLOCKDIM, 1, 1);
int n_blocks = N/MAX_TERMS_PER_BLOCK + (N%MAX_TERMS_PER_BLOCK == 0 ? 0:1);
dim3 dimGrid(n_blocks, 1, 1);
...
// execute the kernel
qcl1<<< dimGrid, dimBlock >>>(a_d, N, gates, blockGrpSize, k);
// check if kernel execution generated and error
cutilCheckMsg("Kernel execution failed");
...
// copy result from device to host
cudaMemcpy(q->termsarray, a_d, size, cudaMemcpyDeviceToHost);
// stop timer
cutilCheckError( cutStopTimer( timer));
//printf( "GPU Processing time: %f (ms)\n", cutGetTimerValue( timer));
cutilCheckError( cutDeleteTimer( timer));
// cleanup memory on device
cudaFree(a_d);
cudaThreadExit();
}
#endif // #ifndef _CUDA_KERNEL_H_
и " gpu.h " имеет следующее содержание:
#ifndef _GPU_H_
#define _GPU_H_
#include "qc/operator.h"
#include "qc/qustates.h"
void gpucaller(opBit* op, quBaseState* q);
#endif // #ifndef _GPU_H_
Я не включаю файл .cu в свой файл c ++, я включаю только файл .h (gpu.h - содержит прототип функции вызова в ядре) как в файлы c ++, так и в файлы .cu.
Я компилирую файл .cu с помощью nvcc и связываю полученный файл .o с файлом Makefile моего проекта.
Также я не забыл добавить флаг «-lcudart» в Makefile.
Проблема в том, что когда я компилирую свой основной проект, я получаю эту ошибку:
expected primary-expression before ',' token
и ссылается на строку в extern.cc , где я вызываю функцию "gpucaller".
Кто-нибудь знает, как сделать это правильно?
EDIT: я попытался снова скомпилировать, на этот раз удалив аргументы из определения функции gpucaller (и, очевидно, не передавая никакие аргументы в функцию, что неправильно, потому что мне нужно для передачи аргументов). Скомпилировано просто отлично.
Итак, проблема в том, что gpucaller типы аргументов не распознаются, я понятия не имею, почему (я включил заголовки, в которых объявлены типы аргументов, т.е. "qc / operator. h "и" qc / quStates.h "). У кого-нибудь есть решение этого?
Makefile моего проекта:
VERSION=0.6.3
# Directory for Standard .qcl files
QCLDIR = /usr/local/lib/qcl
# Path for qcl binaries
QCLBIN = /usr/local/bin
ARCH = `g++ -dumpmachine || echo bin`
# Comment out if you want to compile for a different target architecture
# To build libqc.a, you will also have to edit qc/Makefile!
#ARCH = i686-linux
#ARCHOPT = -m32 -march=i686
# Debugging and optimization options
#DEBUG = -g -pg -DQCL_DEBUG -DQC_DEBUG
#DEBUG = -g -DQCL_DEBUG -DQC_DEBUG
DEBUG = -O2 -g -DQCL_DEBUG -DQC_DEBUG
#DEBUG = -O2
# Plotting support
#
# Comment out if you don't have GNU libplotter and X
PLOPT = -DQCL_PLOT
PLLIB = -L/usr/X11/lib -lplotter
# Readline support
#
# Comment out if you don't have GNU readline on your system
# explicit linking against libtermcap or libncurses may be required
RLOPT = -DQCL_USE_READLINE
#RLLIB = -lreadline
RLLIB = -lreadline -lncurses
# Interrupt support
#
# Comment out if your system doesn't support ANSI C signal handling
IRQOPT = -DQCL_IRQ
# Replace with lex and yacc on non-GNU systems (untested)
LEX = flex
YACC = bison
INSTALL = install
##### You shouldn't have to edit the stuff below #####
DATE = `date +"%y.%m.%d-%H%M"`
QCDIR = qc
QCLIB = $(QCDIR)/libqc.a
QCLINC = lib
#CXX = g++
#CPP = $(CC) -E
CXXFLAGS = -c $(ARCHOPT) -Wall $(DEBUG) $(PLOPT) $(RLOPT) $(IRQOPT) -I$(QCDIR) -DDEF_INCLUDE_PATH="\"$(QCLDIR)\""
LDFLAGS = $(ARCHOPT) -L$(QCDIR) $(DEBUG) $(PLLIB) -lm -lfl -lqc $(RLLIB) -L"/usr/local/cuda/lib" -lcudart
FILESCC = $(wildcard *.cc)
FILESH = $(wildcard *.h)
SOURCE = $(FILESCC) $(FILESH) qcl.lex qcl.y Makefile
OBJECTS = types.o syntax.o typcheck.o symbols.o error.o \
lex.o yacc.o print.o quheap.o extern.o eval.o exec.o \
parse.o options.o debug.o cond.o dump.o plot.o format.o cuda_kernel.o
all: do-it-all
ifeq (.depend,$(wildcard .depend))
include .depend
do-it-all: build
else
do-it-all: dep
$(MAKE)
endif
#### Rules for depend
dep: lex.cc yacc.cc yacc.h $(QCLIB)
for i in *.cc; do \
$(CPP) -I$(QCDIR) -MM $$i; \
done > .depend
lex.cc: qcl.lex yacc.h
$(LEX) -olex.cc qcl.lex
yacc.cc: qcl.y
$(YACC) -t -d -o yacc.cc qcl.y
yacc.h: yacc.cc
mv yacc.*?h yacc.h
$(QCLIB):
cd $(QCDIR) && $(MAKE) libqc.a
#### Rules for build
build: qcl $(QCLINC)/default.qcl
qcl: $(OBJECTS) qcl.o $(QCLIB)
$(CXX) $(OBJECTS) qcl.o $(LDFLAGS) -o qcl
$(QCLINC)/default.qcl: extern.cc
grep "^//!" extern.cc | cut -c5- > $(QCLINC)/default.qcl
checkinst:
[ -f ./qcl -a -f $(QCLINC)/default.qcl ] || $(MAKE) build
install: checkinst
$(INSTALL) -m 0755 -d $(QCLBIN) $(QCLDIR)
$(INSTALL) -m 0755 ./qcl $(QCLBIN)
$(INSTALL) -m 0644 ./$(QCLINC)/*.qcl $(QCLDIR)
uninstall:
-rm -f $(QCLBIN)/qcl
-rm -f $(QCLDIR)/*.qcl
-rmdir $(QCLDIR)
#### Other Functions
edit:
nedit $(SOURCE) &
clean:
rm -f *.o lex.* yacc.*
cd $(QCDIR) && $(MAKE) clean
clear: clean
rm -f qcl $(QCLINC)/default.qcl .depend
cd $(QCDIR) && $(MAKE) clear
dist-src: dep
mkdir qcl-$(VERSION)
cp README CHANGES COPYING .depend $(SOURCE) qcl-$(VERSION)
mkdir qcl-$(VERSION)/qc
cp qc/Makefile qc/*.h qc/*.cc qcl-$(VERSION)/qc
cp -r lib qcl-$(VERSION)
tar czf qcl-$(VERSION).tgz --owner=0 --group=0 qcl-$(VERSION)
rm -r qcl-$(VERSION)
dist-bin: build
mkdir qcl-$(VERSION)-$(ARCH)
cp Makefile README CHANGES COPYING qcl qcl-$(VERSION)-$(ARCH)
cp -r lib qcl-$(VERSION)-$(ARCH)
tar czf qcl-$(VERSION)-$(ARCH).tgz --owner=0 --group=0 qcl-$(VERSION)-$(ARCH)
rm -r qcl-$(VERSION)-$(ARCH)
upload: dist-src
scp qcl-$(VERSION)*.tgz oemer@tph.tuwien.ac.at:html/tgz
scp: dist-src
scp qcl-$(VERSION).tgz oemer@tph.tuwien.ac.at:bak/qcl-$(DATE).tgz
Единственное изменение, которое я добавил в исходный Makefile, - это добавление «cuda_kernel.o» в строку OBJECTS и добавление флага «-lcudart» в LDFLAGS.
ОБНОВЛЕНИЕ: Спасибо Гаррисм за помощь мне. Я передавал тип в качестве параметра.