[gelöst] Erste Schritte mit CUDA - Compilerfehler



  • Hallo allerseits,

    ich setze mich gerade mit CUDA auseinander und verzweifel langsam.

    Mein erstes Programm soll einfach zwei Vektoren mit jeweils n Elementen addieren und in einen dritten schreiben.
    Der Quelltext ist in zwei Dateien aufgeteilt: zum Einen die main.cpp und die kernel_vector_add.cu. Die Quelltexte sind unten aufgelistet.
    Zum compilieren habe ich mittlerweile zwei Makefiles erzeugt, die beide die identischen Fehlermeldungen produzieren. Auch diese sind unten aufgelistet.
    Makefile 1 greift das aus den Beispielprojekten bekannte Schema auf. Es werden einfach die zu compilierenden Dateien registriert und die includierte common.mk übernimmt den Rest. Bei der zweiten Makefile wird alles händisch erzeugt.

    Kommen wir zum Wesentlichen. Die Fehlermeldung ist hier unten aufgelistet. Mich irritiert, dass er die angegebenen Variablen nicht finden kann, obwohl die doch eigentlich systemweit verfügbar sein müssten.

    nvcc -c main.cpp  -I. -I/usr/local/cuda/include -I/Developer/GPU\ Computing/C/common/inc
    In file included from main.cpp:3:
    kernel_vector_add.cu: In function ‘void VecAdd(float*, float*, float*, int)’:
    kernel_vector_add.cu:8: error: ‘blockDim’ was not declared in this scope
    kernel_vector_add.cu:8: error: ‘blockIdx’ was not declared in this scope
    kernel_vector_add.cu:8: error: ‘threadIdx’ was not declared in this scope
    main.cpp: In function ‘int main(int, char**)’:
    main.cpp:29: error: invalid conversion from ‘float**’ to ‘void**’
    main.cpp:29: error:   initializing argument 1 of ‘cudaError_t cudaMalloc(void**, size_t)’
    main.cpp:30: error: invalid conversion from ‘float**’ to ‘void**’
    main.cpp:30: error:   initializing argument 1 of ‘cudaError_t cudaMalloc(void**, size_t)’
    main.cpp:31: error: invalid conversion from ‘float**’ to ‘void**’
    main.cpp:31: error:   initializing argument 1 of ‘cudaError_t cudaMalloc(void**, size_t)’
    main.cpp:36: error: expected primary-expression before ‘<’ token
    main.cpp:36: error: expected primary-expression before ‘>’ token
    make: *** [main.o] Error 1
    

    Das CUDA-SDK ist soweit installiert und compiliert und die Beispielprogramme laufen auch korrekt. Insofern liegt das Problem bei mir und meiner Makefile.

    Ich bitte euch um eure Hilfe, weil ich absolut nicht mehr weiter weiß.

    Beste Grüße

    Vic

    PS:
    Ich entwickel auf einem Mac mit der gcc Version 4.2.1.
    Die CUDA Bibliothek liegt in der Version 3.2 vor.

    #include <stdio.h>
    #include <cuda.h>
    #include "kernel_vector_add.cu"
    #include <cutil_inline.h>
    
    int main (int argc, char** argv) {
    	const unsigned int numElements = 100;
    	const unsigned int vecByteSize = numElements * sizeof(float);
    	unsigned int i = 0;
    
    	const int threadsPerBlock = 50;
    	const int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock;
    
    	float* vecA = (float*)malloc(vecByteSize);
    	float* vecB = (float*)malloc(vecByteSize);
    	float* vecC = (float*)malloc(vecByteSize);
    
    	for (i = 0; i < numElements; ++i) {
    		vecA[i] = i;
    		vecB[i] = i;
    		vecC[i] = 0;
    	}
    
    	float* dA = 0;
    	float* dB = 0;
    	float* dC = 0;
    
    	cudaMalloc(&dA, vecByteSize);
    	cudaMalloc(&dB, vecByteSize);
    	cudaMalloc(&dC, vecByteSize);
    
    	cudaMemcpy(dA, vecA, vecByteSize, cudaMemcpyHostToDevice);
    	cudaMemcpy(dB, vecB, vecByteSize, cudaMemcpyHostToDevice);
    
    	VecAdd<<<blocksPerGrid, threadsPerBlock>>>(dA, dB, dC, numElements);
    	cudaThreadSynchronize();
    
    	cudaMemcpy(vecC, dC, vecByteSize, cudaMemcpyDeviceToHost);
    
    	cudaFree(dA);
    	cudaFree(dB);
    	cudaFree(dC);
    
    	free(vecA);
    	free(vecB);
    	free(vecC);
    
    	return 0;
    }
    
    #ifndef __KERNEL_VECTOR_ADD_CU__
    #define __KERNEL_VECTOR_ADD_CU__
    
    #include <cuda.h>
    #include <cutil_inline.h>
    
    __global__ void VecAdd (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
    
    # Makefile 1
    BINDIR := ./
    EXECUTABLE := vecAddSample
    
    CCFILES := 
    CUFILES := vectorAdd.cu
    
    ROOTDIR := /Developer/GPU\ Computing/C/common
    
    include $(ROOTDIR)/../common/common.mk
    
    # Makefile 2
    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
    CUFILES=kernel_vector_add.cu
    LIBS=-lcublas -lcuda -lcudart -lcufft -lcurand -lcusparse -ltlshook
    
    OBJ=main.o kernel_vector_add.cu.o
    
    $(PROJECT) : $(OBJ)
    	$(NVCC) -o $(PROJECT) $(OBJ) $(LIBDIR) $(LIBS)
    
    kernel_vector_add.cu.o : kernel_vector_add.cu
    	$(NVCC) -c kernel_vector_add.cu -o kernel_vector_add.cu.o $(INCDIR)
    
    main.o : main.cpp
    	$(NVCC) -c main.cpp $(WARNINGS) $(INCDIR)
    


  • 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
    

Anmelden zum Antworten