Halide
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 namespace {
45 template<PrinterType printer_type, uint64_t buffer_length = default_printer_buffer_length>
46 class Printer {
47  char *buf, *dst, *end;
48  void *user_context;
49  bool own_mem;
50 
51 public:
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
70  uint64_t tid;
71  pthread_threadid_np(0, &tid);
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) {
152  if (printer_type == StringStreamPrinterType) {
153  msan_annotate_is_initialized();
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 
193  void msan_annotate_is_initialized() {
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 {
201  msan_annotate_is_initialized();
202  if (printer_type == ErrorPrinterType) {
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.
219 class SinkPrinter {
220 public:
221  ALWAYS_INLINE explicit SinkPrinter(void *user_context) {
222  }
223 };
224 template<typename T>
225 ALWAYS_INLINE SinkPrinter operator<<(const SinkPrinter &s, T) {
226  return s;
227 }
228 
229 template<uint64_t buffer_length = default_printer_buffer_length>
230 using BasicPrinter = Printer<BasicPrinterType, buffer_length>;
231 
232 template<uint64_t buffer_length = default_printer_buffer_length>
233 using ErrorPrinter = Printer<ErrorPrinterType, buffer_length>;
234 
235 template<uint64_t buffer_length = default_printer_buffer_length>
236 using StringStreamPrinter = Printer<StringStreamPrinterType, buffer_length>;
237 
238 using print = BasicPrinter<>;
239 using error = ErrorPrinter<>;
240 using stringstream = StringStreamPrinter<>;
241 
242 #ifdef DEBUG_RUNTIME
243 using debug = BasicPrinter<>;
244 #else
245 using 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.
251 template<PrinterType printer_type, uint64_t buffer_length>
252 class StackPrinter : public Printer<printer_type, buffer_length> {
253  char scratch[buffer_length];
254 
255 public:
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 
262 template<uint64_t buffer_length = default_printer_buffer_length>
264 
265 template<uint64_t buffer_length = default_printer_buffer_length>
267 
268 template<uint64_t buffer_length = default_printer_buffer_length>
270 
271 } // namespace Internal
272 } // namespace Runtime
273 } // namespace Halide
274 #endif
int32_t
signed __INT32_TYPE__ int32_t
Definition: runtime_internal.h:24
halide_double_to_string
WEAK char * halide_double_to_string(char *dst, char *end, double arg, int scientific)
halide_type_to_string
WEAK char * halide_type_to_string(char *dst, char *end, const halide_type_t *arg)
uint16_t
unsigned __INT16_TYPE__ uint16_t
Definition: runtime_internal.h:27
Halide::Runtime::Internal::PrinterType
PrinterType
Definition: printer.h:21
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::Runtime::Internal::StringStreamPrinterType
@ StringStreamPrinterType
Definition: printer.h:23
halide_type_t
A runtime tag for a type in the halide type system.
Definition: HalideRuntime.h:476
halide_buffer_to_string
WEAK char * halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *arg)
Halide::Runtime::Internal::StackPrinter
Definition: printer.h:252
uint64_t
unsigned __INT64_TYPE__ uint64_t
Definition: runtime_internal.h:23
malloc
void * malloc(size_t)
Halide
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
Definition: AbstractGenerator.h:19
halide_error
void halide_error(void *user_context, const char *)
Halide calls this function on runtime errors (for example bounds checking failures).
Halide::print
Expr print(const std::vector< Expr > &values)
Create an Expr that prints out its value whenever it is evaluated.
int64_t
signed __INT64_TYPE__ int64_t
Definition: runtime_internal.h:22
Halide::Runtime::Internal::ErrorPrinterType
@ ErrorPrinterType
Definition: printer.h:22
Halide::Runtime::Internal::StackPrinter::StackPrinter
StackPrinter(void *ctx)
Definition: printer.h:256
halide_int64_to_string
WEAK char * halide_int64_to_string(char *dst, char *end, int64_t arg, int digits)
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: runtime_internal.h:55
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_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.
HalideRuntime.h
free
void free(void *)
halide_buffer_t
The raw representation of an image passed around by generated Halide code.
Definition: HalideRuntime.h:1490
halide_uint64_to_string
WEAK char * halide_uint64_to_string(char *dst, char *end, uint64_t arg, int digits)
halide_pointer_to_string
WEAK char * halide_pointer_to_string(char *dst, char *end, const void *arg)
halide_print
void halide_print(void *user_context, const char *)
Print a message to stderr.
halide_string_to_string
WEAK char * halide_string_to_string(char *dst, char *end, const char *arg)
Halide::Runtime::Internal::BasicPrinterType
@ BasicPrinterType
Definition: printer.h:21
uint32_t
unsigned __INT32_TYPE__ uint32_t
Definition: runtime_internal.h:25
Halide::Runtime::Internal::default_printer_buffer_length
constexpr uint64_t default_printer_buffer_length
Definition: printer.h:25