首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在内核代码中转换C++指针的访问器(尤指。(int (*)[Nelem])

在内核代码中转换C++指针的访问器(尤指。(int (*)[Nelem])
EN

Stack Overflow用户
提问于 2020-05-17 17:25:40
回答 1查看 262关注 0票数 0

环境:Ubuntu18.04,OneAPI beta 6

完整的代码在下面,但是下面是一个令人反感的错误:

代码语言:javascript
运行
复制
#dpcpp -O2 -g -o so2 so2.cpp -lOpenCL -lsycl

so2.cpp:64:38: error: cannot cast from type 'global_ptr<int>' (aka 'multi_ptr<int,  access::address_space::global_space>') to pointer type 'int (*)[nelem]'
                int (*xptr)[nelem] = (int (*)[nelem])xaccessor.get_pointer();                                     
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

如果你想知道为什么..。

在开发数据并行代码时,我经常开发Intel以前称为“元素函数”的程序。编写这些代码是为了对应用程序的单个元素( SYCL称为工作项)进行操作。我一直认为这是一种简单易用的基本SW开发环境,易于测试,而且更易于重用(标量、SIMD、CUDA等)。

在对单个元素进行测试之后,通过扩展调用代码而不必重写/重新测试函数,迁移到数据并行非常容易:

代码语言:javascript
运行
复制
    int x[NELEM]
    fn1(x, NELEM)

变成了

代码语言:javascript
运行
复制
    int x[NPROC][NELEM]
    for (int p=0; p<NPROC; p++) fn1(x[p], NELEM);

在SYCL内核中,fn1(xitem.get_linear_id(),NELEM)将是我所需要的全部,而无需重新调用函数来理解I和/或访问器。

上述代码的SYCL问题是,在内核C++中,我似乎无法重新构造指向2D指针的访问器指针。这在应用程序C++中是允许的(参见上面的代码)。

也许这是正确代码的坏方法,但它使开发/测试代码变得容易,这些代码可以用于标量和数据并行编码,并使库具有一定的可移植性。它还为缓冲区/访问器提供了绕过SYCL 3维限制的方法。

总之,我很好奇一个真正的SYCL程序员会怎么想。

玩具示例的完整代码:

代码语言:javascript
运行
复制
#include <CL/sycl.hpp>
#include <cstdio>

namespace sycl = cl::sycl;

const int Nproc=3;
const int Nelem=4;

/** elemental function **/
void
fn1(int *h, int n)
{
  for (int i=0; i<n; i++) h[i] = 10*h[i]+2*i;
}

int 
main(int argc, char *argv[])
{

  /** Make some memory **/
  int x1d[Nproc * Nelem];
  for (int j=0; j<Nproc; j++) {
    for (int i=0; i<Nelem; i++) x1d[j*Nelem+i] = 10*j+i;
  }
  printf("1D\n");
  for (int i=0; i<Nelem; i++) {
    printf("%d : ", i);
    for (int j=0; j<Nproc; j++) printf("%d ", x1d[j*Nelem+i]);
    printf("\n");
  }

  /** Reshape it into 2D **/
  int (*x2d)[Nelem] = (int (*)[Nelem])x1d;
  for (int j=0; j<Nproc; j++) fn1(x2d[j], Nelem);
  printf("2D\n");
  for (int i=0; i<Nelem; i++) {
    printf("%d : ", i);
    for (int j=0; j<Nproc; j++) printf("%d ", x2d[j][i]);
    printf("\n");
  }

  /** SYCL setup **/
  sycl::device dev = sycl::default_selector().select_device();
  std::cout << "Device: " 
      << "name: " << dev.get_info<sycl::info::device::name>() << std::endl
      << "vendor: " << dev.get_info<sycl::info::device::vendor>() << std::endl;
  sycl::queue q(dev);

  {
    sycl::buffer<int, 1> xbuffer(x1d, sycl::range<1> {Nproc*Nelem});

    q.submit([&](sycl::handler& cgh) {
        int nelem = Nelem;
        auto xaccessor = xbuffer.get_access<sycl::access::mode::read_write, sycl::access::target::global_buffer>(cgh);
        cgh.parallel_for<class k0>(
            sycl::range<1> {Nproc}, 
            [=] (sycl::item<1> item) {
                int idx = item.get_linear_id();
#if 0
                int *xptr = (int *)xaccessor.get_pointer();    // doing this does work so we _can_ get a real pointer
                fn1(xptr + nelem*idx, nelem);
#else
                int (*xptr)[nelem] = (int (*)[nelem])xaccessor.get_pointer();
                //int *ptr = (int *)xaccessor.get_pointer();   // splitting it into two doesn't work either
                //int (*xptr)[nelem] = (int (*)[nelem])ptr;
                fn1(xptr[idx], nelem);
#endif
                }
            );
        }
        ); 
  }
  printf("2D SYCL\n");
  for (int i=0; i<Nelem; i++) {
    printf("%d : ", i);
    for (int j=0; j<Nproc; j++) printf("%d ", x1d[j*Nelem+i]);
    printf("\n");
  }
}

编辑1:

帕卢哈德的评论,我试图充实一些备选方案。

首先,这两句评论似乎应该按照他的建议去做:

代码语言:javascript
运行
复制
    int *ptr = (int *)xaccessor.get_pointer();
    int (*xptr)[nelem] = (int (*)[nelem])ptr;

但实际上,它会产生这样的错误:

代码语言:javascript
运行
复制
    error: cannot initialize a variable of type 'int (*)[nelem]' with an rvalue of type 'int (*)[nelem]'
                int (*xptr)[nelem] = (int (*)[nelem])ptr;
                      ^              ~~~~~~~~~~~~~~~~~~~

将"get()“添加到get_pointer的末尾会产生相同的结果。

奇怪的是,解决了错误的“初始化”部分:

代码语言:javascript
运行
复制
    int *ptr = (int *)xaccessor.get_pointer().get();
    int (*xptr)[nelem];
    xptr = (int (*)[nelem])ptr;

产生有趣的错误:

代码语言:javascript
运行
复制
    error: incompatible pointer types assigning to 'int (*)[nelem]' from 'int (*)[nelem]'
                xptr = (int (*)[nelem])ptr;
                       ^~~~~~~~~~~~~~~~~~~

所以如果某人有时间,我还是很好奇.

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-19 15:12:04

简短回答:不是SYCL问题;)

根据编辑1,很明显,如果行

代码语言:javascript
运行
复制
int *ptr = (int *)xaccessor.get_pointer();
int (*xptr)[nelem] = (int (*)[nelem])ptr;

在第二行中引起转换错误,这不可能是DPC++/SYCL问题,因为只涉及int指针的变化,而且这里没有任何与SYCL相关的内容。

事实上,问题是nelem不是编译时常量.因此,下面的非SYCL测试程序

代码语言:javascript
运行
复制
int main(){
  int nelem = 10;
  int* ptr = nullptr;
  int (*xptr)[nelem] = (int (*)[nelem])ptr;
}

在用常规clang编译或用-pedantic编译gcc时复制您的问题。但是,默认情况下,gcc支持可变长度数组作为C++中的扩展,因此即使代码不是有效的C++,代码也会进行编译。

按照nelem的要求,通过将C++转换为编译时常量可以解决问题。可变长度数组是较新版本的C的一部分,但不是C++的一部分。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61855921

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档