簡體   English   中英

kernel function object 中的 sycl/dpc++ 訪問器與 global_ptr

[英]sycl/dpc++ accessor vs. global_ptr in kernel function object

使用 Intel OneAPI beta6 的以下玩具代碼。

#include <CL/sycl.hpp>
#include <iostream>

namespace sycl = cl::sycl;

const int SIZE=1;

class Increment_accessor {
  public:
    Increment_accessor(sycl::accessor<int, 1, sycl::access::mode::read_write, sycl::access::target::global_buffer> ptr_) : ptr {ptr_} {}
    void operator()(sycl::item<1> item) {
      ptr[item.get_linear_id()]++;
    }
  private:
    sycl::accessor<int, 1, sycl::access::mode::read_write, sycl::access::target::global_buffer> ptr;
};

class Increment_pointer {
  public:
    Increment_pointer(sycl::global_ptr<int> ptr_) : ptr {ptr_} {} 
    void operator()(sycl::item<1> item) {
      ptr[item.get_linear_id()]++;
    }
  private:
    sycl::global_ptr<int> ptr;
};

int 
main(int argc, char *argv[])
{
  sycl::device dev = sycl::default_selector().select_device();
  sycl::queue q(dev);
  int hbuffer[SIZE] = {};

  {
    sycl::buffer<int, 1> hbuf(hbuffer, sycl::range<1> {SIZE});
    q.submit([&](sycl::handler& cgh) {
        auto harray = hbuf.get_access<sycl::access::mode::read_write, sycl::access::target::global_buffer>(cgh);
        // !!! Uncomment _one_ of the following lines to compile !!!
        //Increment_accessor increment {harray};
        //Increment_pointer increment {harray};
        //Increment_pointer increment {harray.get_pointer()};
        cgh.parallel_for<class kernel1>(
            sycl::range<1> {SIZE}, 
            increment
        );
      }
      ); 
  }

  for (int i=0; i<SIZE; i++) std::cout << "hbuffer[" << i << "]= " << hbuffer[i] << std::endl;
}

問題:為什么 Increment_pointer 版本“錯誤”? 沒有編譯/運行時錯誤。 您只是沒有在最后獲得遞增的 hbuffer。 (我玩過一些類似的版本,其中 operator() 中的 ptr 最終為 0x0)。

我仍在學習在“SYCL”中思考,因此歡迎詳細解釋。

如果我理解正確,您是在問為什么您的代碼在使用Increment_accessor時有效,但在使用Increment_pointer時中斷。 或者,更一般地說,可以構建一個 kernel function 來接受指針 arguments 而不是訪問器嗎?

SYCL 規范對此不是很清楚,但第 4.7.6.3 節給出了提示:

SYCL 訪問器可以是設備訪問器,在這種情況下它提供對 SYCL kernel function 中數據的訪問,或者主機訪問器在這種情況下它提供對主機的直接訪問。 如果訪問器具有訪問目標 access::target::global_buffer、access::target::constant_buffer、access::target::local、access::target::image 或 access::target::image_array 那么它被認為設備訪問器,因此只能在 SYCL 中使用 kernel function

因此,設備訪問器在主機上無效。 現在,在基於指針的版本中,您正在調用get_pointer() (或依賴從訪問器到指針的隱式轉換,這將是等效的)。 但此時,您仍在命令組 scope 內,而不是在 kernel 內,即parallel_for increment kernel 內的代碼。命令組 scope 始終在 SYCL 中的主機上進行評估,因為在那里構造的訪問器告訴 SYCL 運行時如何構建任務圖以及 SYCL 任務圖中的依賴節點。

因此,我們可以將問題歸結為調用get_pointer()是否已經符合使用設備訪問器的條件。 如果是這樣,則意味着在 SYCL kernel 之外使用了設備訪問器,這違反了規范的引用部分,並且會使此代碼非法。

我認為調用get_pointer()已經對應於“使用訪問器”。 例如, get_pointer()要求訪問器已經具有可以指向的有效設備 memory 分配。 但是,在命令組 scope 中,此分配可能甚至不存在,因為高效的 SYCL 運行時可能只會在需要之前在后台懶惰地在設備 memory 中進行必要的分配。 但是在命令組評估期間,命令組甚至還沒有完全提交給 SYCL 運行時,因為它實際上仍處於提交階段。 因此,SYCL 實現通常無法保證get_pointer()在此階段已經工作。

因此,最好假設主機上的設備訪問器僅僅是對訪問數據的描述,並且只有作為一種在內核內部使用時實際允許數據訪問的機制才具有更多意義。

現在,對於是否有可能讓內核接受指針作為 arguments 而不是訪問器的更普遍的問題:據我所知,在 SYCL 1.2.1 中不可能擁有訪問器並以某種方式將它們轉換為主機上的指針,因為這些問題如上所述。 但是,如果您根本不使用訪問器,則可以使用英特爾統一共享 memory (USM) 擴展。 此擴展尚未出現在常規 SYCL 1.2.1 中,但在英特爾 oneAPI DPC++ 中可用。 USM 允許您顯式創建使用指針管理的設備可訪問分配。 然后您可以直接在內核中使用這些指針。

更新:USM 已合並到 2021 年 2 月發布的官方 SYCL 2020 標准中,現在可用於除 DPC++ 之外的多個 SYCL 實現。

暫無
暫無

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

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