1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
# Halide tutorial lesson 15: Generators part 2
# This shell script demonstrates how to use a binary containing
# Generators from the command line. Normally you'd call these binaries
# from your build system of choice rather than running them manually
# like we do here.
# This script assumes that you're in the tutorials directory, and the
# generator has been compiled for the current system and is called
# "lesson_15_generate".
# To run this script:
# bash lesson_15_generators_usage.sh
# First we define a helper function that checks that a file exists
check_file_exists()
{
FILE=$1
if [ ! -f $FILE ]; then
echo $FILE not found
exit -1
fi
}
# And another helper function to check if a symbol exists in an object file
check_symbol()
{
FILE=$1
SYM=$2
if !(nm $FILE | grep $SYM > /dev/null); then
echo "$SYM not found in $FILE"
exit -1
fi
}
# Bail out on error
#set -e
# Set up LD_LIBRARY_PATH so that we can find libHalide.so
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:../lib
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:../lib
#########################
# Basic generator usage #
#########################
# First let's compile the first generator for the host system:
./lesson_15_generate -g my_first_generator -o . target=host
# That should create a pair of files in the current directory:
# "my_first_generator.a", and "my_first_generator.h", which define a
# function "my_first_generator" representing the compiled pipeline.
check_file_exists my_first_generator.a
check_file_exists my_first_generator.h
check_symbol my_first_generator.a my_first_generator
#####################
# Cross-compilation #
#####################
# We can also use a generator to compile object files for some other
# target. Let's cross-compile a windows 32-bit object file and header
# for the first generator:
./lesson_15_generate \
-g my_first_generator \
-f my_first_generator_win32 \
-o . \
target=x86-32-windows
# This generates a file called "my_first_generator_win32.lib" in the
# current directory, along with a matching header. The function
# defined is called "my_first_generator_win32".
check_file_exists my_first_generator_win32.lib
check_file_exists my_first_generator_win32.h
################################
# Generating pipeline variants #
################################
# The full set of command-line arguments to the generator binary are:
# -g generator_name : Selects which generator to run. If you only have
# one generator in your binary you can omit this.
# -o directory : Specifies which directory to create the outputs
# in. Usually a build directory.
# -f name : Specifies the name of the generated function. If you omit
# this, it defaults to the generator name.
# -n file_base_name : Specifies the basename of the generated file(s). If
# you omit this, it defaults to the name of the generated function.
# -e static_library,object,c_header,assembly,bitcode,stmt,stmt_html: A list of
# comma-separated values specifying outputs to create. The default is
# "static_library,c_header,registration". "assembly" generates assembly equivalent to the
# generated object file. "bitcode" generates llvm bitcode for the pipeline.
# "stmt" generates human-readable pseudocode for the pipeline (similar to
# setting HL_DEBUG_CODEGEN). "stmt_html" generates an html version of the
# pseudocode, which can be much nicer to read than the raw .stmt file.
# -r file_base_name : Specifies that the generator should create a
# standalone file for just the runtime. For use when generating multiple
# pipelines from a single generator, to be linked together in one
# executable. See example below.
# target=... : The target to compile for.
# my_generator_param=value : The value of your generator params.
# Let's now generate some human-readable pseudocode for the first
# generator:
./lesson_15_generate -g my_first_generator -e stmt -o . target=host
check_file_exists my_first_generator.stmt
# The second generator has generator params, which can be specified on
# the command-line after the target. Let's compile a few different variants:
./lesson_15_generate -g my_second_generator -f my_second_generator_1 -o . \
target=host parallel=false scale=3.0 rotation=ccw output.type=uint16
./lesson_15_generate -g my_second_generator -f my_second_generator_2 -o . \
target=host scale=9.0 rotation=ccw output.type=float32
./lesson_15_generate -g my_second_generator -f my_second_generator_3 -o . \
target=host parallel=false output.type=float64
check_file_exists my_second_generator_1.a
check_file_exists my_second_generator_1.h
check_symbol my_second_generator_1.a my_second_generator_1
check_file_exists my_second_generator_2.a
check_file_exists my_second_generator_2.h
check_symbol my_second_generator_2.a my_second_generator_2
check_file_exists my_second_generator_3.a
check_file_exists my_second_generator_3.h
check_symbol my_second_generator_3.a my_second_generator_3
# Use of these generated object files and headers is exactly the same
# as in lesson 10.
######################
# The Halide runtime #
######################
# Each generated Halide object file contains a simple runtime that
# defines things like how to run a parallel for loop, how to launch a
# cuda program, etc. You can see this runtime in the generated object
# files.
echo "The halide runtime:"
nm my_second_generator_1.a | grep "[SWT] _\?halide_"
# Let's define some functions to check that the runtime exists in a file.
check_runtime()
{
if !(nm $1 | grep "[TSW] _\?halide_" > /dev/null); then
echo "Halide runtime not found in $1"
exit -1
fi
}
check_no_runtime()
{
if nm $1 | grep "[TSW] _\?halide_" > /dev/null; then
echo "Halide runtime found in $1"
exit -1
fi
}
# Declarations and documentation for these runtime functions are in
# HalideRuntime.h
# If you're compiling and linking multiple Halide pipelines, then the
# multiple copies of the runtime should combine into a single copy
# (via weak linkage). If you're compiling and linking for multiple
# different targets (e.g. avx and non-avx), then the runtimes might be
# different, and you can't control which copy of the runtime the
# linker selects.
# You can control this behavior explicitly by compiling your pipelines
# with the no_runtime target flag. Let's generate and link several
# different versions of the first pipeline for different x86 variants:
# (Note that we'll ask the generators to just give us object files ("-e o"),
# instead of static libraries, so that we can easily link them all into a
# single static library.)
./lesson_15_generate \
-g my_first_generator \
-f my_first_generator_basic \
-e object,c_header\
-o . \
target=x86-64-linux-no_runtime
./lesson_15_generate \
-g my_first_generator \
-f my_first_generator_sse41 \
-e object,c_header\
-o . \
target=x86-64-linux-sse41-no_runtime
./lesson_15_generate \
-g my_first_generator \
-f my_first_generator_avx \
-e object,c_header\
-o . \
target=x86-64-linux-avx-no_runtime
# These files don't contain the runtime
check_no_runtime my_first_generator_basic.o
check_symbol my_first_generator_basic.o my_first_generator_basic
check_no_runtime my_first_generator_sse41.o
check_symbol my_first_generator_sse41.o my_first_generator_sse41
check_no_runtime my_first_generator_avx.o
check_symbol my_first_generator_avx.o my_first_generator_avx
# We can then use the generator to emit just the runtime:
./lesson_15_generate \
-r halide_runtime_x86 \
-e object,c_header\
-o . \
target=x86-64-linux
check_runtime halide_runtime_x86.o
# Linking the standalone runtime with the three generated object files
# gives us three versions of the pipeline for varying levels of x86,
# combined with a single runtime that will work on nearly all x86
# processors.
ar q my_first_generator_multi.a \
my_first_generator_basic.o \
my_first_generator_sse41.o \
my_first_generator_avx.o \
halide_runtime_x86.o
check_runtime my_first_generator_multi.a
check_symbol my_first_generator_multi.a my_first_generator_basic
check_symbol my_first_generator_multi.a my_first_generator_sse41
check_symbol my_first_generator_multi.a my_first_generator_avx
echo "Success!"
|