Halide 17.0.2
Halide compiler and libraries
Loading...
Searching...
No Matches
printer.h
Go to the documentation of this file.
1#ifndef HALIDE_RUNTIME_PRINTER_H
2#define HALIDE_RUNTIME_PRINTER_H
3
4#include "HalideRuntime.h"
5
6// This is useful for debugging threading issues in the Halide runtime:
7// prefix all `debug()` statements with the thread id that did the logging.
8// Left here (but disabled) for future reference.
9#ifndef HALIDE_RUNTIME_PRINTER_LOG_THREADID
10#define HALIDE_RUNTIME_PRINTER_LOG_THREADID 0
11#endif
12
13#if HALIDE_RUNTIME_PRINTER_LOG_THREADID
14extern "C" int pthread_threadid_np(long thread, uint64_t *thread_id);
15#endif
16
17namespace Halide {
18namespace Runtime {
19namespace Internal {
20
24
26
27// A class for constructing debug messages from the runtime. Dumps
28// items into a stack array, then prints them when the object leaves
29// scope using halide_print. Think of it as a stringstream that prints
30// when it dies. Use it like this:
31
32// debug(user_context) << "A" << b << c << "\n";
33
34// If you use it like this:
35
36// debug d(user_context);
37// d << "A";
38// d << b;
39// d << c << "\n";
40
41// Then remember the print only happens when the debug object leaves
42// scope, which may print at a confusing time.
43
44namespace {
45template<PrinterType printer_type, uint64_t buffer_length = default_printer_buffer_length>
46class Printer {
47 char *buf, *dst, *end;
48 void *user_context;
49 bool own_mem;
50
51public:
52 explicit Printer(void *ctx, char *mem = nullptr)
53 : user_context(ctx), own_mem(mem == nullptr) {
54 if (mem != nullptr) {
55 buf = mem;
56 } else {
57 buf = (char *)malloc(buffer_length);
58 }
59
60 dst = buf;
61 if (dst) {
62 end = buf + (buffer_length - 1);
63 *end = 0;
64 } else {
65 // Pointers equal ensures no writes to buffer via formatting code
66 end = dst;
67 }
68
69#if HALIDE_RUNTIME_PRINTER_LOG_THREADID
72 *this << "(TID:" << tid << ")";
73#endif
74 }
75
76 // Not movable, not copyable
77 Printer(const Printer &copy) = delete;
78 Printer &operator=(const Printer &) = delete;
79 Printer(Printer &&) = delete;
80 Printer &operator=(Printer &&) = delete;
81
82 Printer &operator<<(const char *arg) {
83 dst = halide_string_to_string(dst, end, arg);
84 return *this;
85 }
86
87 Printer &operator<<(int64_t arg) {
88 dst = halide_int64_to_string(dst, end, arg, 1);
89 return *this;
90 }
91
92 Printer &operator<<(int32_t arg) {
93 dst = halide_int64_to_string(dst, end, arg, 1);
94 return *this;
95 }
96
97 Printer &operator<<(uint64_t arg) {
98 dst = halide_uint64_to_string(dst, end, arg, 1);
99 return *this;
100 }
101
102 Printer &operator<<(uint32_t arg) {
103 dst = halide_uint64_to_string(dst, end, arg, 1);
104 return *this;
105 }
106
107 Printer &operator<<(double arg) {
108 dst = halide_double_to_string(dst, end, arg, 1);
109 return *this;
110 }
111
112 Printer &operator<<(float arg) {
113 dst = halide_double_to_string(dst, end, arg, 0);
114 return *this;
115 }
116
117 Printer &operator<<(const void *arg) {
118 dst = halide_pointer_to_string(dst, end, arg);
119 return *this;
120 }
121
122 Printer &write_float16_from_bits(const uint16_t arg) {
123 double value = halide_float16_bits_to_double(arg);
124 dst = halide_double_to_string(dst, end, value, 1);
125 return *this;
126 }
127
128 Printer &operator<<(const halide_type_t &t) {
129 dst = halide_type_to_string(dst, end, &t);
130 return *this;
131 }
132
133 Printer &operator<<(const halide_buffer_t &buf) {
134 dst = halide_buffer_to_string(dst, end, &buf);
135 return *this;
136 }
137
138 template<typename T>
139 void append(const T &value) {
140 *this << value;
141 }
142
143 template<typename First, typename Second, typename... Rest>
144 void append(const First &first, const Second &second, const Rest &...rest) {
145 append<First>(first);
146 append<Second, Rest...>(second, rest...);
147 }
148
149 // Use it like a stringstream.
150 const char *str() {
151 if (buf) {
154 }
155 return buf;
156 } else {
157 return allocation_error();
158 }
159 }
160
161 // Clear it. Useful for reusing a stringstream.
162 void clear() {
163 dst = buf;
164 if (dst) {
165 dst[0] = 0;
166 }
167 }
168
169 // Returns the number of characters in the buffer
170 uint64_t size() const {
171 return (uint64_t)(dst - buf);
172 }
173
174 uint64_t capacity() const {
175 return buffer_length;
176 }
177
178 // Delete the last N characters
179 void erase(int n) {
180 if (dst) {
181 dst -= n;
182 if (dst < buf) {
183 dst = buf;
184 }
185 dst[0] = 0;
186 }
187 }
188
189 const char *allocation_error() {
190 return "Printer buffer allocation failed.\n";
191 }
192
194 (void)halide_msan_annotate_memory_is_initialized(user_context, buf, dst - buf + 1);
195 }
196
197 ~Printer() {
198 if (!buf) {
199 halide_error(user_context, allocation_error());
200 } else {
203 halide_error(user_context, buf);
204 } else if (printer_type == BasicPrinterType) {
205 halide_print(user_context, buf);
206 } else {
207 // It's a stringstream. Do nothing.
208 }
209 }
210
211 if (own_mem) {
212 free(buf);
213 }
214 }
215};
216
217// A class that supports << with all the same types as Printer, but
218// does nothing and should compile to a no-op.
219class SinkPrinter {
220public:
221 ALWAYS_INLINE explicit SinkPrinter(void *user_context) {
222 }
223};
224template<typename T>
225ALWAYS_INLINE SinkPrinter operator<<(const SinkPrinter &s, T) {
226 return s;
227}
228
229template<uint64_t buffer_length = default_printer_buffer_length>
231
232template<uint64_t buffer_length = default_printer_buffer_length>
234
235template<uint64_t buffer_length = default_printer_buffer_length>
237
238using print = BasicPrinter<>;
239using error = ErrorPrinter<>;
240using stringstream = StringStreamPrinter<>;
241
242#ifdef DEBUG_RUNTIME
243using debug = BasicPrinter<>;
244#else
245using debug = SinkPrinter;
246#endif
247} // namespace
248
249// A Printer that automatically reserves stack space for the printer buffer, rather than malloc.
250// Note that this requires an explicit buffer_length, and it (generally) should be <= 256.
251template<PrinterType printer_type, uint64_t buffer_length>
252class StackPrinter : public Printer<printer_type, buffer_length> {
253 char scratch[buffer_length];
254
255public:
256 explicit StackPrinter(void *ctx)
257 : Printer<printer_type, buffer_length>(ctx, scratch) {
258 static_assert(buffer_length <= 256, "StackPrinter is meant only for small buffer sizes; you are probably making a mistake.");
259 }
260};
261
262template<uint64_t buffer_length = default_printer_buffer_length>
264
265template<uint64_t buffer_length = default_printer_buffer_length>
267
268template<uint64_t buffer_length = default_printer_buffer_length>
270
271} // namespace Internal
272} // namespace Runtime
273} // namespace Halide
274#endif
This file declares the routines used by Halide internally in its runtime.
double halide_float16_bits_to_double(uint16_t)
Read bits representing a half precision floating point number and return the double that represents t...
int halide_msan_annotate_memory_is_initialized(void *user_context, const void *ptr, uint64_t len)
Annotate that a given range of memory has been initialized; only used when Target::MSAN is enabled.
void halide_print(void *user_context, const char *)
Print a message to stderr.
void halide_error(void *user_context, const char *)
Halide calls this function on runtime errors (for example bounds checking failures).
constexpr uint64_t default_printer_buffer_length
Definition printer.h:25
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Expr cast(Expr a)
Cast an expression to the halide type corresponding to the C++ type T.
Definition IROperator.h:364
std::ostream & operator<<(std::ostream &stream, const Expr &)
Emit an expression on an output stream (such as std::cout) in human-readable form.
Expr print(const std::vector< Expr > &values)
Create an Expr that prints out its value whenever it is evaluated.
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
WEAK char * halide_uint64_to_string(char *dst, char *end, uint64_t arg, int digits)
void * malloc(size_t)
WEAK char * halide_type_to_string(char *dst, char *end, const halide_type_t *arg)
signed __INT32_TYPE__ int32_t
unsigned __INT16_TYPE__ uint16_t
WEAK char * halide_int64_to_string(char *dst, char *end, int64_t arg, int digits)
WEAK char * halide_pointer_to_string(char *dst, char *end, const void *arg)
#define ALWAYS_INLINE
unsigned __INT32_TYPE__ uint32_t
WEAK char * halide_double_to_string(char *dst, char *end, double arg, int scientific)
WEAK char * halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *arg)
void free(void *)
WEAK char * halide_string_to_string(char *dst, char *end, const char *arg)
The raw representation of an image passed around by generated Halide code.
A runtime tag for a type in the halide type system.