Как разделить код CUDA на несколько файлов

Я пробую, разделяют программу CUDA на два отдельных .cu файла в усилии ограничиться ближе к записи реального приложения в C++. У меня есть простая небольшая программа что:

Выделяет память на хосте и устройстве.
Инициализирует массив хоста к серии чисел. Копии массив хоста к массиву устройства Находят квадрат всех элементов в массиве с помощью ядра устройства Копии массив устройства назад к Печати массива хоста результаты

Это работает отлично, если я поместил все это в один .cu файл и выполнил его. Когда я разделил его на два отдельных файла, я начинаю получать соединение ошибок. Как все мои недавние вопросы, я знаю, что это - что-то маленькое, но что это?

KernelSupport.cu

#ifndef _KERNEL_SUPPORT_
#define _KERNEL_SUPPORT_

#include <iostream>
#include <MyKernel.cu>

int main( int argc, char** argv) 
{
    int* hostArray;
    int* deviceArray;
    const int arrayLength = 16;
    const unsigned int memSize = sizeof(int) * arrayLength;

    hostArray = (int*)malloc(memSize);
    cudaMalloc((void**) &deviceArray, memSize);

    std::cout << "Before device\n";
    for(int i=0;i<arrayLength;i++)
    {
        hostArray[i] = i+1;
        std::cout << hostArray[i] << "\n";
    }
    std::cout << "\n";

    cudaMemcpy(deviceArray, hostArray, memSize, cudaMemcpyHostToDevice);
    TestDevice <<< 4, 4 >>> (deviceArray);
    cudaMemcpy(hostArray, deviceArray, memSize, cudaMemcpyDeviceToHost);

    std::cout << "After device\n";
    for(int i=0;i<arrayLength;i++)
    {
        std::cout << hostArray[i] << "\n";
    }

    cudaFree(deviceArray);
    free(hostArray);

    std::cout << "Done\n";
}

#endif

MyKernel.cu

#ifndef _MY_KERNEL_
#define _MY_KERNEL_

__global__ void TestDevice(int *deviceArray)
{
    int idx = blockIdx.x*blockDim.x + threadIdx.x;
    deviceArray[idx] = deviceArray[idx]*deviceArray[idx];
}


#endif

Журнал сборки:

1>------ Build started: Project: CUDASandbox, Configuration: Debug x64 ------
1>Compiling with CUDA Build Rule...
1>"C:\CUDA\bin64\nvcc.exe"    -arch sm_10 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin"    -Xcompiler "/EHsc /W3 /nologo /O2 /Zi   /MT  "  -maxrregcount=32  --compile -o "x64\Debug\KernelSupport.cu.obj" "d:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\CUDASandbox\KernelSupport.cu" 
1>KernelSupport.cu
1>tmpxft_000016f4_00000000-3_KernelSupport.cudafe1.gpu
1>tmpxft_000016f4_00000000-8_KernelSupport.cudafe2.gpu
1>tmpxft_000016f4_00000000-3_KernelSupport.cudafe1.cpp
1>tmpxft_000016f4_00000000-12_KernelSupport.ii
1>Linking...
1>KernelSupport.cu.obj : error LNK2005: __device_stub__Z10TestDevicePi already defined in MyKernel.cu.obj
1>KernelSupport.cu.obj : error LNK2005: "void __cdecl TestDevice__entry(int *)" (?TestDevice__entry@@YAXPEAH@Z) already defined in MyKernel.cu.obj
1>D:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\x64\Debug\CUDASandbox.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Build log was saved at "file://d:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\CUDASandbox\x64\Debug\BuildLog.htm"
1>CUDASandbox - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Я запускаю Visual Studio 2008 в Windows 7 64bit.


Править:

Я думаю, что должен уточнить это немного. Конечный результат, который я ищу здесь, состоит в том, чтобы иметь нормальное приложение C++ с чем-то как Main.cpp с int main() событию и выполняли вещи оттуда. В точке certains в моем коде .cpp я хочу быть в состоянии сослаться на биты CUDA. Так мои взгляды (и исправляют меня, если там более стандартная конвенция здесь) то, что я помещу код Ядра CUDA в их на .cu файлах и затем иметь поддержку .cu файл, который будет заботиться о том, чтобы говорить с устройством и вызывании функций ядра и что нет.

13
задан Mr Bell 19 January 2010 в 05:58
поделиться

4 ответа

Вы включаете Mykernel.Cu в Kernelsupport.cu , когда вы пытаетесь связать компилятор видит MyKernel .Ку дважды. Вам придется создать заголовок, определяющий TestDevice и включить это вместо этого.

Re Комментарий:

Что-то вроде этого должно работать

// MyKernel.h
#ifndef mykernel_h
#define mykernel_h
__global__ void TestDevice(int* devicearray);
#endif

, а затем измените включение файла в

//KernelSupport.cu
#ifndef _KERNEL_SUPPORT_
#define _KERNEL_SUPPORT_

