About Halide
Halide的核心思路不在于其能够自动优化代码,而是将 算法的内容 和 算法的执行 解耦,编写时分开编写。程序猿可以很轻松的根据具体的目标机器,设计并尝试不同的优化策略,从中选择一个最优的策略。
Halide GitHub Repo
How to build Halide
安装
llvm4.0
以上版本,并配置环境变量可以在对应系统的包管理工具下安装
llvm4.0
以上版本:$ brew search llvm ==> Searching local taps... llvm@4 ==> Searching taps on GitHub... ==> Searching blacklisted, migrated and deleted formulae...
这里macOS选择使用
brew
作为包管理工具。配置环境变量
在
shell
工具读取的配置目录文件中添加环境变量以下两条:export LLVM_CONFIG="/usr/local/opt/llvm@4/bin/llvm-config" export CLANG="/usr/local/opt/llvm@4/bin/clang"
直接
make
生成库在${workpath}/bin
下,头文件在${workpath}/include
以及${workpath}/tools
目录下。
Halide 基本语法
Halide 关键字
Algorithm
部分:Halide::func
对应图像流水线处理中的一个步骤。这个func
定义了一个图像中每一个像素应该是什么值。这里只是一个定义。Halide::Var
用于定义func
的变量。Halide::Expr
用于定义一个表达式。Halide::cast
强制类型转换。Halide::min
Halide::Buffer<T>
用于定义缓存
Schedule
部分:Vectorize
,parallelize
,unroll
Halide
在定义func
的时候没有真正计算每个像素点的值,只有在调用func
的realize
方法时才会真正执行。Halide
Debug手段_.compile_to_lowered_stmt("_.html", {}, HTML)
可以将中间结果生成html
预览。trace_stores
用于跟踪执行过程。- 在
func
中直接print
部分内容。 cout
可以打印Expr
的具体表达式内容。_.print_loop_nest()
可以将调度的伪代码打印出来。
Halide Schedule
Default ordering
没有添加任何调度代码的时候,也就是default ordering
的调度时,所有的调度均是串行执行的:
Pseudo-code for the schedule:
produce gradient:
for y:
for x:
gradient(...) = ...
示意图如下所示:
Reorder
对func
调用_.reorder(_,_);
后,可以更改调度的顺序。
调度的伪代码如下:
Pseudo-code for the schedule:
produce gradient_col_major:
for x:
for y:
gradient_col_major(...) = ...
Split a variable 分割变量
对func
调用
Var x_outer, x_inner;
gradient.split(x, x_outer, x_inner, 2);
后,会将第一个参数分为x_outer
个x_inner
部分,然后再分别执行。最后一个参数是factor
,该factor
代表着inner
的块的大小。见下面代码的x_inner in [0, 1]
Pseudo-code for the schedule:
produce gradient_split:
for y:
for x.x_outer:
for x.x_inner in [0, 1]:
gradient_split(...) = ...
Splitting by factors that don’t divide the extent
当不能整数分割的时候,会在临界的地方部分点重复计算(保证不越界)。
Store gradient_split_7x2.0(0, 0) = 0
Store gradient_split_7x2.0(1, 0) = 1
Store gradient_split_7x2.0(2, 0) = 2
Store gradient_split_7x2.0(3, 0) = 3
Store gradient_split_7x2.0(4, 0) = 4
Store gradient_split_7x2.0(5, 0) = 5
Store gradient_split_7x2.0(4, 0) = 4
Store gradient_split_7x2.0(5, 0) = 5
Store gradient_split_7x2.0(6, 0) = 6
Fuse two variables into one 合并变量
对func
调用
Var fused;
gradient.fuse(x, y, fused);
可以将原来的多个合并成一个进行处理。下面的伪代码中原来的两次循环变成了一次循环。
Pseudo-code for the schedule:
produce gradient_fused:
for x.fused:
gradient_fused(...) = ...
Evaluating in tiles 分成一块块执行
将原来的图分割成不同的tiles
,然后一块一块进行执行: