2013-11-12 2 views
2

Я получаю эту по-настоящему странную (в моей перспективе) ошибку в VS2012 при попытке скомпилировать некоторый код, который ранее работал. Я использую технологию CUDA для создания 2D массива данных и моя цель состоит в том, чтобы записать его в текстовый файл ... но когда я добавляю этот фрагмент кода из примера, в конце моей основной функцииnvlink: error: Неопределенная ссылка при попытке записи в текстовый файл

// basic file operations 
#include <iostream> 
#include <fstream> 
using namespace std; 

int main() { 
    ofstream myfile; 
    myfile.open ("example.txt"); 
    myfile << "Writing this to a file.\n"; 
    myfile.close(); 
    return 0; 
} 

I получить

1> C:\Users\Karsten Chu\New Google Drive\Research\Visual Studio 2012\Projects\Dynamic Parallelism Test\Dynamic Parallelism Test>"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\bin\nvcc.exe" -dlink -o "x64\Debug\Dynamic Parallelism Test.device-link.obj" -Xcompiler "/EHsc /W3 /nologo /Od /Zi /RTC1 /MDd " -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\lib\x64" cuda.lib cudart.lib cudadevrt.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib -gencode=arch=compute_35,code=sm_35 -G --machine 64 "x64\Debug\CUDA Test 2.cu.obj" "x64\Debug\CUDA Test.cu.obj" "x64\Debug\RKF5 Prototype 2.cu.obj" x64\Debug\version.cu.obj 
1>nvlink : error : Undefined reference to '_ZTVSo__St14basic_ofstreamIcSt11char_traitsIcEE' in 'x64/Debug/RKF5 Prototype 2.cu.obj' 
1>nvlink : error : Undefined reference to '_ZTVSt9basic_iosIcSt11char_traitsIcEE__So__St14basic_ofstreamIcS1_E' in 'x64/Debug/RKF5 Prototype 2.cu.obj' 
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\BuildCustomizations\CUDA 5.5.targets(668,9): error MSB3721: The command ""C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\bin\nvcc.exe" -dlink -o "x64\Debug\Dynamic Parallelism Test.device-link.obj" -Xcompiler "/EHsc /W3 /nologo /Od /Zi /RTC1 /MDd " -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\lib\x64" cuda.lib cudart.lib cudadevrt.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib -gencode=arch=compute_35,code=sm_35 -G --machine 64 "x64\Debug\CUDA Test 2.cu.obj" "x64\Debug\CUDA Test.cu.obj" "x64\Debug\RKF5 Prototype 2.cu.obj" x64\Debug\version.cu.obj" exited with code -1. 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

Теперь я понимаю, что nvlink должен сделать с помощью CUDA, связывающей для этой части моего кода ... почему эти два аспекта моего кода вмешательства? Я думал, что эти ошибки означали, что есть библиотека, которую нужно добавить, которая не входит в мои настройки проекта, или параметры определения функции, и прототип не совпадают.

EDIT

Вот как и директивы #includes основные() мой код ... весь материал CUDA размещен в моем предыдущем вопросе. Мои параметры компилятора Я не уверен, как получить код ошибки. Проект - это просто консольное приложение Win32, и у меня есть только один исходный файл - этот файл RCPF5 Prototype 2.cu. Я попробовал отдельный, новый проект и код, составленный для меня отлично.

#include <cuda.h> 
#include <cuda_runtime.h> 
#include <device_launch_parameters.h> 
//#include <stdio.h> 
#include <iostream> 
#include <fstream> 
//#include <iomanip>      //display 2 decimal places 
#include <math.h> 
using namespace std; 

