Как правильно использовать закрепленную память в ArrayFire?

Спецификатор формата

% n - это разделитель строк, который переносится через операционные системы. Однако он не может использоваться в качестве аргумента для функций System.out.print или System.out.println.

Рекомендуется использовать эту новую версию разделителя строк выше\n.

0
задан ZRP 31 March 2019 в 02:34
поделиться

1 ответ

Я Прадип и один из разработчиков ArrayFire.

Во-первых, все бэкэнды функций ArrayFire (CUDA и OpenCL) имеют некоторую стоимость запуска, которая включает прогрев устройства и / или кэширование ядра (ядра кэшируются при первом вызове определенной функции). По этой причине вы замечаете лучшее время выполнения после первого запуска. Это также является причиной, по которой мы почти всегда настоятельно рекомендуем использовать встроенную функцию timeit для определения времени кода массива, поскольку он усредняется по ряду прогонов, а не по первому прогону.

Как вы уже поняли из своих экспериментов, всегда лучше держать закрепленные распределения памяти контролируемым образом. Если вы еще не знаете о компромиссах, возникающих при использовании закрепленной памяти, вы можете начать с этого поста в блоге от NVIDIA (в равной степени это относится к закрепленной памяти из бэкэнда OpenCL, с любыми специфическими ограничениями, конечно, для разных поставщиков). ). Общее руководство, предложенное в сообщении с гиперссылкой, выглядит следующим образом:

Не следует чрезмерно выделять закрепленную память. Это может снизить общую производительность системы, поскольку уменьшает объем физической памяти, доступной операционной системе и другим программам. Слишком много сложно сказать заранее, поэтому, как и во всех оптимизациях, протестируйте свои приложения и системы, на которых они работают, на предмет оптимальных параметров производительности.

Если возможно, я бы выбрал следующий путь, чтобы использовать закрепленную память для ваших БПФ

  1. Инкапсулировать закрепленные распределения / освобождения в формате RAII, который вы уже сейчас делаете из Ваше отредактированное описание.
  2. Делайте закрепленное выделение памяти только один раз, если это возможно, если ваш размер данных статичен.

Кроме них, я думаю, что ваша функция неверна в двух отношениях. Я перейду к функции в порядке строк.

af :: af_cdouble * device_ptr = af :: pinned (signal.size ());

Этот вызов не выделяет память на устройстве / графическом процессоре. Это заблокированная страница памяти на хосте, RAM.

af :: array s (signal.size (), device_ptr, afDevice);

Поскольку af :: pinned не выделяет память устройства, он не является устройством указатель и перечисление afHost. Таким образом, вызов будет af::array s(signal.size(), ptr);

Вы сами используете s.write правильно, но я считаю, что это не нужно в вашем случае использования.

Следующее, что я буду делать.

  • Использовать конструкцию RAII для указателя, возвращенного af::pinned, и выделить его только один раз. Убедитесь, что у вас не слишком много этих заблокированных страниц.
  • Используйте распределение с блокировкой страницы в качестве обычного распределения хоста вместо std::vector<complex>, потому что это память хоста, просто блокировка страницы. Это потребует написания дополнительного кода на стороне вашего хоста, если вы работаете на std::vector каким-либо образом. В противном случае вы можете просто использовать RAIIed-закрепленный указатель для хранения ваших данных.
  • Все, что вам нужно сделать, это перенести ваши данные БПФ на устройство: af::array s(size, ptr)

При этом операции, которые вам потребуются во времени, будут перенесены с закрепленной памяти на графический процессор, последний вызов в приведенном выше списке; исполнение fft; скопировать обратно на хост.

0
ответ дан pradeep 31 March 2019 в 02:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: