Opencl 将主机用作设备
我在OpenCL上工作,我只有一个CPU i3 core Duo=>我只拥有一个设备(我的CPU)。所以基本上,我猜我的主机(cpu)也将是设备。我试图启动内核,但分配给设备(也是主机)的任务从未终止。考虑到这个问题后,很明显,主机等待设备(自身)完成是不可能的。但有人知道克服这个问题的方法吗?也许使用clCreateSubDevice,将我唯一的设备细分为主机和真实设备?我认为我的想法并没有那么糟糕,因为实际上,您需要通过编程强制主机切换到设备工作,在这种情况下,主机和设备都是相同的硬件 实际上,可以将主机作为设备,但为了让设备工作,您需要调用至少一个阻塞函数(clFinish(),或clEnqueueRead(…CL_TRUE,…)。否则,主机将始终工作,并且永远不会切换到设备工作。我试图添加一个sleep()函数,但它不起作用,您确实需要添加一个阻塞opencl函数Opencl 将主机用作设备,opencl,device,host,termination,Opencl,Device,Host,Termination,我在OpenCL上工作,我只有一个CPU i3 core Duo=>我只拥有一个设备(我的CPU)。所以基本上,我猜我的主机(cpu)也将是设备。我试图启动内核,但分配给设备(也是主机)的任务从未终止。考虑到这个问题后,很明显,主机等待设备(自身)完成是不可能的。但有人知道克服这个问题的方法吗?也许使用clCreateSubDevice,将我唯一的设备细分为主机和真实设备?我认为我的想法并没有那么糟糕,因为实际上,您需要通过编程强制主机切换到设备工作,在这种情况下,主机和设备都是相同的硬件 实际
无论如何谢谢你 您可以在下面找到我的类似java的代码,以便让我知道我的错误。实际上,当我在没有clFinish(commandQueue)的情况下运行以下代码时;(在代码底部),我有以下输出: 我使用Intel(R)OpenCL平台 排队内核。。。 暂停15000毫秒。 任务未完成 如果我添加clFinish(commandQueue),我就有了输出,我的任务也完成了: 我使用Intel(R)OpenCL平台 排队内核。。。 事件内核状态:CL_完成事件ID:10运行时:2.631ms 暂停15000毫秒。 任务完成 那么为什么单个clFinish()指令允许我完成任务呢?提前感谢您的解释
public class Test_CPU
{
private static String programSource0 =
"__kernel void vectorAdd(" +
" __global const float *a,"+
" __global const float *b, " +
" __global float *c)"+
"{"+
" int gid = get_global_id(0);"+
" c[gid] = a[gid]+b[gid];"+
"}";
/**
* The entry point of this sample
*
* @param args Not used
*/
public static void main(String args[])
{
/**
* Callback function that is called when the event ev has the event_status status and will display the runtime of execution kernel in seconds
* @param event: the event
* @param event_status: status of the event
* @param user_data: data given by the user is an integer tag that can be used to match profiling output to the associated kernel
* @return: none
*/
EventCallbackFunction kernelCommandEvent = new EventCallbackFunction()
{
@Override
public void function(cl_event event, int event_status, Object user_data)
{
int evID = (int)user_data;
long[] ev_start_time = new long[1];
Arrays.fill(ev_start_time, 0);
long[] ev_end_time = new long[1];
Arrays.fill(ev_end_time, 0);
long[] return_bytes = new long[1];
double run_time = 0.0;
clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_QUEUED, Sizeof.cl_long, Pointer.to(ev_start_time), return_bytes);
clGetEventProfilingInfo (event, CL_PROFILING_COMMAND_END , Sizeof.cl_long, Pointer.to(ev_end_time), return_bytes);
run_time = (double)(ev_end_time[0] - ev_start_time[0]);
System.out.println("Event kernel status: " + CL.stringFor_command_execution_status(event_status) + " event ID: " + evID + " runtime: " + String.format("%8.3f", (run_time*1.0e-6)) + " ms.");
}
};
// Initialize the input data
int n = 1000000;
float srcArrayA[] = new float[n];
float srcArrayB[] = new float[n];
float dstArray0[] = new float[n];
for (int i=0; i<srcArrayA.length; i++)
{
srcArrayA[i] = i;
srcArrayB[i] = i;
}
Pointer srcA = Pointer.to(srcArrayA);
Pointer srcB = Pointer.to(srcArrayB);
Pointer dst0 = Pointer.to(dstArray0);
// The platform, device type and device number that will be used
final int platformIndex = 1;
final long deviceType = CL_DEVICE_TYPE_CPU;
final int deviceIndex = 0;
// Enable exceptions and subsequently omit error checks in this sample
CL.setExceptionsEnabled(true);
// Obtain the number of platforms
int numPlatformsArray[] = new int[1];
clGetPlatformIDs(0, null, numPlatformsArray);
int numPlatforms = numPlatformsArray[0];
// Obtain a platform ID
cl_platform_id platforms[] = new cl_platform_id[numPlatforms];
clGetPlatformIDs(platforms.length, platforms, null);
cl_platform_id platform = platforms[platformIndex];
long size[] = new long[1];
clGetPlatformInfo(platform, CL_PLATFORM_NAME, 0, null, size);
// Create a buffer of the appropriate size and fill it with the info
byte buffer[] = new byte[(int)size[0]];
clGetPlatformInfo(platform, CL_PLATFORM_NAME, buffer.length, Pointer.to(buffer), null);
// Create a string from the buffer (excluding the trailing \0 byte)
System.out.println("I use the platform " + new String(buffer, 0, buffer.length-1));
// Initialize the context properties
cl_context_properties contextProperties = new cl_context_properties();
contextProperties.addProperty(CL_CONTEXT_PLATFORM, platform);
// Obtain the number of devices for the platform
int numDevicesArray[] = new int[1];
clGetDeviceIDs(platform, deviceType, 0, null, numDevicesArray);
int numDevices = numDevicesArray[0];
// Obtain a device ID
cl_device_id devices[] = new cl_device_id[numDevices];
clGetDeviceIDs(platform, deviceType, numDevices, devices, null);
cl_device_id device = devices[deviceIndex];
// Create a context for the selected device
cl_context context = clCreateContext(contextProperties, 1, new cl_device_id[]{device}, null, null, null);
// Create a command-queue, with profiling info enabled
long properties = 0;
properties |= CL.CL_QUEUE_PROFILING_ENABLE;
cl_command_queue commandQueue = CL.clCreateCommandQueue(context, devices[0], properties, null);
// Allocate the buffer memory objects
cl_mem srcMemA = CL.clCreateBuffer(context, CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR, Sizeof.cl_float * n, srcA, null);
cl_mem srcMemB = CL.clCreateBuffer(context, CL.CL_MEM_READ_ONLY | CL.CL_MEM_COPY_HOST_PTR, Sizeof.cl_float * n, srcB, null);
cl_mem dstMem0 = CL.clCreateBuffer(context, CL.CL_MEM_READ_WRITE, Sizeof.cl_float * n, null, null);
// Create and build the the programs and the kernels
cl_program program0 = CL.clCreateProgramWithSource(context, 1, new String[]{ programSource0 }, null, null);
// Build the programs
CL.clBuildProgram(program0, 0, null, null, null, null);
// Create the kernels
cl_kernel kernel0 = CL.clCreateKernel(program0, "vectorAdd", null);
// Set the arguments
CL.clSetKernelArg(kernel0, 0, Sizeof.cl_mem, Pointer.to(srcMemA));
CL.clSetKernelArg(kernel0, 1, Sizeof.cl_mem, Pointer.to(srcMemB));
CL.clSetKernelArg(kernel0, 2, Sizeof.cl_mem, Pointer.to(dstMem0));
// Set work-item dimensions and execute the kernels
long globalWorkSize[] = new long[]{n};
System.out.println("Enqueueing kernels...");
cl_event[] myEventID = new cl_event[1];
myEventID[0] = new cl_event();
clEnqueueNDRangeKernel(commandQueue, kernel0, 1, null, globalWorkSize, null, 0, null, myEventID[0]);
int ID[] = new int[1];
ID[0] = 10;
clSetEventCallback(myEventID[0], CL_COMPLETE, kernelCommandEvent, ID[0]);
clFinish(commandQueue);
System.out.println("Pause for 15000 ms.");
try
{
Thread.sleep(15000);
}
catch(InterruptedException iEx)
{
iEx.printStackTrace();
}
// See if task completed
int[] ok = new int[1];
Arrays.fill(ok, 0);
clGetEventInfo(myEventID[0], CL_EVENT_COMMAND_EXECUTION_STATUS, Sizeof.cl_int, Pointer.to(ok), null);
if (ok[0] == CL_COMPLETE) System.out.println("Task COMPLETE");else System.out.println("Task INCOMPLETE");
}
}
公共类测试\u CPU
{
私有静态字符串programSource0=
“\uu内核无效向量添加(”+
“\u全局常量浮点*a,”+
“全局常量浮点*b,”+
“_全局浮点*c)”+
"{"+
“int gid=get_global_id(0);”+
“c[gid]=a[gid]+b[gid];”+
"}";
/**
*此示例的入口点
*
*@param参数未使用
*/
公共静态void main(字符串参数[])
{
/**
*回调函数,当事件ev具有事件_状态时调用,并以秒为单位显示执行内核的运行时
*@param事件:事件
*@param event_status:事件的状态
*@param user_data:用户提供的数据是一个整数标记,可用于将分析输出与相关内核匹配
*@return:none
*/
EventCallbackFunction kernelCommandEvent=新的EventCallbackFunction()
{
@凌驾
公共无效函数(cl_事件、int事件状态、对象用户数据)
{
int evID=(int)用户_数据;
long[]电动汽车启动时间=新的long[1];
数组填充(ev_开始时间,0);
long[]ev_end_time=新long[1];
数组填充(ev\U end\U时间,0);
long[]返回_字节=新长[1];
双运行时间=0.0;
clGetEventProfilingInfo(事件,CL_PROFILING_命令已排队,Sizeof.CL_long,指针.to(ev_开始时间),返回字节);
clGetEventProfilingInfo(事件,CL_PROFILING_命令_END,Sizeof.CL_long,指针.to(ev_END_time),返回字节);
运行时间=(双精度)(ev_结束时间[0]-ev_开始时间[0]);
System.out.println(“事件内核状态:+CL.stringFor_命令执行状态(事件状态)+”事件ID:“+evID+”运行时:“+String.format”(%8.3f),(运行时*1.0e-6))+”ms.”;
}
};
//初始化输入数据
int n=1000000;
浮点数srcArrayA[]=新浮点数[n];
float srcArrayB[]=新浮点[n];
浮点数据数组0[]=新浮点[n];
对于(inti=0;我没有任何代码,这很难说,但通常情况下,您应该能够将CPU作为一个设备使用,而不需要任何特殊的“环”。没有i3 core duo这样的东西,有两个core的Intel core i3和Intel core duo CPU。请更具体地说明您使用的是哪个CPU。我还认为您的代码可能有不同的问题。许多core i3还包含GPU,主机和设备随后使用芯片的不同部分。和即使您将CPU用作设备,代码也将在单独的线程中运行。无论实际的CPU和内核数如何,大多数OpenCL CPU驱动程序都使用线程进行设备工作,因此主机线程可以在计算和其他设备活动继续进行时继续执行它所执行的操作。您无需调用阻止API进行工作。这就是不正确,排队函数没有阻塞。例如,clenqueueendrangekernel
函数只是将内核放入队列。即使内核尚未完成,主机线程仍将继续执行。谢谢Martin,但请在我上次答复之前查看我的代码,以便让我知道我的错误。如果clFinish(…)指令被注释,我检索任务未完成作为输出,任务完成作为clFinish(…)是取消命名的。您能告诉我为什么以及我的错误在哪里吗?谢谢。是的,clFinsh
等待命令完成,从而阻塞主机线程。但是,clenqueendrangekernel
仍然是非阻塞的。您可以在两次调用之间对主机执行任何您想要的操作。好的,但是在代码结束时,我调用sleep 15秒,但如果不添加clFinish(),则在内核完成时将永远不会调用回调函数,为什么?这是另一个问题。请提出新问题并提供答案。