forked from halide/Halide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlesson_04_debugging_2.cpp
170 lines (142 loc) · 6.44 KB
/
lesson_04_debugging_2.cpp
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
// Halide tutorial lesson 4: Debugging with tracing, print, and print_when
// This lesson demonstrates how to follow what Halide is doing at runtime.
// On linux, you can compile and run it like so:
// g++ lesson_04*.cpp -g -I <path/to/Halide.h> -L <path/to/libHalide.so> -lHalide -lpthread -ldl -o lesson_04 -std=c++17
// LD_LIBRARY_PATH=<path/to/libHalide.so> ./lesson_04
// On os x:
// g++ lesson_04*.cpp -g -I <path/to/Halide.h> -L <path/to/libHalide.so> -lHalide -o lesson_04 -std=c++17
// DYLD_LIBRARY_PATH=<path/to/libHalide.dylib> ./lesson_04
// If you have the entire Halide source tree, you can also build it by
// running:
// make tutorial_lesson_04_debugging_2
// in a shell with the current directory at the top of the halide
// source tree.
#include "Halide.h"
#include <stdio.h>
using namespace Halide;
int main(int argc, char **argv) {
Var x("x"), y("y");
// Printing out the value of Funcs as they are computed.
{
// We'll define our gradient function as before.
Func gradient("gradient");
gradient(x, y) = x + y;
// And tell Halide that we'd like to be notified of all
// evaluations.
gradient.trace_stores();
// Realize the function over an 8x8 region.
printf("Evaluating gradient\n");
Buffer<int> output = gradient.realize({8, 8});
// This will print out all the times gradient(x, y) gets
// evaluated.
// Now that we can snoop on what Halide is doing, let's try our
// first scheduling primitive. We'll make a new version of
// gradient that processes each scanline in parallel.
Func parallel_gradient("parallel_gradient");
parallel_gradient(x, y) = x + y;
// We'll also trace this function.
parallel_gradient.trace_stores();
// Things are the same so far. We've defined the algorithm, but
// haven't said anything about how to schedule it. In general,
// exploring different scheduling decisions doesn't change the code
// that describes the algorithm.
// Now we tell Halide to use a parallel for loop over the y
// coordinate. On Linux we run this using a thread pool and a task
// queue. On OS X we call into grand central dispatch, which does
// the same thing for us.
parallel_gradient.parallel(y);
// This time the printfs should come out of order, because each
// scanline is potentially being processed in a different
// thread. The number of threads should adapt to your system, but
// on linux you can control it manually using the environment
// variable HL_NUM_THREADS.
printf("\nEvaluating parallel_gradient\n");
parallel_gradient.realize({8, 8});
}
// Printing individual Exprs.
{
// trace_stores() can only print the value of a
// Func. Sometimes you want to inspect the value of
// sub-expressions rather than the entire Func. The built-in
// function 'print' can be wrapped around any Expr to print
// the value of that Expr every time it is evaluated.
// For example, say we have some Func that is the sum of two terms:
Func f;
f(x, y) = sin(x) + cos(y);
// If we want to inspect just one of the terms, we can wrap
// 'print' around it like so:
Func g;
g(x, y) = sin(x) + print(cos(y));
printf("\nEvaluating sin(x) + cos(y), and just printing cos(y)\n");
g.realize({4, 4});
}
// Printing additional context.
{
// print can take multiple arguments. It prints all of them
// and evaluates to the first one. The arguments can be Exprs
// or constant strings. This can be used to print additional
// context alongside the value:
Func f;
f(x, y) = sin(x) + print(cos(y), "<- this is cos(", y, ") when x =", x);
printf("\nEvaluating sin(x) + cos(y), and printing cos(y) with more context\n");
f.realize({4, 4});
// It can be useful to split expressions like the one above
// across multiple lines to make it easier to turn on and off
// printing certain values while debugging.
Expr e = cos(y);
// Uncomment the following line to print the value of cos(y)
// e = print(e, "<- this is cos(", y, ") when x =", x);
Func g;
g(x, y) = sin(x) + e;
g.realize({4, 4});
}
// Conditional printing
{
// Both print and trace_stores can produce a lot of output. If
// you're looking for a rare event, or just want to see what
// happens at a single pixel, this amount of output can be
// difficult to dig through. Instead, the function print_when
// can be used to conditionally print an Expr. The first
// argument to print_when is a boolean Expr. If the Expr
// evaluates to true, it returns the second argument and
// prints all of the arguments. If the Expr evaluates to false
// it just returns the second argument and does not print.
Func f;
Expr e = cos(y);
e = print_when(x == 37 && y == 42, e, "<- this is cos(y) at x, y == (37, 42)");
f(x, y) = sin(x) + e;
printf("\nEvaluating sin(x) + cos(y), and printing cos(y) at a single pixel\n");
f.realize({640, 480});
// print_when can also be used to check for values you're not expecting:
Func g;
e = cos(y);
e = print_when(e < 0, e, "cos(y) < 0 at y ==", y);
g(x, y) = sin(x) + e;
printf("\nEvaluating sin(x) + cos(y), and printing whenever cos(y) < 0\n");
g.realize({4, 4});
}
// Printing expressions at compile-time.
{
// The code above builds up a Halide Expr across several lines
// of code. If you're programmatically constructing a complex
// expression, and you want to check the Expr you've created
// is what you think it is, you can also print out the
// expression itself using C++ streams:
Var fizz("fizz"), buzz("buzz");
Expr e = 1;
for (int i = 2; i < 100; i++) {
if (i % 3 == 0 && i % 5 == 0) {
e += fizz * buzz;
} else if (i % 3 == 0) {
e += fizz;
} else if (i % 5 == 0) {
e += buzz;
} else {
e += i;
}
}
std::cout << "Printing a complex Expr: " << e << "\n";
}
printf("Success!\n");
return 0;
}