【发布时间】:2022-11-03 03:44:16
【问题描述】:
在 sycl 中,我们创建一个像这样的内核:
queue.submit(
[&d_cells, &d_count_occupied](sycl::handler& cgh)
{
auto cells_accessor = d_cells.get_access<sycl::access_mode::read>(cgh);
auto count_accessor =
d_count_occupied.get_access<sycl::access_mode::write>(cgh);
cgh.parallel_for(
d_cells.range(),
[cells_accessor,
count_accessor](sycl::id<3> id, sycl::kernel_handler kh)
{
auto cell = cells_accessor.at(kh, id);
if (cell.is_occupied())
{
sycl::atomic_ref<
unsigned,
sycl::memory_order::relaxed,
sycl::memory_scope::device>
count{count_accessor[0]};
count++;
}
}
);
}
)
该内核采用 2 个缓冲区,其中 1 个保存单元信息,另一个用于计算“占用”单元的数量。现在想象一下,我将d_cells 缓冲区包装到一个知道或不知道占用单元格的类中。我们可以想象提供一个智能函数,它需要用户提供的 lambda 来对单元格进行操作:
class Cell {
bool is_occupied() const;
int get_position() const;
// implementation details.
};
class Grid {
// Apply some user function to all of the occupied cells.
template <typename TFunctor, typename... TArgs>
sycl::event apply_all_occupied(sycl::queue q, TFunctor&& function, TArgs... args);
private:
sycl::buffer<Cell> d_cells;
};
预期的调用模式将是这样的:
sycl::buffer<unsigned> d_count_occupied{
count_occupied.data(), count_occupied.size()};
auto function = [](auto grid_cell, sycl::kernel_handler, auto count_accessor)
{
sycl::atomic_ref<
unsigned,
sycl::memory_order::relaxed,
sycl::memory_scope::device>
count{count_accessor[0]};
count++;
};
grid.apply_all_occupied(queue, function, d_count_occupied).wait_and_throw();
这将非常酷,它大大简化和抽象了“网格”的实现,这很好。但是这里我们有一个问题。用户提供的函子的实现必须能够在设备上运行。因此,提供的缓冲区需要在传递给用户提供的函数之前转换为“访问器”。我们也许可以通过一些元编程来解决它,例如:
template <typename TFunctor, typename... TArgs>
sycl::event apply_all_occupied(sycl::queue q, TFunctor&& function, TArgs... args) {
queue.submit(
[this, function, &args...](sycl::handler& cgh)
{
auto cells_accessor = d_cells_.get_access<sycl::access_mode::write>(cgh);
// Somehow get the access to all of the arguments here?
std::tuple accessors = {args.get_access<sycl::access_mode::read>(cgh), ...};
cgh.parallel_for(
d_cells.range(),
[cells_accessor,
accessors, function](sycl::id<3> id, sycl::kernel_handler kh)
{
auto cell = cells_accessor.at(kh, id);
function(kh, cell, accessors);
}
);
}
但这有严重的问题:
- 用户需要他们的 lambda 来接收一些带有访问器的模棱两可的元组类型。
- 无法为每个
get_access调用自定义访问模式。有没有一种明智的方法来实现这种行为?
【问题讨论】:
标签: c++ c++17 intel sycl dpc++