C++数组到Halide Image(和背面)

C++ array to Halide Image (and back)

本文关键字:背面 Image 数组 Halide C++      更新时间:2023-10-16

我刚开始使用Halide,虽然我已经掌握了它设计的基本原理,但我正在努力解决高效调度计算所需的细节(读作:魔术)

我在下面发布了一个使用Halide将数组从一个位置复制到另一个位置的MWE。我曾以为这只会编译成少数指令,运行时间不到一微秒。相反,它生产了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

让我从您的第二个问题开始:_copy需要很长时间,因为它需要将Halide代码编译为x86机器代码。IIRC,Func缓存机器代码,但由于copy_copy的本地缓存,因此无法重用该缓存。无论如何,调度copy是非常简单的,因为它是一个逐点操作:首先,将其矢量化可能是有意义的。其次,将其并行化可能有意义(取决于数据量)。例如:

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

将以32的向量大小沿CCD_ 8进行矢量化并沿y进行并行化。(我是根据记忆编的,可能会对正确的名称感到困惑。)当然,这样做也可能会增加编译时间。。。

没有好的日程安排的良方。我通过查看compile_to_lowered_stmt的输出并分析代码来实现这一点。我还使用了Halide::Generator提供的AOT编译,这确保了我只测量代码的运行时间,而不是编译时间。

您的另一个问题是,如何将现有数组封装在Halide::Image中。我不这么做,主要是因为我使用了AOT编译。然而,Halide内部使用一种称为buffer_t的类型来处理所有与图像相关的内容。还有一个名为Halide::Buffer的C++包装器,它使使用buffer_t变得更容易,我认为它也可以用于Func::realize而不是Halide::Image。重点是:如果你理解buffer_t,你几乎可以把所有东西都包装成Halide可以消化的东西。

为了强调Florian提到的第一件事,我认为这是这里误解的关键点:您似乎在为copy操作(常见的Halide术语中的"管道")的编译计时,而不仅仅是它的执行。您的代码大小估计可能也是针对copy.cpp产生的整个二进制文件,而不仅仅是Halide生成的copy函数中的代码(它实际上甚至不会出现在您使用clang编译的二进制文件中,因为它只是由JITing在该程序的运行时构建的)。

通过在realize之前先调用copy.compile_jit(),可以观察到管道的实际成本(realize在第一次运行时隐式调用compile_jit,因此没有必要,但将运行时与编译开销分开是很有价值的)。然后,您可以将计时器完全设置在realize附近。

如果你真的想预编译这个(或任何其他)管道,以便静态链接到你的最终程序中,这似乎是你所期望的,那么你真正想做的是在一个程序中使用Func::compile_to_file来编译和发出代码(如copy.hcopy.o),然后在另一个程序中将它们链接和调用。查看教程第10课,了解更多详细信息:

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