openCL (C++) 中的二进制文件

Binaries in openCL (C++)

假设我在 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.

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

How would I go about pushing

binaries

and

binaries_size

into

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<unsigned char>(binaries, binaries + binaries_size) 中。

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

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

(链接文档中的风味 (5)。)

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

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 }
}

(我必须承认,我仍然认为 brace init 有点吓人。因此,我很难提及它,但为了完整起见我还是应该提及。)

在某些情况下,例如如果你有一个积分向量,你必须小心区分具有大小 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