Двоичные файлы в OpenCL (C )

#c #c 11 #opencl

Вопрос:

Предположим, у меня была программа на OpenCL:

 ...

const unsigned char* binaries;
size_t binaries_size;

assign_binaries(amp;binaries, amp;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, amp;binary_status, amp;err);

...
 

Как бы я стал подталкивать

 binaries
 

и

 binaries_size
 

в

 Binaries
 

?

В документах OpenCL говорится::

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

Однако для меня это не имеет смысла, так как существует очевидное несоответствие типов.

Комментарии:

1. Вот что меня смутило (в приведенной ссылке): typedef vector< vector< unsigned char > > Binaries Что такое vector ? Так ли это std::vector ? Так ли это cl::vector ? Оглядываясь вокруг, я только что обнаружил открытые привязки C — Совместимость : Для заголовка 2.0 мы теперь предполагаем наличие стандартной библиотеки, если не требуется иное. Мы используем std::массив, std::вектор, std::shared_ptr и std::строку повсюду, чтобы безопасно управлять памятью и снизить вероятность повторения предыдущих ошибок управления памятью.

2. В этом случае мой (теперь удаленный) ответ даже мог бы сработать. Вы можете попробовать cl::Program prog = cl::Program(context, device_list, { std::vector<unsigned char>(binaries, binaries binaries_size) }, amp;binary_status, amp;err); . Кстати. используете ли вы OpenCL 1.1 или OpenCL 2.0? (Потому что, по-видимому, существуют различия в отношении vector )

3. ладно, стыдно: мне действительно очень понравился другой ответ … в любом случае, спасибо. Я полагаю, что это OpenCL 1.2.

4. Я все еще могу его восстановить. Я немного забеспокоился, когда понял, что vector в документе OpenCL. это не обязательно std::vector так . (Я должен признать, что я немного разбираюсь в C , но совсем не в OpenCL.) После того, как я узнал, что сейчас в моем 1-м комментарии, это может быть даже полезно.

5. Пожалуйста, взгляните на ссылку совместимости . Они также упомянули, как обращаться с контейнерами до OpenCL 2.0…

Ответ №1:

Как бы я стал подталкивать

 binaries
 

и

 binaries_size
 

в

 Binaries
 

?

Есть много способов добиться этого.

TL;DR: Наиболее компактный код для достижения цели OPs, вероятно,:

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

Более длинная история:

MCVE для демонстрации двух:

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

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

void print(const Binariesamp; binaries)
{
  std::cout << "Binaries: [" << binaries.size() << "]: {n";
  for (const std::vector<unsigned char>amp; 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<unsigned char>(binaries, binaries binaries_size) std::vector .

std::vector предоставляет множество конструкторов. В этом случае используется конструктор с first last итератором и:

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

(Это аромат (5) в связанном документе.)

Однако это может быть ненужным шагом копирования. Предоставление данных в a std::vector<unsigned char> с самого начала может быть использовано для избавления от этого.

Функция push_back() может использоваться с семантикой перемещения (что предотвращает 2-е ненужное глубокое копирование). (Это описано в связанном документе.) (2) Если конструктор внутреннего вектора передается непосредственно в качестве аргумента, это приводит к значению R, которое автоматически запускает семантику перемещения.

Если существует промежуточное хранилище внутреннего вектора (например, в локальной переменной), семантика перемещения все еще может быть принудительной с 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 }
}
 

Живая демонстрация на coliru


Я также добавил инициализацию фигурных скобок (которая в данном случае является инициализацией прямого списка).

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

Живая демонстрация на coliru