__global__ void rkf5(double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, int*, int*, size_t, double*, double*, double*); 
__global__ void calcK(double*, double*, double*); 
__global__ void k1(double*, double*, double*); 
__global__ void k2(double*, double*, double*); 
__global__ void k3(double*, double*, double*); 
__global__ void k4(double*, double*, double*); 
__global__ void k5(double*, double*, double*); 
__global__ void k6(double*, double*, double*); 
__global__ void arrAdd(double*, double*, double*); 
__global__ void arrSub(double*, double*, double*); 
__global__ void arrMult(double*, double*, double*); 
__global__ void arrInit(double*, double); 
__global__ void arrCopy(double*, double*); 
__device__ void setup(double , double*, double*, double*, double*, int*); 
__device__ double flux(int, double*) ; 
__device__ double knowles_flux(int, double*); 
__device__ void calcStepSize(double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, double*, int*); 
__global__ void storeConcs(double*, size_t, double*, int); 
__global__ void takeFourthOrderStep(double*, double*, double*, double*, double*, double*, double*); 
__global__ void takeFifthOrderStep(double*, double*, double*, double*, double*, double*, double*, double*); 

//Error checking that I don't understand yet. 
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); } 
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true) 
{ 
    if (code != cudaSuccess) 
    { 
     fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line); 
     if (abort) exit(code); 
    } 
} 

