Я пробую, разделяют программу 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 файл, который будет заботиться о том, чтобы говорить с устройством и вызывании функций ядра и что нет.
Вы включаете 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.
Если вы посмотрите на примеры кода 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.
Не похоже, что SimpleXML поддерживает это, поэтому у вас есть два варианта:
Используйте модуль DOM (или, возможно, один из других модулей XML) и DOMNode:: insertBefore метод или
Создайте новый 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.
Простое решение - отключить здание файла 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;
}