如何创建在多个设备上运行的openCL测试

如何创建在多个设备上运行的openCL测试,opencl,Opencl,我想问一些关于如何创建在多个设备上运行的openCL测试的问题 假设我想创建一个openCL程序来计算表达式AB+CD,这就是我的想法 创建3个内核,一个用于AB,一个用于CD,另一个用于M+N(AB+CD) 创建一个主机代码,并行执行3个任务,每个任务在不同的设备上运行,但我不知道如何为单个任务分配特定的设备 请帮帮我 谢谢从各方面考虑,OpenCL是一个非常明确的API。它要求您在创建上下文时指定特定的设备,并要求您在创建队列时指定特定的上下文。因此,从字面上来说,完成任务非常简单 //Th

我想问一些关于如何创建在多个设备上运行的openCL测试的问题 假设我想创建一个openCL程序来计算表达式AB+CD,这就是我的想法

  • 创建3个内核,一个用于AB,一个用于CD,另一个用于M+N(AB+CD)
  • 创建一个主机代码,并行执行3个任务,每个任务在不同的设备上运行,但我不知道如何为单个任务分配特定的设备
  • 请帮帮我
    谢谢

    从各方面考虑,OpenCL是一个非常明确的API。它要求您在创建上下文时指定特定的设备,并要求您在创建队列时指定特定的上下文。因此,从字面上来说,完成任务非常简单

    //This is going to be pseudocode; I'm not going to look up the literal syntax for this stuff
    //It is going to closely resemble how you'd write this code in C++, though
    std::vector<_type> perform_tasks(cl_device_id ab_device, cl_device_id cd_device, cl_device_id n_m_device) {
        cl_context ab_context = clCreateContext(ab_device);
        cl_context cd_context = clCreateContext(cd_device);
        cl_context n_m_context = clCreateContext(n_m_device);
        cl_command_queue ab_queue = clCreateQueue(ab_context, ab_device);
        cl_command_queue cd_queue = clCreateQueue(cd_context, cd_device);
        cl_command_queue n_m_queue = clCreateQueue(n_m_context, n_m_device);
        cl_kernel ab_kernel = get_ab_kernel(ab_context, ab_device);
        cl_kernel cd_kernel = get_ab_kernel(cd_context, cd_device);
        cl_kernel n_m_kernel = get_ab_kernel(n_m_context, n_m_device);
        set_args_for_ab(ab_kernel);
        set_args_for_cd(cd_kernel);
        set_args_for_n_m(n_m_kernel);
        cl_event events[2];
        clEnqueueKernel(ab_queue, ab_kernel, &events[0]);
        clEnqueueKernel(cd_queue, cd_kernel, &events[1]);
        //Here, I'm assuming that the n_m kernel depends on the results of ab and cd, and thus 
        //must be sequenced afterwards.
        clWaitForEvents(2, events);
        copy_ab_and_cd_data_into_n_m_buffers();
        cl_event n_m_event;
        clEnqueueKernel(n_m_queue, n_m_kernel, &n_m_event);
        clWaitForEvents(1, &n_m_event);
        return copy_n_m_data_to_host();
    }
    
    按照您所建议的程序逻辑,您只需尝试在不同的设备之间传输数据就会产生不可避免的开销(这将发生在
    将\u ab\u和\u cd\u数据\u复制到\u n\u m\u缓冲区()
    中,在我描述的伪代码中)。如果您致力于为此类程序使用多个设备,那么编写以下内容更简单(而且可能更高效!):

    //Again; using pseudocode. Again, gonna look like C++ code.
    cl_event perform_tasks(cl_device_id device, cl_context * context, cl_command_queue * queue, cl_kernel * kernel) {
        *context = clCreateContext(device);
        *queue = clCreateQueue(context, device);
        *kernel = get_kernel();
        cl_event event;
        clEnqueueKernel(queue, kernel, &event);
        return event;
    }
    
    int main() {
        std::vector<cl_device_id> device_ids = get_device_ids();
        std::vector<_type> results;
        std::vector<cl_context> contexts(device_ids.size());
        std::vector<cl_command_queue> queues(device_ids.size());
        std::vector<cl_kernel> kernels(device_ids.size());
        std::vector<cl_event> events;
        for(size_t i = 0; i < device_ids.size(); i++) {
            events.emplace_back(perform_tasks(device_ids[i], &contexts[i], &queues[i], &kernels[i]));
        }
        clWaitForEvents(events.size(), events.data());
        for(cl_command_queue const& queue : queues) {
            std::vector<_type> result = read_results_from_queue(queue);
            results.insert(results.end(), result.begin(), result.end());
        }
        //results now contains the results of all executions
        return 0;
    }
    
    //再次;使用伪代码。再次,看起来像C++代码。
    cl_事件执行_任务(cl_设备_id设备、cl_上下文*上下文、cl_命令_队列*队列、cl_内核*内核){
    *context=clCreateContext(设备);
    *queue=clCreateQueue(上下文、设备);
    *kernel=get_kernel();
    cl_事件;
    clEnqueueKernel(队列、内核和事件);
    返回事件;
    }
    int main(){
    std::vector device_ids=get_device_ids();
    std::矢量结果;
    向量上下文(device_id.size());
    向量队列(device_id.size());
    向量内核(device_id.size());
    向量事件;
    对于(size_t i=0;i

    除非您正在使用FPGA,或者处理特别特殊的工作负载,让不同的设备执行不同的工作是绝对必要的,否则您可能只是为自己创建了比您需要的更多的工作。

    OpenCL是一个非常明确的API。它要求您在创建上下文时指定特定的设备,并要求您在创建队列时指定特定的上下文。因此,从字面上来说,完成任务非常简单

    //This is going to be pseudocode; I'm not going to look up the literal syntax for this stuff
    //It is going to closely resemble how you'd write this code in C++, though
    std::vector<_type> perform_tasks(cl_device_id ab_device, cl_device_id cd_device, cl_device_id n_m_device) {
        cl_context ab_context = clCreateContext(ab_device);
        cl_context cd_context = clCreateContext(cd_device);
        cl_context n_m_context = clCreateContext(n_m_device);
        cl_command_queue ab_queue = clCreateQueue(ab_context, ab_device);
        cl_command_queue cd_queue = clCreateQueue(cd_context, cd_device);
        cl_command_queue n_m_queue = clCreateQueue(n_m_context, n_m_device);
        cl_kernel ab_kernel = get_ab_kernel(ab_context, ab_device);
        cl_kernel cd_kernel = get_ab_kernel(cd_context, cd_device);
        cl_kernel n_m_kernel = get_ab_kernel(n_m_context, n_m_device);
        set_args_for_ab(ab_kernel);
        set_args_for_cd(cd_kernel);
        set_args_for_n_m(n_m_kernel);
        cl_event events[2];
        clEnqueueKernel(ab_queue, ab_kernel, &events[0]);
        clEnqueueKernel(cd_queue, cd_kernel, &events[1]);
        //Here, I'm assuming that the n_m kernel depends on the results of ab and cd, and thus 
        //must be sequenced afterwards.
        clWaitForEvents(2, events);
        copy_ab_and_cd_data_into_n_m_buffers();
        cl_event n_m_event;
        clEnqueueKernel(n_m_queue, n_m_kernel, &n_m_event);
        clWaitForEvents(1, &n_m_event);
        return copy_n_m_data_to_host();
    }
    
    按照您所建议的程序逻辑,您只需尝试在不同的设备之间传输数据就会产生不可避免的开销(这将发生在
    将\u ab\u和\u cd\u数据\u复制到\u n\u m\u缓冲区()
    中,在我描述的伪代码中)。如果您致力于为此类程序使用多个设备,那么编写以下内容更简单(而且可能更高效!):

    //Again; using pseudocode. Again, gonna look like C++ code.
    cl_event perform_tasks(cl_device_id device, cl_context * context, cl_command_queue * queue, cl_kernel * kernel) {
        *context = clCreateContext(device);
        *queue = clCreateQueue(context, device);
        *kernel = get_kernel();
        cl_event event;
        clEnqueueKernel(queue, kernel, &event);
        return event;
    }
    
    int main() {
        std::vector<cl_device_id> device_ids = get_device_ids();
        std::vector<_type> results;
        std::vector<cl_context> contexts(device_ids.size());
        std::vector<cl_command_queue> queues(device_ids.size());
        std::vector<cl_kernel> kernels(device_ids.size());
        std::vector<cl_event> events;
        for(size_t i = 0; i < device_ids.size(); i++) {
            events.emplace_back(perform_tasks(device_ids[i], &contexts[i], &queues[i], &kernels[i]));
        }
        clWaitForEvents(events.size(), events.data());
        for(cl_command_queue const& queue : queues) {
            std::vector<_type> result = read_results_from_queue(queue);
            results.insert(results.end(), result.begin(), result.end());
        }
        //results now contains the results of all executions
        return 0;
    }
    
    //再次;使用伪代码。再次,看起来像C++代码。
    cl_事件执行_任务(cl_设备_id设备、cl_上下文*上下文、cl_命令_队列*队列、cl_内核*内核){
    *context=clCreateContext(设备);
    *queue=clCreateQueue(上下文、设备);
    *kernel=get_kernel();
    cl_事件;
    clEnqueueKernel(队列、内核和事件);
    返回事件;
    }
    int main(){
    std::vector device_ids=get_device_ids();
    std::矢量结果;
    向量上下文(device_id.size());
    向量队列(device_id.size());
    向量内核(device_id.size());
    向量事件;
    对于(size_t i=0;i

    除非您正在使用FPGA,或者正在处理特殊的工作负载,在这种情况下,让不同的设备执行不同的工作是绝对必要的,否则您可能只是在为自己创造比需要更多的工作。

    您在哪里停下来的?您是否选择了平台和设备,然后选择了队列,但无法将任务分配给这些设备?哪个版本的opencl?什么样的设备?什么样的工作分配?你在哪里停下来的?您是否选择了平台和设备,然后选择了队列,但无法将任务分配给这些设备?哪个版本的opencl?什么样的设备?什么样的工作分配?谢谢你,Xirema,我正在做一个openCL测试,它在多个FPGA设备上运行,所以它真的让我很头疼headcahe@tpham1002002等等,你实际上是在处理FPGA的??呵呵。正如我提到的,我提供的第一个代码将处理该模型。但请记住,我最初的断言仍然适用:很少有情况下,将单个计算拆分为多个设备是有意义的,特别是如果计算的子组件在设备之间是相似的。谢谢Xirema,我正在进行一项openCL测试,该测试在多个FPGA设备上运行,因此它确实让我感到不安headcahe@tpham1002002等等,你实际上是在处理FPGA的??呵呵。正如我提到的,我提供的第一个代码将处理该模型。请记住,我最初的断言仍然适用:在很少的情况下,将一个计算拆分为多个设备是有意义的,特别是如果计算的子组件在设备之间是相似的。