【问题标题】:how to create openCL test that run on multiple devices如何创建在多个设备上运行的 openCL 测试
【发布时间】:2017-03-03 06:27:22
【问题描述】:

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

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

请帮帮我 谢谢

【问题讨论】:

  • 你停在哪里了?您是否选择了平台和设备,然后选择了队列,但无法将任务分配给这些设备?
  • 哪个版本的opencl?什么样的设备?什么样的工作分配?

标签: opencl


【解决方案1】:

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();
}

但还有一个更大的问题需要解决,您的问题似乎没有考虑到:为什么?

您希望从这种逻辑中获得什么样的性能提升,而不是简单地编写类似以下内容,在单个设备上执行?

kernel void ab_cd(global _type * a, global _type * b, global _type * c, global _type * d, global _type * output) {
    long id = get_global_id(0);
    output[id] = a[id] * b[id] + c[id] * d[id];
}

使用您提出的那种程序逻辑,您将因为简单地尝试在不同设备之间传输数据而产生不可避免的开销(这将发生在我描述的伪代码中的copy_ab_and_cd_data_into_n_m_buffers() 中)。如果您致力于为此类程序使用多个设备,那么编写这样的内容仍然更简单(并且可能更高效!):

//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;
}

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

【讨论】:

  • 谢谢 Xirema,我正在做一个在多个 FPGA 设备上运行的 openCL 测试,所以真的让我头疼
  • @tpham1002002 等等,您实际上是在 处理 FPGA 的??嗯。好吧,正如我所提到的,我提供的第一个代码将处理该模型。请记住,尽管我最初的断言仍然适用:在很少的情况下将单个计算拆分到多个设备上是有意义的,特别是如果该计算的子组件在设备之间是相似的。
猜你喜欢
  • 2020-03-06
  • 1970-01-01
  • 2016-12-05
  • 1970-01-01
  • 2015-07-24
  • 2016-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多