【问题标题】:Binaries in openCL (C++)openCL (C++) 中的二进制文件
【发布时间】:2021-12-04 02:04:30
【问题描述】:

假设我在 openCL 中有一个程序:

...

const unsigned char* binaries;
size_t binaries_size;

assign_binaries(&binaries, &binaries_size); // my assign function, assigns bin and bin_size

std::vector<std::vector<unsigned char>> Binaries;

cl::Program prog = cl::Program(context, device_list, Binaries, &binary_status, &err);

...

我将如何推动

binaries

binaries_size

进入

Binaries

?

OpenCL docs 中,它说:

Binaries: A vector of pairs of a pointer to a binary object and its length.

但是,这对我来说毫无意义,因为存在明显的类型不匹配。

【问题讨论】:

  • 这是我感到困惑的地方(在提供的链接中):typedef vector&lt; vector&lt; unsigned char &gt; &gt; Binaries vector 是什么?是std::vector吗?是cl::vector吗?环顾四周时,我发现Open C++ Bindings - Compatibility对于 2.0 标头,我们现在假设存在标准库,除非另有要求。我们始终使用 std::array、std::vector、std::shared_ptr 和 std::string 来安全地管理内存并减少早期内存管理错误再次发生的机会。
  • 在这种情况下,我(现已删除)的答案甚至可能有效。你可以试试cl::Program prog = cl::Program(context, device_list, { std::vector&lt;unsigned char&gt;(binaries, binaries + binaries_size) }, &amp;binary_status, &amp;err);。顺便提一句。你使用 OpenCL 1.1 还是 OpenCL 2.0? (因为vector好像有区别)
  • 好吧,不好意思:我真的很喜欢另一个答案……无论如何,谢谢。我相信它的 openCL 1.2。
  • 我仍然可以取消删除它。当我意识到 OpenCL 文档中的 vector 时,我有点担心。不一定是std::vector。 (我必须承认我在 C++ 方面有点经验,但对 OpenCL 一点也不了解。)在发现我的第 1 条评论中的内容后,它甚至可能很有价值。
  • 请查看Compatibility 链接。他们还提到了如何在 OpenCL 2.0 之前处理容器......

标签: c++ c++11 opencl


【解决方案1】:

我将如何推动

binaries

binaries_size

进入

Binaries

?

有很多方法可以做到这一点。

TL;DR:实现 OP 意图的最紧凑的代码可能是:

cl::Program prog
  = cl::Program(context, device_list,
    { std::vector<unsigned char>(binaries, binaries + binaries_size) }, 
    &binary_status, &err);

更长的故事:

演示两个的 MCVE:

#include <iomanip>
#include <iostream>
#include <vector>

// the OpenCL typedef
using Binaries = std::vector<std::vector<unsigned char>>;

void print(const Binaries& binaries)
{
  std::cout << "Binaries: [" << binaries.size() << "]: {\n";
  for (const std::vector<unsigned char>& binary : binaries) {
    std::cout << "  [" << binary.size() << "]: {" ;
    const char* sep = " ";
    for (const unsigned char value : binary) {
      std::cout << sep << "0x"
        << std::hex << std::setw(2) << std::setfill('0') << (unsigned)value;
      sep = ", ";
    }
    std::cout << " }\n";
  }
  std::cout << "}\n";
}

int main()
{
  // sample data
  const unsigned char data[] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
  };
  // OPs initial exposure of data
  const unsigned char *binaries = data;
  const size_t binaries_size = std::size(data);
  // filling a Binaries var.:
  Binaries vecBinaries1;
  vecBinaries1.push_back(
    std::vector<unsigned char>(binaries, binaries + binaries_size));
  print(vecBinaries1);
  // or
  const Binaries vecBinaries2(1, std::vector<unsigned char>(binaries, binaries + binaries_size));
  print(vecBinaries2);
}

输出:

Binaries: [1]: {
  [8]: { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
}
Binaries: [1]: {
  [8]: { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
}

请注意,数据是在binaries中准备好的,然后复制到std::vector的构造函数std::vector&lt;unsigned char&gt;(binaries, binaries + binaries_size)中。

std::vector提供多种constructors。在这种情况下,使用带有firstlast 迭代器的构造函数:

template< class InputIt >
vector( InputIt first, InputIt last,
        const Allocator& alloc = Allocator() );

(这是链接文档中(5) 的味道。)

但是,这可能是不必要的复制步骤。从一开始就在std::vector&lt;unsigned char&gt; 中提供数据可以用来摆脱这种情况。

push_back() 可以与移动语义一起使用(这可以防止 2nd 不必要的深层复制)。 (这是链接文档中(2) 的味道。) 如果内部向量的构造函数直接作为参数传递,它会产生一个 RValue,它会自动触发移动语义。

如果有内部向量的中间存储(例如在局部变量中),移动语义仍然可以通过std::move() 强制执行:

  std::vector<unsigned char> vecBinary3(binaries, binaries + binaries_size);
  Binaries vecBinaries3;
  vecBinaries3.push_back(std::move(vecBinary3));
  print(vecBinaries3);

输出:

Binaries: [1]: {
  [8]: { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
}

Live Demo on coliru


我还添加了大括号初始化(在本例中为 direct-list-initialization)。

  const Binaries vecBinaries4 {
    std::vector<unsigned char>(binaries, binaries + binaries_size)
  };
  print(vecBinaries4);

输出:

Binaries: [1]: {
  [8]: { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
}

(我必须承认,我仍然认为大括号初始化。有点吓人。因此,我很难提及它,但为了完整起见,我应该提及它。)

在某些情况下,例如如果您有一个积分向量,则必须小心区分大小为n 和初始填充值的构造函数与具有两个值的初始化列表的构造函数。 对于两者,您必须提供两个整数值,但括号的种类和数量决定了使用哪个构造函数。这很容易导致混乱。

例子:

#include <iostream>
#include <vector>

void print(const std::vector<int>& values)
{
  std::cout << '{';
  const char* sep = " ";
  for (const int value : values) {
    std::cout << sep << value;
    sep = ", ";
  }
  std::cout << " }\n";
}

int main()
{
  // sample 1:
  print({ 1, 2 });
  // sample 2:
  print(std::vector<int>(1, 2));
  // sample 3:
  print(std::vector<int>{ 1, 2 });
  // sample 4:
  print(std::vector<int>({ 1, 2 }));
}

输出:

{ 1, 2 }
{ 2 }
{ 1, 2 }
{ 1, 2 }

Live Demo on coliru

【讨论】:

    猜你喜欢
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 2012-01-11
    • 2020-09-03
    • 2011-02-07
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    相关资源
    最近更新 更多