我现在的算法会调用 enqueueNDRangeKernel
函数,每次调用多次。在调用它之前,我将使用 enqueueWriteBuffer
来修改一个参数的值。但现在的问题是,有时在调用 enqueueNDRangeKernel
,会出现一个 "无效的内核参数 "错误。上次出现是在上个月。昨天又出现了,太随机了。谁能给我一个解决办法?我查了相关资料,说这个错误一般是因为内核参数没有设置,但我查了一下 enqueueWriteBuffer
函数,它没有报告任何错误。我传给GPU的参数是。
cl.setKernelArg(kernel, 0, "double*", d_X);
cl.setKernelArg(kernel, 1, "double*", d_A);
cl.setKernelArg(kernel, 2, "int*", d_A_INDIEX);
cl.setKernelArg(kernel, 3, "int*", d_A_INDICE);
cl.setKernelArg(kernel, 4, "double*", d_CONSTANTS);
cl.setKernelArg(kernel, 5, "int*", d_ourpartitions);
cl.setKernelArg(kernel, 6, "int*", d_INDIEX);
cl.setKernelArg(kernel, 7, "int*", d_hasGreater);
cl.setKernelArg(kernel, 8, "int", xnum);
cl.setKernelArg(kernel, 9, "int", ynum);
cl.setKernelArg(kernel, 10, "int", n);
cl.setKernelArg(kernel, 11, "int", iterations);
cl.setKernelArg(kernel, 12, "double", error);
我调用enqueueNDRangeKernel的方式是这样的:
for (var j = 0; j <partitions.length;j++) {
INDIEX[0] = INDICE[j];
State = cl.enqueueWriteBuffer(queue, d_INDIEX, true, 0, intsize, INDIEX);
if(State != 0){
console.log("Write INDIEX error! "+ State);
}
var localSize = null;
// This place sometimes gives an error: Error: Invalid kernel arguments ?? (you can look at it again)
var globalSize=[partitions[j].length];
State = cl.enqueueNDRangeKernel(queue, kernel, 1,
null,
globalSize,
localSize
);
if(State != 0){
console.log("enqueueNDRangeKernel error! "+ State);
}
cl.finish(queue);
}
我的内核函数原型如下:
__kernel void kernelCode(
__global double* X,
__global double * A,
__global int * A_INDIEX,
__global int * A_INDICE,
__global double * b,
__global int* partitions,
__global int* INDIEX,
__global int* hasGreater,
const int xnum,
const int ynum,
const int n,
const int iterations,
const double error);
所以,我从来没有使用过 节点所以我不是使用它的专家。但看起来它处理错误的方式和你的代码预期的不同。具体来说,在 的执行情况 enqueueNDRangeKernel
包皮:
CHECK_ERR(::clEnqueueNDRangeKernel(
q->getRaw(),
k->getRaw(),
work_dim,
cl_work_offset.size() ? cl_work_offset.data() : nullptr,
cl_work_global.size() ? cl_work_global.data() : nullptr,
cl_work_local.size() ? cl_work_local.data() : nullptr,
(cl_uint)cl_events.size(), NOCL_TO_CL_ARRAY(cl_events, NoCLEvent),
eventPtr
));
RETURN_EVENT
}
我们可以看到,对OpenCL的底层调用中的 clEnqueueNDRangeKernel
被包裹在 CHECK_ERR
的宏,它是 这样定义:
#define CHECK_ERR(ret) { cl_int _err=(ret); \
if ((_err) != CL_SUCCESS) { \
return Nan::ThrowError(JS_STR(opencl::getExceptionMessage(_err))); \
} \
}
RETURN_EVENT
meanwhile是这样定义的。
#define RETURN_EVENT \
if (eventPtr) { \
info.GetReturnValue().Set(NOCL_WRAP(NoCLEvent, event)); \
} else { \
info.GetReturnValue().Set(JS_INT(CL_SUCCESS)); \
}
这意味着任何错误都不会通过JS包装函数的返回值返回,而是通过一个抛出的异常来返回。所以,如果我的JavaScript知识没问题的话,如果在一个CL调用过程中遇到了错误,你的 "错误处理 "代码将永远不会真正运行,因为函数因为抛出异常而提前退出。
所以我不知道你的问题的根本原因是什么,但是。
State
只有当你的代码为0的时候CL_SUCCESS
)或一个事件对象,它永远不会返回错误。try
catch
构造。clEnqueueNDRangeKernel
正在返回 CL_INVALID_KERNEL_ARGS
.由于它 "大部分时间 "都在工作,我怀疑缓冲区的创建以某种方式结束,也许是因为资源耗尽?我不知道node-opencl是如何处理缓冲区的,但如果它使用垃圾回收来代替显式销毁缓冲区,我可以想象你可能需要在处理完缓冲区后强制进行一次清扫。如果缓冲区 是 明确的创造和毁灭,也许你并不是在毁灭所有的人?