C ++ массив для Halide Image (и обратно)

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

Ниже я написал MWE об использовании Halide для копирования массива из одного места в другое. Я предполагал, что это скомпилирует всего лишь несколько инструкций и займет меньше микросекунды для запуска. Вместо этого он производит 4000 строк сборки и требует 40 мс для запуска! Очевидно, поэтому у меня есть существенная дыра в моем понимании.

  1. Каков канонический способ упаковки существующего массива в Halide::Image?
  2. Как должна функционировать copy быть запланирован, чтобы выполнить копию эффективно?

Минимальный рабочий пример

#include <Halide.h>

using namespace Halide;

void _copy(uint8_t* in_ptr, uint8_t* out_ptr, const int M, const int N) {

Image<uint8_t> in(Buffer(UInt(8), N, M, 0, 0, in_ptr));
Image<uint8_t> out(Buffer(UInt(8), N, M, 0, 0, out_ptr));

Var x,y;
Func copy;
copy(x,y) = in(x,y);
copy.realize(out);
}

int main(void) {
uint8_t in[10000], out[10000];
_copy(in, out, 100, 100);
}

Флаги сборника

clang++ -O3 -march=native -std=c++11 -Iinclude -Lbin -lHalide copy.cpp

0

Решение

Позвольте мне начать с вашего второго вопроса: _copy занимает много времени, потому что нужно скомпилировать код Halide в машинный код x86. IIRC, Func кеширует машинный код, но так как copy является локальным для _copy этот кеш не может быть использован повторно. В любом случае, планирование copy это довольно просто, потому что это точечная операция: во-первых, возможно, имеет смысл векторизовать ее. Во-вторых, возможно, имеет смысл распараллелить это (в зависимости от того, сколько там данных). Например:

copy.vectorize (x, 32) .parallel (y);

будет векторизовать вдоль x с размером вектора 32 и распараллелить вдоль y, (Я делаю это по памяти, может быть некоторая путаница с правильными именами.) Конечно, выполнение всего этого также может увеличить время компиляции …

Нет рецепта для хорошего планирования. Я делаю это, глядя на вывод compile_to_lowered_stmt и профилирование кода. Я также использую компиляцию AOT, предоставленную Halide::GeneratorЭто гарантирует, что я измеряю только время выполнения кода, а не время компиляции.

Ваш другой вопрос был, как обернуть существующий массив в Halide::Image, Я не делаю этого, в основном потому, что я использую компиляцию AOT. Однако внутренне Halide использует тип, называемый buffer_t для всего изображения, связанного. Существует также оболочка C ++, которая называется Halide::Buffer что делает использование buffer_t немного проще, я думаю, что это также может быть использовано в Func::realize вместо Halide::Image, Дело в том: если вы понимаете, buffer_t Вы можете завернуть почти все во что-нибудь усваиваемое Halide.

2

Другие решения

Чтобы подчеркнуть первое, что упомянул Флориан, я думаю, что это ключевой момент недопонимания: вы, похоже, рассчитываете время составления copy операция («конвейер», в общих терминах Halide), а не только ее выполнение. Ваша оценка размера кода предположительно также для всего двоичного файла, полученного в результате copy.cpp, а не только код в сгенерированном Halide copy функция (которая на самом деле даже не появится в бинарном файле, который вы компилируете с помощью clang, поскольку он создается только JITing во время выполнения в этой программе).

Вы можете увидеть фактическую стоимость вашего трубопровода здесь, сначала позвонив copy.compile_jit() до realize (realize неявно называет compile_jit при первом запуске, так что в этом нет необходимости, но важно отделить среду выполнения от накладных расходов компиляции). Вы бы тогда поместили свой таймер исключительно вокруг realize,

Если вы действительно хотите предварительно скомпилировать этот (или любой другой) конвейер для статического соединения с вашей конечной программой, что, как вам кажется, вы можете ожидать, то, что вы действительно хотите сделать, это использовать Func::compile_to_file в одной программе для компиляции и выдачи кода (как copy.h а также copy.o), а затем связать и вызвать их в другой программе. Проверьте урок 10, чтобы увидеть это более подробно:

https://github.com/halide/Halide/blob/master/tutorial/lesson_10_aot_compilation_generate.cpp https://github.com/halide/Halide/blob/master/tutorial/lesson_10_aot_compilation_run.cpp

1

По вопросам рекламы [email protected]