簡體   English   中英

如何使用PyOpenCL將具有數組和變量的C結構傳遞給OpenCL內核

[英]How to pass a C struct with arrays and variables to OpenCL kernel using PyOpenCL

因此,我必須使用PyOpenCL將一些數據傳遞給OpenCL內核,或者使用Python將一些解決方法傳遞給OpenCL。 數據在內核端作為結構讀取,我無法更改內核cuz,它工作正常,並且是我的代碼必須使用的更大項目的一部分。

內核看起來像這樣:

typedef struct VglClStrEl{ 
    float data[VGL_ARR_CLSTREL_SIZE];
    int ndim;
    int shape[VGL_ARR_SHAPE_SIZE];
    int offset[VGL_ARR_SHAPE_SIZE];
    int size;
} VglClStrEl;

typedef struct VglClShape{ 
    int ndim;
    int shape[VGL_ARR_SHAPE_SIZE];
    int offset[VGL_ARR_SHAPE_SIZE];
    int size;
} VglClShape;

__kernel void kernel(__global unsigned char* img_input, 
                     __global unsigned char* img_output,  
                     __constant VglClShape* img_shape,
                     __constant VglClStrEl* window)
{

    // do what is needed

}

因此,如您所見,VglClShape和VglClStrElEl結構具有不同的類型數組和靜態位大小變量。

[1]解決方法僅支持一種類型數組的結構(或者我悲慘地無法獲得一種處理多種數組類型的方法)。

[2]解決方法是PyOpenCL文檔參考,有關如何將Python數據傳遞到OpenCL內核結構。 這種方法根本不支持數組。

那么,如何傳遞OpenCL內核可以讀取的python數據? 我已經在Python端擁有了所有數據,我只需要知道如何將其從Python傳遞到內核。

在您詢問之前:我正在使用Python 3,並且無法更改內核

是的,數組大小是靜態的。 您可以假設這樣:

VGL_ARR_CLSTREL_SIZE=256;
VGL_ARR_SHAPE_SIZE=20;

[1] 使用PyOpenCL將帶有指針成員的結構傳遞給OpenCL內核

[2] https://documen.tician.de/pyopencl/howto.html#how-to-use-struct-types-with-pyopencl

有一種駭人聽聞的方法來執行此操作,這需要一些乏味的字節爭用。 大概您可以部署小型OpenCL探測內核了嗎? (在任何情況下,PyOpenCL都會在某些操作下進行此操作)

基本思想是:

  • 通過運行單個實例內核,了解OpenCL設備如何對齊結構的所有元素
  • 創建一個numpy字節數組以匹配OpenCL結構的大小
  • 按字節方式將Python結構的每個元素復制到此數組中
  • 調用不可更改的OpenCL內核時,請通過一袋字節緩沖區傳遞此數組

以下內核可以完成這項工作:

__kernel void get_struct_sizes( __global uint *struct_sizes )
{
    const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
    VglClStrEl vgclstrel;
    VglClShape vgclshape;
    uint offset;

    printf("In GPU (probing):\n Kernel instance = %d\n", global_id);

    if (global_id==0) {
        offset = (uint)&(vgclstrel.data);
        struct_sizes[0] = (uint)sizeof(vgclstrel);
        struct_sizes[1] = (uint)&(vgclstrel.ndim)-offset;
        struct_sizes[2] = (uint)&(vgclstrel.shape)-offset;
        struct_sizes[3] = (uint)&(vgclstrel.offset)-offset;
        struct_sizes[4] = (uint)&(vgclstrel.size)-offset;
        offset = (uint)&(vgclshape.ndim);
        struct_sizes[5] = (uint)sizeof(vgclshape);
        struct_sizes[6] = (uint)&(vgclshape.shape)-offset;
        struct_sizes[7] = (uint)&(vgclshape.offset)-offset;
        struct_sizes[8] = (uint)&(vgclshape.size)-offset;
    }
    return;
}

執行此內核並將struct_sizes返回到vgclshape_sizes ,創建以下數組:

img_shape  = np.zeros((vgclshape_sizes[0]), dtype=np.uint8)

並復制到其中:

def copy_into_byte_array(value, byte_array, offset):
        for i,b in enumerate(np.ndarray.tobytes(value)):
            byte_array[i+offset] = b
copy_into_byte_array(ndim,   img_shape, 0) 
copy_into_byte_array(shape,  img_shape, vgclshape_sizes[1]) 
copy_into_byte_array(offset, img_shape, vgclshape_sizes[2]) 
copy_into_byte_array(size,   img_shape, vgclshape_sizes[3]) 

我在這里跳過了一些步驟; 填寫它們,您會發現此方法有效。 我能夠將演示結構傳遞給違規內核的虛擬副本。

我想聽聽是否有更優雅的方法來完成所有這些步驟。 我還希望字節序等方面存在問題,否則這些問題將是透明的。 幸運的話,您可以在他們周圍工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM