Tiramisu Compiler
utils.h
Go to the documentation of this file.
1 #ifndef _TIRAMISU_UTILS
2 #define _TIRAMISU_UTILS
3 
4 #include "Halide.h"
5 #include "tiramisu/debug.h"
6 
7 #include <chrono>
8 #include <iostream>
9 #include <fstream>
10 #include <string>
11 #include <vector>
12 
13 double median(std::vector<std::chrono::duration<double, std::milli>> scores);
14 void print_time(const std::string &file_name, const std::string &kernel_name,
15  const std::vector<std::string> &header_text,
16  const std::vector<double> &time_vector);
17 
18 // TODO(psuriana): init_buffer, print_buffer, copy_buffers, and compare_buffers
19 // assume the buffers can only be at most 3 dimensions. Make the functions
20 // able to handle arbitrary buffer dimension.
21 
22 template<typename T>
23 inline void init_buffer(Halide::Buffer<T> &buf, T val)
24 {
25  for (int z = 0; z < buf.channels(); z++)
26  {
27  for (int y = 0; y < buf.height(); y++)
28  {
29  for (int x = 0; x < buf.width(); x++)
30  {
31  buf(x, y, z) = val;
32  }
33  }
34  }
35 }
36 
37 template<typename T>
38 inline void print_buffer(const Halide::Buffer<T> &buf)
39 {
40  std::string channels_size = ((buf.channels()>1)?std::to_string(buf.channels())+",":"");
41  std::string heigth_size = ((buf.height()>1)?std::to_string(buf.height())+",":"");
42  std::string width_size = ((buf.width()>=0)?std::to_string(buf.width()):"");
43 
44  std::cout << "Printing " << buf.name() << "[" << channels_size << heigth_size << width_size << "]: " << std::endl;
45 
46  for (int z = 0; z < buf.channels(); z++)
47  {
48  for (int y = 0; y < buf.height(); y++)
49  {
50  for (int x = 0; x < buf.width(); x++)
51  {
52  if (std::is_same<T, uint8_t>::value)
53  std::cout << (int)buf(x, y, z);
54  else
55  std::cout << buf(x, y, z);
56 
57  if (x != buf.width() - 1)
58  std::cout << ", ";
59  }
60  std::cout << "\n";
61  }
62  std::cout << ((buf.height()>1)?"\n":"");
63  }
64  std::cout << "\n";
65 }
66 
67 template<typename T>
68 inline void copy_buffer(const Halide::Buffer<T> &from, Halide::Buffer<T> &to)
69 {
70  if ((from.dimensions() > to.dimensions()) || (from.channels() > to.channels()) ||
71  (from.height() > to.height()) || (from.width() > to.width()))
72  {
73  ERROR("'from' has bigger dimension size than 'to'. 'from' size: " +
74  std::to_string(from.dimensions()) + ", 'to' size: " +
75  std::to_string(to.dimensions()) + "\n", true);
76  }
77 
78  for (int z = 0; z < from.channels(); z++)
79  {
80  for (int y = 0; y < from.height(); y++)
81  {
82  for (int x = 0; x < from.width(); x++)
83  {
84  to(x, y, z) = from(x, y, z);
85  }
86  }
87  }
88 }
89 
90 template<typename T>
91 inline void compare_buffers_approximately(const std::string &test, const Halide::Buffer<T> &result,
92  const Halide::Buffer<T> &expected, float threshold)
93 {
94  if ((result.dimensions() != expected.dimensions()) ||
95  (result.channels() != expected.channels()) ||
96  (result.height() != expected.height()) ||
97  (result.width() != expected.width()))
98  {
99  ERROR("result has different dimension size from expected\n", true);
100  }
101 
102  for (int z = 0; z < result.channels(); z++) {
103  for (int y = 0; y < result.height(); y++) {
104  for (int x = 0; x < result.width(); x++) {
105  if ((float) (result(x, y, z) - expected(x, y, z)) > threshold) {
106  ERROR("\033[1;31mTest " + test + " failed. At (" + std::to_string(x) +
107  ", " + std::to_string(y) + ", " + std::to_string(z) + "), expected: " +
108  std::to_string(expected(x, y, z)) + ", got: " +
109  std::to_string(result(x, y, z)) + ".\033[0m\n", false);
110  return;
111  }
112  }
113  }
114  }
115  tiramisu::str_dump("\033[1;32mTest " + test + " succeeded.\033[0m\n");
116 }
117 
118 template<typename T>
119 inline void compare_buffers_approximately(const std::string &test, const Halide::Buffer<T> &result,
120  const Halide::Buffer<T> &expected)
121 {
122  compare_buffers_approximately(test, result, expected, 0.1);
123 }
124 
125 template<typename T>
126 inline void compare_4D_buffers(const std::string &test, const Halide::Buffer<T> &result,
127  const Halide::Buffer<T> &expected, int box)
128 {
129  for (int n = 0; n < result.extent(3); n++) {
130  for (int z = 0; z < result.extent(2); z++) {
131  for (int y = 0; y < result.extent(1)-box; y++) {
132  for (int x = 0; x < result.extent(0)-box; x++) {
133 #if 0
134  std::cout << "Comparing " << result(x, y, z, n) << " and "
135  << expected(x, y, z, n) << " at position " <<
136  "(" + std::to_string(x) + "/" + std::to_string(result.extent(0)-box) + ", " + std::to_string(y) + "/" + std::to_string(result.extent(1)-box) +
137  ", " + std::to_string(z) + "/" + std::to_string(result.extent(2)) + ", " + std::to_string(n) + "/" + std::to_string(result.extent(3)) + ")"
138  << std::endl;
139 #endif
140  if (result(x, y, z, n) != expected(x, y, z, n)) {
141  ERROR("\033[1;31mTest " + test + " failed. At (" + std::to_string(x) +
142  ", " + std::to_string(y) + ", " + std::to_string(z) + ", " + std::to_string(n)+ "), expected: " +
143  std::to_string(expected(x, y, z, n)) + ", got: " +
144  std::to_string(result(x, y, z, n)) + ".\033[0m\n", false);
145  return;
146  }
147  }
148  }
149  }
150  }
151  tiramisu::str_dump("\033[1;32mTest " + test + " succeeded.\033[0m\n");
152 }
153 
154 template<typename T>
155 inline void compare_buffers(const std::string &test, const Halide::Buffer<T> &result,
156  const Halide::Buffer<T> &expected)
157 {
158 /* if ((result.dimensions() != expected.dimensions()) ||
159  (result.channels() != expected.channels()) ||
160  (result.height() != expected.height()) ||
161  (result.width() != expected.width()))
162  {
163  ERROR("result has different dimension size from expected\n", true);
164  }*/
165 
166  for (int z = 0; z < result.channels(); z++) {
167  for (int y = 0; y < result.height(); y++) {
168  for (int x = 0; x < result.width(); x++) {
169  if (result(x, y, z) != expected(x, y, z)) {
170  ERROR("\033[1;31mTest " + test + " failed. At (" + std::to_string(x) +
171  ", " + std::to_string(y) + ", " + std::to_string(z) + "), expected: " +
172  std::to_string(expected(x, y, z)) + ", got: " +
173  std::to_string(result(x, y, z)) + ".\033[0m\n", true);
174  return;
175  }
176  }
177  }
178  }
179  tiramisu::str_dump("\033[1;32mTest " + test + " succeeded.\033[0m\n");
180 }
181 
182 template <typename T>
183 inline void compare_dist_buffers(const std::string &test, const Halide::Buffer<T> &expected_result) {
184  // open the result file
185  std::ifstream result("/tmp/" + test + "_all_ranks.txt");
186  if (result.is_open()) {
187  std::string line;
188  for (int z = 0; z < expected_result.channels(); z++) {
189  for (int y = 0; y < expected_result.height(); y++) {
190  for (int x = 0; x < expected_result.width(); x++) {
191  std::getline(result, line);
192  if (line != std::to_string(expected_result(x, y, z))) {
193  ERROR("\033[1;31mTest " + test + " failed. At (" + std::to_string(x) +
194  ", " + std::to_string(y) + ", " + std::to_string(z) + "), expected: " +
195  std::to_string(expected_result(x, y, z)) + ", got: " +
196  line + ".\033[0m\n", true);
197  return;
198  }
199  }
200  }
201  }
202  } else {
203  assert(false); // TODO put in appropriate error checking
204  }
205 }
206 
207 template <typename T, typename C>
208 inline void store_dist_results(const std::string &test, int rank, const Halide::Buffer<T> &result) {
209  std::ofstream output_file;
210  output_file.open("/tmp/" + test + "_rank_" + std::to_string(rank) + ".txt");
211  for (int z = 0; z < result.channels(); z++) {
212  for (int y = 0; y < result.height(); y++) {
213  for (int x = 0; x < result.width(); x++) {
214  output_file << static_cast<C>(result(x, y, z)) << std::endl;
215  }
216  }
217  }
218  output_file.flush();
219  output_file.close();
220 }
221 
222 // Combine distributed outputs into a single file. Assumes all individual output files are the same size.
223 void combine_dist_results(const std::string &test, std::vector<int> dims, int num_ranks);
224 /**
225  * success: a boolean indicating whether the test succeeded.
226  */
227 inline void print_test_results(const std::string &test, bool success)
228 {
229  if (success == true)
230  tiramisu::str_dump("\033[1;32mTest " + test + " succeeded.\033[0m\n");
231  else
232  ERROR("\033[1;31mTest " + test + " failed.\033[0m\n", false);
233 }
234 
235 
236 /**
237  * Create an array {val1, val2, val1, val2, val1, val2, val1,
238  * val2, ...}.
239  */
240 template<typename T>
241 inline void init_2D_buffer_interleaving(Halide::Buffer<T> &buf, T val1, T val2)
242 {
243  for (int y = 0; y < buf.height(); y++)
244  {
245  for (int x = 0; x < buf.width(); x++)
246  {
247  buf(x, y) = (y % 2 == 0) ? val1 : val2;
248  }
249  }
250 }
251 
253 {
254 public:
255  std::chrono::time_point<std::chrono::system_clock> start_timing, end_timing;
256 
257  void start()
258  {
259  start_timing = std::chrono::system_clock::now();
260  }
261 
262  void stop()
263  {
264  end_timing = std::chrono::system_clock::now();
265  }
266 
267  void print(std::string bench_name)
268  {
269  std::chrono::duration<double> elapsed_seconds = end_timing - start_timing;
270  auto elapsed_micro_seconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed_seconds);
271  std::cout << bench_name << ": " << elapsed_micro_seconds.count() << " micro-seconds\n";
272  }
273 };
274 
275 template <typename T>
276 class optional
277 {
278  T value;
279  bool has_value;
280 
281 public:
282  optional() : has_value(false) {}
283  optional(T value) : value(value), has_value(true) {}
284 
285  explicit operator bool() const
286  {
287  return has_value;
288  }
289 
290  T get()
291  {
292  return value;
293  }
294 };
295 
296 #endif
std::chrono::time_point< std::chrono::system_clock > start_timing
Definition: utils.h:255
void compare_4D_buffers(const std::string &test, const Halide::Buffer< T > &result, const Halide::Buffer< T > &expected, int box)
Definition: utils.h:126
void print(std::string bench_name)
Definition: utils.h:267
void copy_buffer(const Halide::Buffer< T > &from, Halide::Buffer< T > &to)
Definition: utils.h:68
int result
Definition: cuda_ast.h:705
void store_dist_results(const std::string &test, int rank, const Halide::Buffer< T > &result)
Definition: utils.h:208
optional(T value)
Definition: utils.h:283
void print_test_results(const std::string &test, bool success)
success: a boolean indicating whether the test succeeded.
Definition: utils.h:227
void print_time(const std::string &file_name, const std::string &kernel_name, const std::vector< std::string > &header_text, const std::vector< double > &time_vector)
void combine_dist_results(const std::string &test, std::vector< int > dims, int num_ranks)
optional()
Definition: utils.h:282
void stop()
Definition: utils.h:262
void init_buffer(Halide::Buffer< T > &buf, T val)
Definition: utils.h:23
void compare_buffers(const std::string &test, const Halide::Buffer< T > &result, const Halide::Buffer< T > &expected)
Definition: utils.h:155
void print_buffer(const Halide::Buffer< T > &buf)
Definition: utils.h:38
void compare_dist_buffers(const std::string &test, const Halide::Buffer< T > &expected_result)
Definition: utils.h:183
void init_2D_buffer_interleaving(Halide::Buffer< T > &buf, T val1, T val2)
Create an array {val1, val2, val1, val2, val1, val2, val1, val2, ...}.
Definition: utils.h:241
void start()
Definition: utils.h:257
void compare_buffers_approximately(const std::string &test, const Halide::Buffer< T > &result, const Halide::Buffer< T > &expected, float threshold)
Definition: utils.h:91
std::chrono::time_point< std::chrono::system_clock > end_timing
Definition: utils.h:255
double median(std::vector< std::chrono::duration< double, std::milli >> scores)