//Main program. 
int main(int argc, char** argv) 
{ 
    //std::cout << std::fixed;   //display 2 decimal places 
    //std::cout << std::setprecision(12); //display 2 decimal places 
    const int maxlength = 1;   //Number of discrete concentrations we are tracking. 
    double concs[maxlength];   //Meant to store the current concentrations 
    double temp1[maxlength];    //Used as a bin to store products of Butcher's tableau and k values. 
    double temp2[maxlength];    //Used as a bin to store products of Butcher's tableau and k values. 
    double tempsum[maxlength];   //Used as a bin to store cumulative sum of tableau and k values 
    double k1s[maxlength]; 
    double k2s[maxlength]; 
    double k3s[maxlength]; 
    double k4s[maxlength]; 
    double k5s[maxlength]; 
    double k6s[maxlength]; 
    const int numpoints = 40;  
    double to = 0; 
    double tf = 1; 
    //double dt = static_cast<double>(.5)/static_cast<double>(64); 
    double dt = (tf-to)/static_cast<double>(numpoints); 
    double mo = 1; 
    double concStorage[maxlength][numpoints]; //Stores concs vs. time      

    //Initialize all the arrays on the host to ensure arrays of 0's are sent to the device. 
    //Also, here is where we can seed the system. 
    std::cout<<dt; 
    std::cout<<"\n"; 
    concs[0]=mo; 
    std::cout<<concs[0]; 
    std::cout<<" "; 
    for (int i=0; i<maxlength; i++) 
    { 
     for (int j=0; j<numpoints; j++) 
      concStorage[i][j]=0; 
     concs[i]=0; 
     temp1[i]=0; 
     temp2[i]=0; 
     tempsum[i]=0; 
     k1s[i]=0; 
     k2s[i]=0; 
     k3s[i]=0; 
     k4s[i]=0; 
     k5s[i]=0; 
     k6s[i]=0; 
     std::cout<<concs[i]; 
     std::cout<<" "; 
    } 
    concs[0]=mo; 
    std::cout<<"\n"; 

    //Define all the pointers to device array memory addresses. These contain the on-GPU 
    //addresses of all the data we're generating/using. 
    double *d_concs; 
    double *d_temp1; 
    double *d_temp2; 
    double *d_tempsum; 
    double *d_k1s; 
    double *d_k2s; 
    double *d_k3s; 
    double *d_k4s; 
    double *d_k5s; 
    double *d_k6s; 
    double *d_dt; 
    int *d_maxlength; 
    int *d_numpoints; 
    double *d_to; 
    double *d_tf; 
    double *d_concStorage; 

    //Calculate all the sizes of the arrays in order to allocate the proper amount of memory on the GPU. 
    size_t size_concs = sizeof(concs); 
    size_t size_temp1 = sizeof(temp1); 
    size_t size_temp2 = sizeof(temp2); 
    size_t size_tempsum = sizeof(tempsum); 
    size_t size_ks = sizeof(k1s); 
    size_t size_maxlength = sizeof(maxlength); 
    size_t size_numpoints = sizeof(numpoints); 
    size_t size_dt = sizeof(dt); 
    size_t size_to = sizeof(to); 
    size_t size_tf = sizeof(tf); 
    size_t h_pitch = numpoints*sizeof(double); 
    size_t d_pitch; 

    //Calculate the "pitch" of the 2D array. The pitch is basically the length of a 2D array's row. IT's larger 
    //than the actual row full of data due to hadware issues. We thusly will use the pitch instead of the data 
    //size to traverse the array. 
    gpuErrchk(cudaMallocPitch((void**)&d_concStorage, &d_pitch, numpoints * sizeof(double), maxlength)); 

    //Allocate memory on the GPU for all the arrrays we're going to use in the integrator. 
    gpuErrchk(cudaMalloc((void**)&d_concs, size_concs)); 
    gpuErrchk(cudaMalloc((void**)&d_temp1, size_temp1)); 
    gpuErrchk(cudaMalloc((void**)&d_temp2, size_temp1)); 
    gpuErrchk(cudaMalloc((void**)&d_tempsum, size_tempsum)); 
    gpuErrchk(cudaMalloc((void**)&d_k1s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_k2s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_k3s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_k4s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_k5s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_k6s, size_ks)); 
    gpuErrchk(cudaMalloc((void**)&d_maxlength, size_maxlength)); 
    gpuErrchk(cudaMalloc((void**)&d_numpoints, size_numpoints)); 
    gpuErrchk(cudaMalloc((void**)&d_dt, size_dt)); 
    gpuErrchk(cudaMalloc((void**)&d_to, size_to)); 
    gpuErrchk(cudaMalloc((void**)&d_tf, size_tf)); 

    //Copy all initial values of arrays to GPU. 
    gpuErrchk(cudaMemcpy2D(d_concStorage, d_pitch, concStorage, h_pitch, numpoints*sizeof(double), maxlength, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_concs, &concs, size_concs, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_temp1, &temp1, size_temp1, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_temp2, &temp2, size_temp2, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_tempsum, &tempsum, size_tempsum, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k1s, &k1s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k2s, &k2s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k3s, &k3s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k4s, &k4s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k5s, &k5s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_k6s, &k6s, size_ks, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_maxlength, &maxlength, size_maxlength, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_numpoints, &numpoints, size_numpoints, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_dt, &dt, size_dt, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_to, &to, size_to, cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_tf, &tf, size_tf, cudaMemcpyHostToDevice)); 

    //Run the integrator. 
    rkf5<<<1,1>>>(d_concs, d_concStorage, d_temp1, d_temp2, d_tempsum, d_k1s, d_k2s, d_k3s, d_k4s, d_k5s, d_k6s, d_maxlength, d_numpoints, d_pitch, d_dt, d_to, d_tf); 
    gpuErrchk(cudaPeekAtLastError()); 
    gpuErrchk(cudaDeviceSynchronize()); 
    cudaDeviceSynchronize(); 
    /* 
    //Sets all of concStorage to 1 after the kernel runs. Used to make sure that 2D array copied over the array. 
    std::cout << "\n"; 
    for (int i=0; i<maxlength; i++) 
     for(int j=0; j<numpoints; j++) 
      concStorage[i][j]=1; 
    */ 

    //Copy concentrations from GPU to Host. Almost defunct now that transferring the 2D array works. 
    cudaMemcpy(concs, d_concs, size_concs, cudaMemcpyDeviceToHost); 
    //Copy 2D array of concentrations vs. time from GPU to Host. 
    gpuErrchk(cudaMemcpy2D(concStorage, h_pitch, d_concStorage, d_pitch, numpoints*sizeof(double), maxlength, cudaMemcpyDeviceToHost)); 

    //Print concentrations after the integrator kernel runs. Used to test that data was transferring to and from GPU correctly. 
    std::cout << "\n"; 
    for (int i=0; i<maxlength; i++) 
    { 
     std::cout<<concs[i]; 
     std::cout<<" "; 
    } 

    double a[10]; 
    double b[10]; 
    double c[10]; 
    for(int i = 0; i< 10; i++) 
    { 
     a[i]=0; 
     b[i]=0; 
     c[i]=0; 
    } 

    //Print out the concStorage array after the kernel runs. Used to test that the 2D array transferred correctly from host to GPU and back. 
    std::cout << "\n\n"; 
    std::cout << "Calculated Array"; 
    std::cout << "\n\n"; 
    for (int i=0; i<maxlength; i++) 
    { 
     for(int j=0; j<numpoints; j++) 
     { 
      if (j%(numpoints/10)==0) 
      { 
       a[j/(numpoints/10)]=concStorage[i][j]; 
       std::cout<<concStorage[i][j]; 
       std::cout<<" "; 
      } 
     } 
     std::cout << "\n"; 
    } 
    std::cout << "\n"; 
    std::cout << "Exponential"; 
    std::cout << "\n\n"; 
    for (int i=0; i<10; i++) 
    { 
     b[i]=exp(-i*(tf-to)/10); 
     std::cout<<exp(-i*(tf-to)/10); 
     std::cout<<" "; 
    } 
    std::cout << "\n\n"; 
    std::cout << "Error Array"; 
    std::cout << "\n\n"; 
    for (int i=0; i<10; i++) 
    { 
     c[i]=a[i]-b[i]; 
     std::cout<<c[i]; 
     std::cout<<" "; 
    } 
    std::cout << "\n\n"; 

    cudaDeviceReset(); //Clean up all memory. 
    ///* 
    ofstream myfile; 
    myfile.open ("example.txt"); 
    myfile << "Writing."; 
    myfile.close(); 
    //*/ 

    return 0; 
} 
+0

