Overview
Halide是为了在现代计算机上编写更高性能的图像处理代码而设计的一种编程语言。目前只吃的目标为:
- CPU架构:X86, ARM, MIPS, Hexagon, PowerPC
- 操作系统:Linux, Windows, macOS, Andriod, IOS, Qualcomm QuRT
- GPU计算API: CUDA,OpenGL, OpenCL, Apple Metal, Microsoft Direction X 12
Halide不是独立的一种编程语言,而是嵌入在C++中,这就意味着可以将其集成到C++的工程中,然后编成对象文件,或者在JIT框架中运行。
Getting Started
安装依赖: LLVM
下载源码进行安装, 要求LLVM版本高于9.0:
% git clone --depth 1 --branch llvmorg-10.0.0 https://github.com/llvm/llvm-project.git
编译llvm:
% mkdir llvm-build
% cd llvm-build
% cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../llvm-install \
-DLLVM_ENABLE_PROJECTS="clang;lld;clang-tools-extra" \
-DLLVM_TARGETS_TO_BUILD="X86;ARM;NVPTX;AArch64;Mips;Hexagon" \
-DLLVM_ENABLE_TERMINFO=OFF \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_ENABLE_EH=ON \
-DLLVM_ENABLE_RTTI=ON \
-DLLVM_BUILD_32_BITS=OFF \
../llvm-project/llvm
% cmake --build . --target install -j32
指定LLVM环境到Halide:
% export LLVM_CONFIG=<path to llvm>/llvm-install/bin/llvm-config
编译Halide:
% cd Halide
% mkdir halide_build
% cd halide_build
% make -f ../Makefile
% cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_DIR=/path/to/llvm-install/lib/cmake/llvm ../
% cmake --build . -j32
Halide设计思想
在算法优化过程中,重新组织计算是很困难的:
- Optimizing parallelism, locality requires
- transforming program & data structure
- what transformations are legal
- what transofrmations are beneficial
BLAS, IPP, MKL, OpenCV, MatLab这类的计算库无法解决这样的问题,优化的算子并没有考虑高效的pipeline。
Halide的核心思想是解耦算法和调度,算法采用典型的函数式风格定义要计算什么;调度则指定什么时候如何计算。
Algorithm: What is computed
Schedule: where and when it's computed
优点:
- Easy for programmers to build pipelines
- Easy to specify & explore optimizations(manual or automatic search)
- Easy for the compiler to generate fast code
Halide语言
Algorithm部分:
- Halide::Func 对应图像流水线处理中的一个步骤。这个func定义了一个图像中每一个像素应该是什么值。这里只是一个定义。eg. blur, brighten, harris.
- Halide::Var 用于定义func的变量,该专用语言的抽象变量。eg. x, y, c.
- Halide::Expr 用于定义一个算术表达式,可以包含Func和Var。包含标准的算术运算法和函数(+,-,*,/,**,sqrt, sin, cos,...)
- 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()可以将调度的伪代码打印出来。
Basic Halide program
一个基本的Halide程序:
Image<float> input = load<float>("image/rgb.png")
Var x, y;
Func blur_x;
Func blur_y;
blur_x(x, y) = (input(x,y) + input(x+1, y) + input(x+2, y)) / 3.0;
blur_y(x, y) = (blur_x(x,y) + blur_x(x, y+1) + blur_x(x, y+2)) / 3.0;
Image<float> output = blur_y.realize(input.width() - 2), input.height() -2);
介绍如下:
总结如何创建一个基本的Halide程序:
1. 创建描述Halide程序的C++对象;
2. 构建算术树(Abstract Syntax Tree, AST)
3. 调用realize进行编译,执行
欢迎关注亦梦云烟的微信公众号: 亦梦智能计算