Halide 22.0.0 Halide compiler and libraries

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
14 extern "C" int pthread_threadid_np(long thread, uint64_t *thread_id);
15#endif
16
17 namespace Halide {
18 namespace Runtime {
19 namespace Internal {
20
21 enum PrinterType { BasicPrinterType = 0,
22 ErrorPrinterType = 1,
23 StringStreamPrinterType = 2 };
24
25 constexpr uint64_t default_printer_buffer_length = 1024;
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
44 class PrinterBase {
45 protected:
46 char *dst;
47 char *const end;
48 char *const start;
49 void *const user_context;
50
51 NEVER_INLINE void allocation_error() const {
52 halide_error(user_context, "Printer buffer allocation failed.\n");
53 }
54
55 public:
56 // This class will stream text into the range [start, start + size - 1].
57 // It does *not* assume any ownership of the memory; it assumes
58 // the memory will remain valid for its lifespan, and doesn't
59 // attempt to free any allocations. It also doesn't do any sanity
60 // checking of the pointers, so if you pass in a null or bogus value,
61 // it will attempt to use it.
62 NEVER_INLINE PrinterBase(void *user_context_, char *start_, uint64_t size_)
63 : dst(start_),
64 // (If start is null, set end = start to ensure no writes are done)
65 end(start_ ? start_ + size_ - 1 : start_),
66 start(start_),
67 user_context(user_context_) {
68 if (end > start) {
69 // null-terminate the final byte to ensure string isn't $ENDLESS
70 *end = 0;
71 }
72 }
73
74 NEVER_INLINE const char *str() {
75 (void)halide_msan_annotate_memory_is_initialized(user_context, start, dst - start + 1);
76 return start;
77 }
78
79 uint64_t size() const {
80 halide_debug_assert(user_context, dst >= start);
81 return (uint64_t)(dst - start);
82 }
83
84 uint64_t capacity() const {
85 halide_debug_assert(user_context, end >= start);
86 return (uint64_t)(end - start);
87 }
88
89 NEVER_INLINE void clear() {
90 dst = start;
91 if (dst) {
92 dst[0] = 0;
93 }
94 }
95
96 NEVER_INLINE void erase(int n) {
97 if (dst) {
98 dst -= n;
99 if (dst < start) {
100 dst = start;
101 }
102 dst[0] = 0;
103 }
104 }
105
106 struct Float16Bits {
107 uint16_t bits;
108 };
109
110 // These are NEVER_INLINE because Clang will aggressively inline
111 // all of them, but the code size of calling out-of-line here is slightly
112 // smaller, and we ~always prefer smaller code size when using Printer
113 // in the runtime (it's a modest but nonzero difference).
114 NEVER_INLINE PrinterBase &operator<<(const char *arg) {
115 dst = halide_string_to_string(dst, end, arg);
116 return *this;
117 }
118
119 NEVER_INLINE PrinterBase &operator<<(int64_t arg) {
120 dst = halide_int64_to_string(dst, end, arg, 1);
121 return *this;
122 }
123
124 NEVER_INLINE PrinterBase &operator<<(int32_t arg) {
125 dst = halide_int64_to_string(dst, end, arg, 1);
126 return *this;
127 }
128
129 NEVER_INLINE PrinterBase &operator<<(uint64_t arg) {
130 dst = halide_uint64_to_string(dst, end, arg, 1);
131 return *this;
132 }
133
134 NEVER_INLINE PrinterBase &operator<<(uint32_t arg) {
135 dst = halide_uint64_to_string(dst, end, arg, 1);
136 return *this;
137 }
138
139 NEVER_INLINE PrinterBase &operator<<(double arg) {
140 dst = halide_double_to_string(dst, end, arg, 1);
141 return *this;
142 }
143
144 NEVER_INLINE PrinterBase &operator<<(float arg) {
145 dst = halide_double_to_string(dst, end, arg, 0);
146 return *this;
147 }
148
149 NEVER_INLINE PrinterBase &operator<<(Float16Bits arg) {
150 double value = halide_float16_bits_to_double(arg.bits);
151 dst = halide_double_to_string(dst, end, value, 1);
152 return *this;
153 }
154
155 NEVER_INLINE PrinterBase &operator<<(const void *arg) {
156 dst = halide_pointer_to_string(dst, end, arg);
157 return *this;
158 }
159
160 NEVER_INLINE PrinterBase &operator<<(const halide_type_t &t) {
161 dst = halide_type_to_string(dst, end, &t);
162 return *this;
163 }
164
165 NEVER_INLINE PrinterBase &operator<<(const halide_buffer_t &buf) {
166 dst = halide_buffer_to_string(dst, end, &buf);
167 return *this;
168 }
169
170 template<typename... Args>
171 void append(const Args &...args) {
172 ((*this << args), ...);
173 }
174
175 // Not movable, not copyable
176 PrinterBase(const PrinterBase &copy) = delete;
177 PrinterBase &operator=(const PrinterBase &) = delete;
178 PrinterBase(PrinterBase &&) = delete;
179 PrinterBase &operator=(PrinterBase &&) = delete;
180};
181
182 namespace {
183
184 template<PrinterType printer_type, uint64_t buffer_length = default_printer_buffer_length>
185 class HeapPrinter : public PrinterBase {
186 public:
187 NEVER_INLINE explicit HeapPrinter(void *user_context_)
188 : PrinterBase(user_context_, (char *)malloc(buffer_length), buffer_length) {
189 if (!start) {
190 allocation_error();
191 }
192
193#if HALIDE_RUNTIME_PRINTER_LOG_THREADID
194 uint64_t tid;
195 pthread_threadid_np(0, &tid);
196 *this << "(TID:" << tid << ")";
197#endif
198 }
199
200 NEVER_INLINE ~HeapPrinter() {
201 if (printer_type == ErrorPrinterType) {
202 halide_error(user_context, str());
203 } else if (printer_type == BasicPrinterType) {
204 halide_print(user_context, str());
205 } else {
206 // It's a stringstream. Do nothing.
207 }
208
209 free(start);
210 }
211};
212// A class that supports << with all the same types as Printer, but
213// does nothing and should compile to a no-op.
214 class SinkPrinter {
215 public:
216 ALWAYS_INLINE explicit SinkPrinter(void *user_context) {
217 }
218};
219 template<typename T>
220 ALWAYS_INLINE SinkPrinter operator<<(const SinkPrinter &s, T) {
221 return s;
222}
223
224 template<uint64_t buffer_length = default_printer_buffer_length>
225 using BasicPrinter = HeapPrinter<BasicPrinterType, buffer_length>;
226
227 template<uint64_t buffer_length = default_printer_buffer_length>
228 using ErrorPrinter = HeapPrinter<ErrorPrinterType, buffer_length>;
229
230 template<uint64_t buffer_length = default_printer_buffer_length>
231 using StringStreamPrinter = HeapPrinter<StringStreamPrinterType, buffer_length>;
232
233 using print = BasicPrinter<>;
234 using error = ErrorPrinter<>;
235 using stringstream = StringStreamPrinter<>;
236
237#ifdef DEBUG_RUNTIME
238 using debug = BasicPrinter<>;
239#else
240 using debug = SinkPrinter;
241#endif
242
243// A Printer that automatically reserves stack space for the printer buffer, rather than malloc.
244// Note that this requires an explicit buffer_length, and it (generally) should be <= 256.
245 template<PrinterType printer_type, uint64_t buffer_length>
246 class StackPrinter : public PrinterBase {
247 char scratch[buffer_length];
248
249 public:
250 explicit StackPrinter(void *user_context_)
251 : PrinterBase(user_context_, scratch, buffer_length) {
252 static_assert(buffer_length <= 256, "StackPrinter is meant only for small buffer sizes; you are probably making a mistake.");
253 }
254};
255
256 template<uint64_t buffer_length = default_printer_buffer_length>
257 using StackBasicPrinter = StackPrinter<BasicPrinterType, buffer_length>;
258
259 template<uint64_t buffer_length = default_printer_buffer_length>
260 using StackErrorPrinter = StackPrinter<ErrorPrinterType, buffer_length>;
261
262 template<uint64_t buffer_length = default_printer_buffer_length>
263 using StackStringStreamPrinter = StackPrinter<StringStreamPrinterType, buffer_length>;
264
265} // namespace
266
267} // namespace Internal
268} // namespace Runtime
269} // namespace Halide
270#endif
debug
#define debug(n)
For optional debugging during codegen, use the debug macro as follows:
Definition: Debug.h:52
HalideRuntime.h
This file declares the routines used by Halide internally in its runtime.
halide_float16_bits_to_double
double halide_float16_bits_to_double(uint16_t)
Read bits representing a half precision floating point number and return the double that represents t...
halide_msan_annotate_memory_is_initialized
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.
halide_print
void halide_print(void *user_context, const char *)
Print a message to stderr.
halide_error
void halide_error(void *user_context, const char *)
Halide calls this function on runtime errors (for example bounds checking failures).
Halide::Runtime::Internal::PrinterBase
Definition: printer.h:44
Halide::Runtime::Internal::PrinterBase::clear
NEVER_INLINE void clear()
Definition: printer.h:89
Halide::Runtime::Internal::PrinterBase::erase
NEVER_INLINE void erase(int n)
Definition: printer.h:96
Halide::Runtime::Internal::PrinterBase::size
uint64_t size() const
Definition: printer.h:79
Halide::Runtime::Internal::PrinterBase::operator=
PrinterBase & operator=(PrinterBase &&)=delete
Halide::Runtime::Internal::PrinterBase::capacity
uint64_t capacity() const
Definition: printer.h:84
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(float arg)
Definition: printer.h:144
Halide::Runtime::Internal::PrinterBase::append
void append(const Args &...args)
Definition: printer.h:171
Halide::Runtime::Internal::PrinterBase::allocation_error
NEVER_INLINE void allocation_error() const
Definition: printer.h:51
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(uint32_t arg)
Definition: printer.h:134
Halide::Runtime::Internal::PrinterBase::PrinterBase
NEVER_INLINE PrinterBase(void *user_context_, char *start_, uint64_t size_)
Definition: printer.h:62
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(uint64_t arg)
Definition: printer.h:129
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(int32_t arg)
Definition: printer.h:124
Halide::Runtime::Internal::PrinterBase::operator=
PrinterBase & operator=(const PrinterBase &)=delete
Halide::Runtime::Internal::PrinterBase::PrinterBase
PrinterBase(PrinterBase &&)=delete
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(const char *arg)
Definition: printer.h:114
Halide::Runtime::Internal::PrinterBase::PrinterBase
PrinterBase(const PrinterBase &copy)=delete
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(const halide_type_t &t)
Definition: printer.h:160
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(const void *arg)
Definition: printer.h:155
Halide::Runtime::Internal::PrinterBase::end
char *const end
Definition: printer.h:47
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(const halide_buffer_t &buf)
Definition: printer.h:165
Halide::Runtime::Internal::PrinterBase::str
NEVER_INLINE const char * str()
Definition: printer.h:74
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(Float16Bits arg)
Definition: printer.h:149
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(int64_t arg)
Definition: printer.h:119
Halide::Runtime::Internal::PrinterBase::dst
char * dst
Definition: printer.h:46
Halide::Runtime::Internal::PrinterBase::start
char *const start
Definition: printer.h:48
Halide::Runtime::Internal::PrinterBase::operator<<
NEVER_INLINE PrinterBase & operator<<(double arg)
Definition: printer.h:139
Halide::Runtime::Internal::PrinterBase::user_context
void *const user_context
Definition: printer.h:49
Halide::Runtime::Internal::PrinterType
PrinterType
Definition: printer.h:21
Halide::Runtime::Internal::StringStreamPrinterType
@ StringStreamPrinterType
Definition: printer.h:23
Halide::Runtime::Internal::BasicPrinterType
@ BasicPrinterType
Definition: printer.h:21
Halide::Runtime::Internal::ErrorPrinterType
@ ErrorPrinterType
Definition: printer.h:22
Halide::Runtime::Internal::default_printer_buffer_length
constexpr uint64_t default_printer_buffer_length
Definition: printer.h:25
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
Halide::operator<<
std::ostream & operator<<(std::ostream &stream, const Expr &)
Emit an expression on an output stream (such as std::cout) in human-readable form.
Halide::print
Expr print(const std::vector< Expr > &values)
Create an Expr that prints out its value whenever it is evaluated.
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
int64_t
signed __INT64_TYPE__ int64_t
Definition: runtime_internal.h:22
halide_uint64_to_string
WEAK char * halide_uint64_to_string(char *dst, char *end, uint64_t arg, int digits)
halide_debug_assert
#define halide_debug_assert(user_context, cond)
halide_debug_assert() is like halide_assert(), but only expands into a check when DEBUG_RUNTIME is de...
Definition: runtime_internal.h:290
NEVER_INLINE
#define NEVER_INLINE
Definition: runtime_internal.h:54
malloc
void * malloc(size_t)
halide_type_to_string
WEAK char * halide_type_to_string(char *dst, char *end, const halide_type_t *arg)
int32_t
signed __INT32_TYPE__ int32_t
Definition: runtime_internal.h:24
uint16_t
unsigned __INT16_TYPE__ uint16_t
Definition: runtime_internal.h:27
halide_int64_to_string
WEAK char * halide_int64_to_string(char *dst, char *end, int64_t arg, int digits)
halide_pointer_to_string
WEAK char * halide_pointer_to_string(char *dst, char *end, const void *arg)
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: runtime_internal.h:57
uint32_t
unsigned __INT32_TYPE__ uint32_t
Definition: runtime_internal.h:25
halide_double_to_string
WEAK char * halide_double_to_string(char *dst, char *end, double arg, int scientific)
halide_buffer_to_string
WEAK char * halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *arg)
free
void free(void *)
halide_string_to_string
WEAK char * halide_string_to_string(char *dst, char *end, const char *arg)
Halide::Runtime::Internal::PrinterBase::Float16Bits
Definition: printer.h:106
Halide::Runtime::Internal::PrinterBase::Float16Bits::bits
uint16_t bits
Definition: printer.h:107
halide_buffer_t
The raw representation of an image passed around by generated Halide code.
Definition: HalideRuntime.h:1569
halide_type_t
A runtime tag for a type in the halide type system.
Definition: HalideRuntime.h:503
user_context
void * user_context
Definition: vulkan_resources.h:178