Код, показанный здесь, компилируется и выполняется просто отлично, независимо от того, прошел ли он через обычный компилятор хоста или 'nvcc'. Я думаю, вам нужно будет предоставить дополнительную информацию о файле, который содержит этот фрагмент, а также структуру вашего проекта (какой проект вы строите, какие все файлы в нем, какой полный файл содержит этот файл фрагмент кода, какие полные команды компиляции 'nvcc' выдает VS и т. д.) –

+0

@RobertCrovella Я добавил код main() и большую часть запрошенной вами информации, как я мог. Постскриптум Надеюсь, я лучше справился с проверкой ошибок CUDA. –

+0

Я только что прокомментировал 5-ю строку запуска ядра интегратора Runge-Kutta, так как вы не предоставили соответствующую функцию '__global__'. Я вижу, что он правильно компилируется, когда я отключу возможность создания перемещаемого кода. Если у меня есть эта опция, я получаю ошибку привязки с 'ofstream', которую вы сообщаете. – JackOLantern

ответ

4

Ваш простой код

#include <iostream> 
#include <fstream> 
using namespace std; 

int main() { 
    ofstream myfile; 
    myfile.open ("example.txt"); 
    myfile << "Writing this to a file.\n"; 
    myfile.close(); 
    return 0; 
} 

скомпилирован с опцией -rdc=true давал nvlink ошибку вы сообщили. Это может быть связано с невозможностью использования статически загруженной среды выполнения C в соответствии с временем выполнения CUDA. Это может быть исправлено с помощью

Project -> Properties -> Configuration Properties -> CUDA C/C++ -> Host -> Runtime Library 

и выбрать

Multi-Threaded Debug (/MTd) 

, если вы находитесь в режиме отладки или

Multi-Threaded (/MT) 

, если вы находитесь в режиме выпуска.

Я надеюсь, что это исправить вашу проблему.

+0

Большое спасибо за то, что нашли время, чтобы помочь мне с этим. Я никогда не подумал об этом. Оно работает! Хотя я думал, что был в режиме Debug, и сделал предложенное вами изменение, и он вырвал больше ошибок, затем я попробовал/MT change, и он сработал. –

+1

Святой F, я, наконец, решил свои проблемы! Хотя я устанавливал «Проект -> Свойства -> Свойства конфигурации -> C/C++ -> Генерация кода -> Библиотека времени выполнения» для предлагаемого MTd, и эта настройка, на которую ссылается Jack, я просто разрешаю по умолчанию - наследует от хоста. –

Смежные вопросы