SYCL/DPC++ cpu 版本给出了正确的结果,但 gpu 给出了不正确的数据

Posted

技术标签:

【中文标题】SYCL/DPC++ cpu 版本给出了正确的结果,但 gpu 给出了不正确的数据【英文标题】:SYCL/DPC++ cpu version gives correct result, but gpu gives incorrect data 【发布时间】:2021-08-30 12:59:17 【问题描述】:

我使用 intel dpc++ 编译器编译并运行了以下代码。使用 cpu 选择器时我得到了正确的结果,但 gpu 选择器给出了垃圾值。

我的代码所做的只是将一个名为 data 的数组初始化为全 1。在 sycl 内核中,对该数组的访问器乘以 3 并保存到结果数组中。我尝试在结果数组中打印值,该数组预计全为 3,但我得到了垃圾值。

因为我在 gpu 上执行代码时收到垃圾值。我尝试在 cpu 选择器上运行,这里的代码没有问题。

我在 linux 和 windows 上试过这个。编译器版本dpcpp 2021.3

#include "iostream"
#include<CL/sycl.hpp>
#include <array>
using namespace std;
using namespace sycl;
int main()         
    
    sycl::gpu_selector selector;   
    //using cpu selector as in the line below works
    //sycl::cpu_selector selector;    
    sycl::queue q = sycl::queue(selector);
    std::cout << q.get_device().get_info<sycl::info::device::name>();    
    constexpr int size = 3;
    std::array<int, size> data1,1,1;
    std::array<int, size> resultarray;
    range<1> num_items size ;
    buffer<int, 1> data_buff(data.data(), num_items);
    buffer<int, 1> result(resultarray.data(), num_items);

    
    
    q.submit([&](sycl::handler& cgh) 
        
        auto dataAccess = data_buff.get_access<access::mode::read_write>(cgh);
        auto resultAccess = result.get_access<access::mode::write>(cgh);
        cgh.parallel_for(num_items, [=](id<1>  i)
            
                resultAccess[i] = dataAccess[i] * 3;
            );

        ).wait();


    std::cout <<"||"<< resultarray[0]<<"||"; //expected result ||3||

有人能帮忙解释一下为什么代码在 GPU 上会给出错误的结果吗?

【问题讨论】:

【参考方案1】:

您没有触发复制回主机。大概在 CPU 上,你的 SYCL 实现只是决定直接对输入指针进行操作,所以你看不到问题。

想一想:SYCL 实现如何知道resultarray 正在您的cout 中使用,并且必须将数据复制回来?它不能,因为这种内存访问不通过任何 SYCL 构造。因此它无法知道它必须将数据复制回来。 wait() 只会让主机等待内核完成,不会触发副本。

触发必要副本的最重要方法是:

使用缓冲区写回:默认情况下,从主机指针构造的缓冲区会将缓冲区析构函数中的内容写回构造它们的数据指针(缓冲区中还有成员函数可以手动启用/禁用此功能) .在您的情况下,将缓冲区声明和内核包装在额外的 中就足够了,因为这样缓冲区将在您的 cout 之前超出范围,并触发回写。 使用host_accessor 而不是直接访问resultarray 使用显式handler::copy()

【讨论】:

以上是关于SYCL/DPC++ cpu 版本给出了正确的结果,但 gpu 给出了不正确的数据的主要内容,如果未能解决你的问题,请参考以下文章

sycl/dpc++ 访问器与内核函数对象中的 global_ptr

在 dpc++ malloc_shared 我们可以在 2 个 gpus 之间共享一个缓冲区吗

相同算法的 C++ 和 Python 版本给出不同的结果

Spark 使用左外连接给出不正确的结果

本地存储没有给出正确的结果

cuda 内核通过增加网格大小给出不正确的结果