字节排列顺序OpenCL设备

问题描述:

除了一个GPU,CPU和一个自定义的OpenCL的芯片之间的精确度/准确度/排列不一致,为什么所有的OpenCL例子在网上直接接受主机端的缓冲区?字节排列顺序OpenCL设备

clEnqueueWriteBuffer ( cl_command_queue command, ...) 

__kernel void vecAdd(__global float * c, ..) 
{ 
    int id=get_global_id(0); 
    c[id]=b[id]+a[id] 
} 

让我们假设主机是小端,但设备是big endian和A,B,C,是彩车:

  • 将b和加载非标准化的垃圾?

    • 如果是的话,我是否必须发送一个字节来告诉内核缓冲区endianness?
    • 如果没有,都转换的(使用CPU的4字节SIMD改组?或者在GPU?)缓冲液中的读写操作自动?即使是USE_HOST_PTR(RAM)类型的缓冲区和CL_MEM_READ_WRITE(GDDR)?
    • 如果不知道,就下面的例子功能始终正常工作?

      int endianness_of_device() 
          { 
            unsigned int x = 1; 
            return (( ( (char *)&x) [0])==0?0:1) ; 
          } 
      
          int reverseBytesInt(int bytes) 
          { 
           void * p = &bytes; 
           uchar4 bytesr = ((uchar4 *)p)[0].wzyx; 
           int * p2=(int *)&bytesr; 
           return *p2; 
          } 
      
          float reverseBytesFloat(float bytes) 
          { 
           void * p = &bytes; 
           uchar4 bytesr = ((uchar4 *)p)[0].wzyx; 
           float * p2=(float *)&bytesr; 
           return *p2; 
          } 
      
          uint sizeOf2(uint structSize) 
          { 
           uit mult0=structSize/256;mult0++; 
           return mult0*256; 
          } 
      
          typedef struct 
          { 
           uchar end; 
           uchar sizeRelByteAdr; 
           uchar adrRelByteAdr; 
           uchar idRelByteAdr; 
           uchar valRelByteAdr; 
           uchar woRelByteAdr; 
           int size; 
           uint adr; 
           int id; 
           float val; 
           float wo; 
          }nn_p_n; 
      
      
      
      
          uint malloc(__global uchar * heap, __global uint * mallocCtr, int size) 
          { 
           return (atomic_add(mallocCtr,(uint)size)+(uint)heap); 
          } 
      

帮助像内核:

  __kernel void nn(__global uchar *heap,__global uint * mallocCtr) 
         { 
          int id=get_global_id(0); 
          if(id==0) 
          { 

           nn_p_n * np=(nn_p_n *)malloc(heap,mallocCtr,sizeOf2(sizeof(nn_p_n))); 
           np->end=endianness_of_device(); 
           np->size=sizeOf2(sizeof(nn_p_n)); 
           np->id=9; 
           np->val=99.9f; 

           // lets simulate different endianness 
           np->end=1-endianness_of_device(); 


           np->adr=(uint)np-(uint)heap; 

           mem_fence(CLK_GLOBAL_MEM_FENCE); 
          } 

          if(id==900) 
          { 
           // simulating another device reads buffer 
           for(int i=0;i<1000000;i++){int dummy=0; dummy++; if(dummy>id) dummy++;} 

           nn_p_n n=*((nn_p_n *)&heap[0]); 
           if(n.end!=endianness_of_device()) 
           { 
            n.size=reverseBytesInt(n.size); 
            //if(n.size!=sizeof2(sizeof(nn_p_n))) 
            //{ return; } 
            n.adr=reverseBytesInt(n.adr); 
            n.val=reverseBytesFloat(n.val); 
           } 
           nn_p_n * np=(nn_p_n *)malloc(heap,mallocCtr,sizeOf2(sizeof(nn_p_n))); 
           *np = n; 
          } 

         } 

,因为它正在为我的英特尔iGPU的与目前英特尔CPU和其它机器采用AMD CPU和AMD的GPU不任何字节序问题。未来如果我在英特尔CPU之上获得Nvidia gpu和AMD GPU?

Ofcourse在集群计算,需要涵盖计算机,但关于其他操作系统上运行,并使用相同设备的虚拟操作系统之间有什么字节顺序的情况?那么该设备是一个具有多个排序核心(可能?)的fpga?

最后一个问题:可以在OS力的所有设备,甚至是CPU,成为相同的字节顺序

编辑?(我不这么认为,但可以通过OS在性能成本进行仿真):这是不可能在设备端预处理只读数据。这是矫枉过正在主机侧进行后处理,其被标记为“写”,因为只有1-2元可能已被写入这些元素,而整体数据可能是千兆字节下载到主机。

+0

根据@Gundolf Gundelfinger,没有完美的代码,有完美的硬件设置。 –

传递给内核的参数保证具有正确的字节顺序(因此所有typedefs cl_int等),但缓冲区并非如此。这很有意义,因为缓冲区的内容对于OpenCL来说是完全不透明的:只有用户知道如何理解内部的内容。因此,在进行计算之前(可能通过启动专用内核),执行潜在字节序转换是用户的责任。

换句话说:

__kernel void vecAdd(__global float * c, ..) 

这里,值的c被保证是正确的字节序(指针的字节本身是在正确的设备顺序),但字节指向通过c是为了什么用户设置他们的主机上。

为什么互联网上的所有opencl实例都直接接受主机端缓冲区?

大多数程序都是针对相对狭窄的目标平台进行开发的,其中的特征事先已知:如果它们都是小端,为什么要支持大端?可移植性已经是一个难题,而且我怀疑,在一般情况下,关心字节序的问题在增值很少的情况下会带来额外的复杂性。对绝大多数的程序来说这是不值得的。

如果您认为这种级别的可移植性很有价值,那么您可以选择实施它。

+0

我同意。是否有一个真实世界的OpenCL设备示例与主机的字节序不匹配? – Dithermaster

+0

@Dithermaster我个人不知道任何。 –