Halide  20.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 
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 
44 class PrinterBase {
45 protected:
46  char *dst;
47  char *const end;
48  char *const start;
49  void *const user_context;
50 
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() {
76  return start;
77  }
78 
79  uint64_t size() const {
81  return (uint64_t)(dst - start);
82  }
83 
84  uint64_t capacity() const {
86  return (uint64_t)(end - start);
87  }
88 
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 {
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) {
116  return *this;
117  }
118 
120  dst = halide_int64_to_string(dst, end, arg, 1);
121  return *this;
122  }
123 
125  dst = halide_int64_to_string(dst, end, arg, 1);
126  return *this;
127  }
128 
130  dst = halide_uint64_to_string(dst, end, arg, 1);
131  return *this;
132  }
133 
135  dst = halide_uint64_to_string(dst, end, arg, 1);
136  return *this;
137  }
138 
140  dst = halide_double_to_string(dst, end, arg, 1);
141  return *this;
142  }
143 
145  dst = halide_double_to_string(dst, end, arg, 0);
146  return *this;
147  }
148 
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) {
157  return *this;
158  }
159 
162  return *this;
163  }
164 
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;
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
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).
NEVER_INLINE PrinterBase & operator<<(const char *arg)
Definition: printer.h:114
NEVER_INLINE void erase(int n)
Definition: printer.h:96
NEVER_INLINE PrinterBase & operator<<(const halide_type_t &t)
Definition: printer.h:160
NEVER_INLINE PrinterBase & operator<<(Float16Bits arg)
Definition: printer.h:149
void append(const Args &...args)
Definition: printer.h:171
NEVER_INLINE void allocation_error() const
Definition: printer.h:51
NEVER_INLINE PrinterBase(void *user_context_, char *start_, uint64_t size_)
Definition: printer.h:62
NEVER_INLINE PrinterBase & operator<<(uint32_t arg)
Definition: printer.h:134
NEVER_INLINE PrinterBase & operator<<(float arg)
Definition: printer.h:144
NEVER_INLINE PrinterBase & operator<<(int32_t arg)
Definition: printer.h:124
PrinterBase(PrinterBase &&)=delete
PrinterBase(const PrinterBase &copy)=delete
NEVER_INLINE PrinterBase & operator<<(int64_t arg)
Definition: printer.h:119
NEVER_INLINE PrinterBase & operator<<(double arg)
Definition: printer.h:139
NEVER_INLINE PrinterBase & operator<<(const void *arg)
Definition: printer.h:155
NEVER_INLINE PrinterBase & operator<<(uint64_t arg)
Definition: printer.h:129
NEVER_INLINE const char * str()
Definition: printer.h:74
NEVER_INLINE PrinterBase & operator<<(const halide_buffer_t &buf)
Definition: printer.h:165
PrinterBase & operator=(const PrinterBase &)=delete
PrinterBase & operator=(PrinterBase &&)=delete
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,...
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
WEAK char * halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *arg)
signed __INT64_TYPE__ int64_t
void * malloc(size_t)
#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...
WEAK char * halide_uint64_to_string(char *dst, char *end, uint64_t arg, int digits)
WEAK char * halide_double_to_string(char *dst, char *end, double arg, int scientific)
#define NEVER_INLINE
signed __INT32_TYPE__ int32_t
WEAK char * halide_string_to_string(char *dst, char *end, const char *arg)
unsigned __INT16_TYPE__ uint16_t
WEAK char * halide_type_to_string(char *dst, char *end, const halide_type_t *arg)
#define ALWAYS_INLINE
unsigned __INT32_TYPE__ uint32_t
WEAK char * halide_pointer_to_string(char *dst, char *end, const void *arg)
void free(void *)
WEAK char * halide_int64_to_string(char *dst, char *end, int64_t arg, int digits)
The raw representation of an image passed around by generated Halide code.
A runtime tag for a type in the halide type system.
void * user_context