Halide学习笔记----Halide tutorial源码阅读10

本教程介绍如何使用Halide进行提前编译(AOT),通过两步编译过程,第一步创建Halide pipeline并编译成静态链接库和头文件,第二步使用该静态链接库运行pipeline,实现无需即时编译和Halide库依赖的高效运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Halide入门教程10

// Halide tutorial lesson 10: AOT compilation part 1
    // Halide入门教程第十课:提前编译
    // This lesson demonstrates how to use Halide as an more traditional
    // ahead-of-time (AOT) compiler.
    // 本课程展示了如何用Halide来充当一个传统的提前编译器

    // This lesson is split across two files. The first (this one), builds
    // a Halide pipeline and compiles it to a static library and
    // header. The second (lesson_10_aot_compilation_run.cpp), uses that
    // static library to actually run the pipeline. This means that
    // compiling this code is a multi-step process.
    // 本课程拆分成两个文件,第一个建立Halide pipeline,并且将它编译成静态链接库和相应的头文件,
    // 第二个文件使用静态链接库来运行整个pipeline。这意味着编译这些代码要多个阶段的流程。

    // On linux, you can compile and run it like so:
    // g++ lesson_10*generate.cpp -g -std=c++11 -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_10_generate
    // LD_LIBRARY_PATH=../bin ./lesson_10_generate
    // g++ lesson_10*run.cpp lesson_10_halide.a -std=c++11 -I ../include -lpthread -ldl -o lesson_10_run
    // ./lesson_10_run

    // The benefits of this approach are that the final program:
    // - Doesn't do any jit compilation at runtime, so it's fast.
    // - Doesn't depend on libHalide at all, so it's a small, easy-to-deploy binary.
    // 这种放出的好处是,最终生成的程序:
    // 1.不需要做任何即时编译,因此很快
    // 2.不依赖libHalide库,因此可执行程序很小,容易部署二进制文件


    #include "Halide.h"
    #include <stdio.h>
    using namespace Halide;

    int main(int argc, char **argv) {

        // We'll define a simple one-stage pipeline:
        Func brighter;
        Var x, y;

        // The pipeline will depend on one scalar parameter.
        // 定义输入变量
        Param<uint8_t> offset;

        // And take one grayscale 8-bit input buffer. The first
        // constructor argument gives the type of a pixel, and the second
        // specifies the number of dimensions (not the number of
        // channels!). For a grayscale image this is two; for a color
        // image it's three. Currently, four dimensions is the maximum for
        // inputs and outputs.
        // 定义输入图像,构造函数的第一个变量定义图像数据类型,第二个变量定义图像通道数。
        // 灰度图像为2通道的。当前Halide最大支持4通道的输入输出。
        ImageParam input(type_of<uint8_t>(), 2);

        // If we were jit-compiling, these would just be an int and a
        // Buffer, but because we want to compile the pipeline once and
        // have it work for any value of the parameter, we need to make a
        // Param object, which can be used like an Expr, and an ImageParam
        // object, which can be used like a Buffer.
        // 如果是即时编译的话,这些就是int类型数据和Buffer,但是由于一次编译pipeline,然后对任何参数
        // 都能工作,我们需要Param对象,它可以当做表达式一样使用,ImageParam可以当做Buffer一样使用

        // Define the Func.
        brighter(x, y) = input(x, y) + offset;

        // Schedule it.
        brighter.vectorize(x, 16).parallel(y);

        // This time, instead of calling brighter.realize(...), which
        // would compile and run the pipeline immediately, we'll call a
        // method that compiles the pipeline to a static library and header.
        // 显式调用函数来编译成静态链接库和对应的头文件
        // For AOT-compiled code, we need to explicitly declare the
        // arguments to the routine. This routine takes two. Arguments are
        // usually Params or ImageParams.
        // 对于提前便已代码,我们需要显示生命对应的输入参数。
        brighter.compile_to_static_library("lesson_10_halide", {input, offset}, "brighter");

        printf("Halide pipeline compiled, but not yet run.\n");

        // To continue this lesson, look in the file lesson_10_aot_compilation_run.cpp

        return 0;
    }

这里需要特别说明的是compile_to_static_library函数,它的声明如下

