プログラム内の数学ルーチンの一部を高速化するために、配列除算の一部を GPU にシフトしたいと考えていました。私が開発している環境は、monodevelop を使用し、opencl C ライブラリの単なる P/Invoke ラッパーであるOpenTkライブラリを使用する Linux (Arch)です。
具体的には、すべての初期化を行い、エラーやログに何も報告されずにカーネルを構築し、メモリ バッファーをセットアップし、カーネル引数をセットアップすることができます。この問題は、「clEnqueueTask」メソッドを使用してタスクをキューに入れようとしたときに発生し、その時点でプログラムが segfault します。
この時点で、例外がスローされていないため (dll の欠落などのよりありふれたエラーに対してスローされていた)、プログラムをデバッグする方法がわからないので、途方に暮れていて、少しアドバイスを探しています。
どうもありがとう!
これがコードです...
string vecDivision = @"__kernel void floatDivision(__global float * v1, __global float * v2){
// Vector element index
int i = get_global_id(0);
v1[i] = v1[i] / v2[0];
}";
try{
fixed(float* srcA = &data[0]){
ErrorCode err = ErrorCode.Success;
IntPtr deviceId = IntPtr.Zero;
int numDevices = -1;
// get the platform to create the context from
IntPtr[] platforms = new IntPtr[3];
uint[] numPlatforms = new uint[3];
err = (ErrorCode)CL.GetPlatformIDs(3, platforms, numPlatforms);
// create the context
IntPtr[] properties = new IntPtr[]{new IntPtr((int)ContextProperties.ContextPlatform), platforms[0], IntPtr.Zero};
IntPtr context = CL.CreateContextFromType(properties, DeviceTypeFlags.DeviceTypeGpu, IntPtr.Zero, IntPtr.Zero, new ErrorCode[0]);
if(context == IntPtr.Zero){
throw new Exception("Count not create CL Context");
}
// get the device id
err = (ErrorCode)CL.GetDeviceIDs(platforms[0],DeviceTypeFlags.DeviceTypeDefault, 1, ref deviceId, ref numDevices);
if(err != ErrorCode.Success){
throw new Exception("Count not get the CL device");
}
// create the command queue
IntPtr queue = CL.CreateCommandQueue(context, deviceId, 0, out err);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL command queue");
}
// create the memory buffers
IntPtr ptrA = CL.CreateBuffer(context, MemFlags.MemReadWrite | MemFlags.MemUseHostPtr, new IntPtr(sizeof(float)*length), (IntPtr)srcA , out err);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL buffer");
}
IntPtr ptrB = CL.CreateBuffer(context, MemFlags.MemReadOnly | MemFlags.MemUseHostPtr, new IntPtr(sizeof(float)) , (IntPtr)divisor, out err);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL buffer");
}
// create the program using the source
IntPtr lengths = IntPtr.Zero;
IntPtr program = CL.CreateProgramWithSource(context, 1,new string[]{vecDivision}, ref lengths, out err);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL program from source");
}
// build the program from source
err = (ErrorCode)CL.BuildProgram(program, 1, new IntPtr[]{deviceId}, "", IntPtr.Zero, IntPtr.Zero);
if(err != ErrorCode.Success){
throw new Exception("Count not build the CL program");
}
// get the build log
char[] log = new char[2000];
IntPtr returnSize = IntPtr.Zero;
fixed(char* logp = &log[0]){
err = (ErrorCode)CL.GetProgramBuildInfo(program, deviceId, ProgramBuildInfo.ProgramBuildLog, new IntPtr(log.Length), new IntPtr(logp), out returnSize);
}
MsgHandling.LogMessage(new string(log).Substring(0,(int)returnSize), string.Empty);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL kernel");
}
// create the kernel object
IntPtr kernel = CL.CreateKernel(program, "floatDivision", out err);
if(err != ErrorCode.Success){
throw new Exception("Count not create CL kernel");
}
// set the arguments for the program
err = (ErrorCode)CL.SetKernelArg(kernel, 0, new IntPtr(sizeof(float*)), new IntPtr(&ptrA));
if(err != ErrorCode.Success){
throw new Exception("Count not set CL first argument");
}
err = (ErrorCode)CL.SetKernelArg(kernel, 1, new IntPtr(sizeof(float*)), new IntPtr(&ptrB));
if(err != ErrorCode.Success){
throw new Exception("Count not set CL second argument");
}
// queue up the worker
IntPtr globalWorkOffset = IntPtr.Zero;
IntPtr globalWorkSize = new IntPtr(length);
IntPtr localWorkSize = new IntPtr(64);
IntPtr eventWaitList = IntPtr.Zero;
IntPtr eventItem = IntPtr.Zero;
//err = (ErrorCode)CL.EnqueueNDRangeKernel(queue, kernel, 1, null, new IntPtr[]{globalWorkSize}, new IntPtr[]{localWorkSize}, 0, null, new IntPtr[]{eventItem});
// I DIE HERE!
err = (ErrorCode)CL.EnqueueTask(queue, kernel, 0,null, new IntPtr[]{eventItem});
// I DIE HERE!
if(err != ErrorCode.Success){
throw new Exception("Count not queue CL job");
}
// wait for it to finish
err = (ErrorCode)CL.Finish(queue);
if(err != ErrorCode.Success){
throw new Exception("Count not wait for CL job to finish");
}
}
アップデート:
私はそれを考え出した。問題は、バッファの作成方法でした。どうやら MemUseHostPtr を使用するオプションを使用する場合、別の方法を使用して読み取りバッファーをキューに入れる必要があるため、代わりにメモリを GPU メモリに直接コピーするオプションを使用しました。