我正在使用C#和CUDAfy.net(是的,这个问题在带有指针的直接C中更容易,但考虑到更大的系统,我有理由使用这种方法。)
我有一个视频帧采集卡,以30 FPS收集字节[1024 x 1024]图像数据。每33.3毫秒填充一个循环缓冲区中的一个槽并返回一个System.IntPtr
,指向*byte
的未管理的1D向量;循环缓冲区有15个插槽。
在GPU设备(Tesla K40)上,我想要一个全局的2D数组,它被组织成一个密集的2D数组。也就是说,我想要像循环队列这样的东西,但在GPU上组织成一个密集的2D阵列。
byte[15, 1024*1024] rawdata;
// if CUDAfy.NET supported jagged arrays I could use byte[15][1024*1024 but it does not
如何每33毫秒填一个不同的行?我是否使用类似的东西:
gpu.CopyToDevice<byte>(inputPtr, 0, rawdata, offset, length) // length = 1024*1024
//offset is computed by rowID*(1024*1024) where rowID wraps to 0 via modulo 15.
// inputPrt is the System.Inptr that points to the buffer in the circular queue (un-managed)?
// rawdata is a device buffer allocated gpu.Allocate<byte>(1024*1024);
在我的内核标题中是:
[Cudafy]
public static void filter(GThread thread, byte[,] rawdata, int frameSize, byte[] result)
我确实尝试过这些方法。但CudaFy中没有API模式:
GPGPU.CopyToDevice(T) Method (IntPtr, Int32, T[,], Int32, Int32, Int32)
所以我使用gpu.Cast函数将2D设备数组更改为1D。
我尝试了以下代码,但我收到了CUDA.net异常: ErrorLaunchFailed
仅供参考:当我尝试使用CUDA模拟器时,它会在CopyToDevice上中止 声称数据不是主机分配
public static byte[] process(System.IntPtr data, int slot)
{
Stopwatch watch = new Stopwatch();
watch.Start();
byte[] output = new byte[FrameSize];
int offset = slot*FrameSize;
gpu.Lock();
byte[] rawdata = gpu.Cast<byte>(grawdata, FrameSize); // What is the size supposed to be? Documentation lacking
gpu.CopyToDevice<byte>(data, 0, rawdata, offset, FrameSize * frameCount);
byte[] goutput = gpu.Allocate<byte>(output);
gpu.Launch(height, width).filter(rawdata, FrameSize, goutput);
runTime = watch.Elapsed.ToString();
gpu.CopyFromDevice(goutput, output);
gpu.Free(goutput);
gpu.Synchronize();
gpu.Unlock();
watch.Stop();
totalRunTime = watch.Elapsed.ToString();
return output;
}
答案 0 :(得分:1)
我现在提出这个&#34;解决方案&#34; : 1.仅在纯模式下运行程序(不在仿真模式下)。 或 2.不要自己处理固定内存分配。
现在似乎有一个悬而未决的问题。但这种情况仅在仿真模式下发生 。
答案 1 :(得分:1)
如果我理解你的问题,我认为你正在寻求转换
byte*
您从循环缓冲区进入要发送到的多维byte
数组
显卡API。
int slots = 15;
int rows = 1024;
int columns = 1024;
//Try this
for (int currentSlot = 0; currentSlot < slots; currentSlot++)
{
IntPtr intPtrToUnManagedMemory = CopyContextFrom(currentSlot);
// use Marshal.Copy ?
byte[] byteData = CopyIntPtrToByteArray(intPtrToUnManagedMemory);
int offset =0;
for (int m = 0; m < rows; m++)
for (int n = 0; n < columns; n++)
{
//then send this to your GPU method
rawForGpu[m, n] = ReadByteValue(IntPtr: intPtrToUnManagedMemory,
offset++);
}
}
//or try this
for (int currentSlot = 0; currentSlot < slots; currentSlot++)
{
IntPtr intPtrToUnManagedMemory = CopyContextFrom(currentSlot);
// use Marshal.Copy ?
byte[] byteData = CopyIntPtrToByteArray(intPtrToUnManagedMemory);
byte[,] rawForGpu = ConvertTo2DArray(byteData, rows, columns);
}
}
private static byte[,] ConvertTo2DArray(byte[] byteArr, int rows, int columns)
{
byte[,] data = new byte[rows, columns];
int totalElements = rows * columns;
//Convert 1D to 2D rows, colums
return data;
}
private static IntPtr CopyContextFrom(int slotNumber)
{
//code that return byte* from circular buffer.
return IntPtr.Zero;
}
答案 2 :(得分:0)
您应该考虑使用内置的 GPGPU Async 功能,以便以非常有效的方式将数据从/向主机/设备移动并使用gpuKern.LaunchAsync(...)
查看http://www.codeproject.com/Articles/276993/Base-Encoding-on-a-GPU以获得有效使用方法。另一个很好的例子可以在CudafyExamples项目中找到,查找PinnedAsyncIO.cs。你要做的就是你所描述的一切。
这是在Cudafy.Host项目的CudaGPU.cs
中,它与您正在寻找的方法匹配(只是它的异步):
public void CopyToDeviceAsync<T>(IntPtr hostArray, int hostOffset, DevicePtrEx devArray,
int devOffset, int count, int streamId = 0) where T : struct;
public void CopyToDeviceAsync<T>(IntPtr hostArray, int hostOffset, T[, ,] devArray,
int devOffset, int count, int streamId = 0) where T : struct;
public void CopyToDeviceAsync<T>(IntPtr hostArray, int hostOffset, T[,] devArray,
int devOffset, int count, int streamId = 0) where T : struct;
public void CopyToDeviceAsync<T>(IntPtr hostArray, int hostOffset, T[] devArray,
int devOffset, int count, int streamId = 0) where T : struct;