#include <iostream>
#include <MyKernel.h>
// ...

Re Edit

, пока заголовок, который вы используете в C ++, не имеют каких-либо CUDA Вещи ( __ ядро ​​__ , __ Global __ , и т. Д.) Вы должны быть хорошими связываниями C ++ и CUDA.

12
ответ дан 2 December 2019 в 00:03
поделиться

Если вы посмотрите на примеры кода CUDA SDK, у них есть Extern C Определяет, что ссылочные функции скомпилированы из файлов .cu. Таким образом, файлы .cu скомпилированы NVCC и связаны только в основную программу, когда файлы .CPP обычно скомпилированы нормально.

Например, в MarchingCubes_Kernel.CU имеет функциональный корпус:

extern "C" void
launch_classifyVoxel( dim3 grid, dim3 threads, uint* voxelVerts, uint *voxelOccupied, uchar *volume,
                      uint3 gridSize, uint3 gridSizeShift, uint3 gridSizeMask, uint numVoxels,
                      float3 voxelSize, float isoValue)
{
    // calculate number of vertices need per voxel
    classifyVoxel<<<grid, threads>>>(voxelVerts, voxelOccupied, volume, 
                                     gridSize, gridSizeShift, gridSizeMask, 
                                     numVoxels, voxelSize, isoValue);
    cutilCheckMsg("classifyVoxel failed");
}

в то время как в MarchingCubes.cpp (где основные () проживает) просто имеет определение:

extern "C" void
launch_classifyVoxel( dim3 grid, dim3 threads, uint* voxelVerts, uint *voxelOccupied, uchar *volume,
                      uint3 gridSize, uint3 gridSizeShift, uint3 gridSizeMask, uint numVoxels,
                      float3 voxelSize, float isoValue);

Вы можете поставить их в файл .h.

4
ответ дан 2 December 2019 в 00:03
поделиться

Не похоже, что SimpleXML поддерживает это, поэтому у вас есть два варианта:

  1. Используйте модуль DOM (или, возможно, один из других модулей XML) и DOMNode:: insertBefore метод или

  2. Создайте новый SimpleXMLElement, скопируйте атрибуты, затем добавьте новый узел, затем после этого добавьте все нижестоящие элементы исходного узла, а затем замените исходный на новый.

обновление: После того, как я еще немного просмотрел документы, я бы предложил что-то вроде следующего (предполагая, что вы все еще хотите придерживаться SimpleXML по большей части, в противном случае, просто используйте DOM непосредственно для всего):

$dom_elem = dom_import_simplexml($simple_xml_element);
$dom_elem->insertBefore(dom_import_simplexml($new_element), $dom_elem->firstChild);
-121--3064151-

Джон Скит имеет один в своем Push LINQ . Он также упоминает его в Первые встречи с реактивными расширениями .

-121--3832523-

Получение разделения на самом деле довольно просто, пожалуйста, ознакомьтесь этот ответ , чтобы узнать, как его настроить. Затем вы просто помещаете код узла в файлы .cpp, а код устройства - в файлы .cu. Правила построения указывают Visual Studio, как связать их с конечным исполняемым файлом.

Непосредственная проблема в коде, заключающаяся в том, что вы определяете функцию __ global __ StartDevice дважды, один раз при # include MyKernel.cu и один раз при независимой компиляции MyKernel.cu.

Вам также потребуется поместить оболочку в файл .cu - в данный момент вы вызываете StartDevice < < < > > > из своей основной функции, но при перемещении этого файла в файл .cpp он будет скомпилирован с помощью cl.exe, который не понимает синтаксис < < < > > > . Поэтому вы можете просто вызвать (griddim, blockdim, params) в файле .cpp и предоставить эту функцию в файле .cu.

Если вы хотите пример, образец SobolQRNG в SDK достигает хорошего разделения, хотя он по-прежнему использует cutil, и я бы всегда рекомендовал избегать cutil.

3
ответ дан 2 December 2019 в 00:03
поделиться

Простое решение - отключить здание файла mykernel.cu.

Свойства -> General -> Исключая из строя

, лучшее решение IMO - разделить ядро ​​в Cu и файл CUH и включить, например,

//kernel.cu
#include "kernel.cuh"
#include <cuda_runtime.h>

__global__ void increment_by_one_kernel(int* vals) {
  vals[threadIdx.x] += 1;
}

void increment_by_one(int* a) {
  int* a_d;

  cudaMalloc(&a_d, 1);
  cudaMemcpy(a_d, a, 1, cudaMemcpyHostToDevice);
  increment_by_one_kernel<<<1, 1>>>(a_d);
  cudaMemcpy(a, a_d, 1, cudaMemcpyDeviceToHost);

  cudaFree(a_d);
}

//kernel.cuh
#pragma once

void increment_by_one(int* a);

//main.cpp
#include "kernel.cuh"

int main() {
  int a[] = {1};

  increment_by_one(a);

  return 0;
}
-3
ответ дан 2 December 2019 в 00:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: