Compiling the pipeline#
// Halide tutorial lesson 10: AOT compilation: compiling the pipeline
// This lesson demonstrates how to use Halide as an more traditional
// ahead-of-time (AOT) compiler.
// 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.
// On linux, you can compile and run it like so:
// g++ lesson_10*generate.cpp -g -std=c++17 -I <path/to/include> -L <path/to/lib> -lHalide -lpthread -ldl -o lesson_10_generate
// LD_LIBRARY_PATH=<path/to/lib> ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -std=c++17 -I <path/to/include> -lpthread -ldl -o lesson_10_run
// ./lesson_10_run
// On macOS:
// g++ lesson_10*generate.cpp -g -std=c++17 -I <path/to/include> -L <path/to/lib> -lHalide -o lesson_10_generate
// DYLD_LIBRARY_PATH=<path/to/lib> ./lesson_10_generate
// g++ lesson_10*run.cpp lesson_10_halide.a -std=c++17 -o lesson_10_run -I <path/to/include>
// ./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.
#include "Halide.h"
#include <cstdio>
using namespace Halide;
int main() {
// 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.
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.
// 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;
}
#!/usr/bin/python3
# Halide tutorial lesson 10.
# This lesson demonstrates how to use Halide as an more traditional
# ahead-of-time (AOT) compiler.
# This lesson is split across two files. The first (this one), builds
# a Halide pipeline and compiles it to an object file, a header and
# a Python extension. The second (lesson_10_aot_compilation_run.py),
# uses that object file to actually run the pipeline. This means that
# compiling this code is a multi-step process.
# 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.
import halide as hl
def main():
# We'll define a simple one-stage pipeline:
brighter = hl.Func("brighter")
x, y = hl.Var("x"), hl.Var("y")
# The pipeline will depend on one scalar parameter.
offset = hl.Param(hl.UInt(8), name="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.
input = hl.ImageParam(hl.UInt(8), 2)
# If we were jit-compiling, these would just be an int and a
# hl.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
# hl.Param object, which can be used like an hl.Expr, and an hl.ImageParam
# object, which can be used like a hl.Buffer.
# Define the hl.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 an object file 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.
fname = "lesson_10_halide"
brighter.compile_to(
{
hl.OutputFileType.object: f"{fname}.o",
hl.OutputFileType.python_extension: f"{fname}.py.cpp",
},
[input, offset],
fname,
)
print("Halide pipeline compiled, but not yet run.")
# To continue this lesson, look in the file
# lesson_10_aot_compilation_run.py
return 0
if __name__ == "__main__":
main()