EXPORT void Halide::Pipeline::compile_to_static_library (
    const std::string &filename_prefix,                    //静态链接库和头文件名字的前缀
    const std::vector< Argument > & args,                  // 函数的参数
    const std::string & fn_name,                           // 函数名称
    const Target &  target = get_target_from_environment() // 指定编译成哪种平台的代码,   x86/arm/...
    )       
    //Compile to static-library file and header pair, with the given arguments.
    // 在给定参数的情况下将对应文件编译成静态链接库和头文件
// Halide tutorial lesson 10: AOT compilation part 2
    // Halide入门教程第十课:提前编译
    // Before reading this file, see lesson_10_aot_compilation_generate.cpp

    // This is the code that actually uses the Halide pipeline we've
    // compiled. It does not depend on libHalide, so we won't be including
    // Halide.h.
    // 这部分代码才是实际上使用已经编译过的Halide pipeline.它并不依赖与libHalide。
    // Instead, it depends on the header file that lesson_10_generate
    // produced when we ran it:
    // 但是它依赖于生成器生成的静态链接库和头文件
    #include "lesson_10_halide.h"

    // We want to continue to use our Halide::Buffer with AOT-compiled
    // code, so we explicitly include it. It's a header-only class, and
    // doesn't require libHalide.
    #include "HalideBuffer.h"

    #include <stdio.h>

    int main(int argc, char **argv) {
        // Have a look in the header file above (it won't exist until you've run
        // lesson_10_generate). At the bottom is the signature of the function we generated:

        // int brighter(halide_buffer_t *_input_buffer, uint8_t _offset, halide_buffer_t *_brighter_buffer);
        // 查看生成器生成的头文件中函数的声明格式,按此格式调用函数。

        // The ImageParam inputs have become pointers to "halide_buffer_t"
        // structs. This is struct that Halide uses to represent arrays of
        // data.  Unless you're calling the Halide pipeline from pure C
        // code, you don't want to use it
        // directly. Halide::Runtime::Buffer is a simple wrapper around
        // halide_buffer_t that will implicitly convert to a
        // halide_buffer_t *. We will pass Halide::Runtime::Buffer objects
        // in those slots.

        // The Halide::Buffer class we have been using in JIT code is in
        // fact just a shared pointer to the simpler
        // Halide::Runtime::Buffer class. They share the same API.

        // Finally, the return value of "brighter" is an error code. It's
        // zero on success.

        // Let's make a buffer for our input and output.
        Halide::Runtime::Buffer<uint8_t> input(640, 480), output(640, 480);

        // Halide::Runtime::Buffer also has constructors that wrap
        // existing data instead of allocating new memory. Use these if
        // you have your own Image type that you want to use.

        int offset = 5;
        int error = brighter(input, offset, output); // 调用静态库中的代码

        if (error) {
            printf("Halide returned an error: %d\n", error);
            return -1;
        }

        // Now let's check the filter performed as advertised. It was
        // supposed to add the offset to every input pixel.
        for (int y = 0; y < 480; y++) {
            for (int x = 0; x < 640; x++) {
                uint8_t input_val = input(x, y);
                uint8_t output_val = output(x, y);
                uint8_t correct_val = input_val + offset;
                if (output_val != correct_val) {
                    printf("output(%d, %d) was %d instead of %d\n",
                           x, y, output_val, correct_val);
                    return -1;
                }
            }
        }

        // Everything worked!
        printf("Success!\n");
        return 0;
    }

可以按照第一部分中代码提到的那样,在终端中逐步执行对应的命令,最后得到运行代码。

由于步骤繁多,在这里写成shell脚本,方便执行:

#!/usr/bin/bash
#########################################################################
# File Name: lesson_10_compile.sh
# Author: xxx
# Created Time: Fri 22 Dec 2017 09:56:20 PM CST
#########################################################################

echo "1. compile generator"
g++ lesson_10*generate.cpp -std=c++11 -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_10_generate
echo "2. generate static library"
./lesson_10_generate
echo "3. compile run to generate executive file"
g++ lesson_10*run.cpp lesson_10_halide.a -std=c++11 -I ../include -lpthread -ldl -o lesson_10_run
echo "4. test executive file"
./lesson_10_run

在终端中运行shell脚本

$ sh lesson_10_compile.sh

执行shell脚本
这里写图片描述
生成的生成器、静态链接库、头文件和可执行文件
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值