| // This header defines several methods useful for debugging programs that |
| // operate on the Image class supporting images with arbitrary dimensions. |
| // |
| // Image<uint16_t> input = load_image(argv[1]); |
| // |
| // info(input, "input"); // Output the Image header info |
| // dump(input, "input"); // Dump the Image data |
| // stats(input, "input"); // Report statistics for the Image |
| // |
| // |
| #ifndef HALIDE_TOOLS_IMAGE_INFO_H |
| #define HALIDE_TOOLS_IMAGE_INFO_H |
| |
| #include <cassert> |
| #include <cstdlib> |
| #include <limits> |
| #include <memory> |
| #include <iostream> |
| #include <iomanip> |
| #include <sstream> |
| #include <stdint.h> |
| |
| #include "halide_buffer.h" |
| |
| namespace Halide { |
| namespace Tools { |
| |
| static inline void print_dimid(int d, int val) { |
| static const char *dimid[] = {"x", "y", "z", "w"}; |
| int numdimid = 4; |
| if (d < numdimid) { |
| std::cout << " " << dimid[d] << ":" << val; |
| } else { |
| std::cout << " extent[" << d << "]:" << val; |
| } |
| } |
| |
| static inline void print_loc(int32_t *loc, int dim, int32_t *min) { |
| for (int d = 0; d < dim; d++) { |
| if (d) { |
| std::cout << ","; |
| } |
| std::cout << loc[d] + min[d]; |
| } |
| } |
| |
| static inline void print_memalign(intptr_t val) { |
| intptr_t align_chk = 1024*1024; |
| while (align_chk > 0) { |
| if ((val & (align_chk-1)) == 0) { |
| char aunit = ' '; |
| if (align_chk >= 1024) { |
| align_chk >>= 10; |
| aunit = 'K'; |
| } |
| if (align_chk >= 1024) { |
| align_chk >>= 10; |
| aunit = 'M'; |
| } |
| std::cout << "align:" << align_chk; |
| if (aunit != ' ') { |
| std::cout << aunit; |
| } |
| break; |
| } |
| align_chk >>= 1; |
| } |
| } |
| |
| template<typename T> |
| void info(Image<T> &img, const char *tag = "Image") { |
| buffer_t *buf = &(*img); |
| int32_t *min = buf->min; |
| int32_t *extent = buf->extent; |
| int32_t *stride = buf->stride; |
| int dim = img.dimensions(); |
| int img_bpp = buf->elem_size; |
| int img_tsize = sizeof(T); |
| int img_csize = sizeof(Image<T>); |
| int img_bsize = sizeof(buffer_t); |
| int32_t size = 1; |
| uint64_t dev = buf->dev; |
| bool host_dirty = buf->host_dirty; |
| bool dev_dirty = buf->dev_dirty; |
| |
| std::cout << std::endl |
| << "-----------------------------------------------------------------------------"; |
| std::cout << std::endl << "Image info: " << tag |
| << " dim:" << dim << " bpp:" << img_bpp; |
| for (int d = 0; d < dim; d++) { |
| print_dimid(d, extent[d]); |
| size *= extent[d]; |
| } |
| std::cout << std::endl; |
| std::cout << tag << " class = 0x" << std::left << std::setw(10) << (void*)img |
| << std::right << " # "; |
| print_memalign((intptr_t)&img); std::cout << std::endl; |
| std::cout << tag << " class size = "<< img_csize |
| << " (0x"<< std::hex << img_csize << std::dec <<")\n"; |
| std::cout << tag << "-class => [ 0x" << (void*)&img |
| << ", 0x" << (void*)(((char*)&img)+img_csize-1) |
| << " ], # size:" << img_csize << ", "; |
| print_memalign((intptr_t)&img); std::cout << std::endl; |
| std::cout << tag << " buf_t size = "<< img_bsize |
| << " (0x"<< std::hex << img_bsize << std::dec <<")\n"; |
| std::cout << tag << "-buf_t => [ 0x" << (void*)&buf |
| << ", 0x" << (void*)(((char*)&buf)+img_bsize-1) |
| << " ], # size:" << img_bsize << ", "; |
| print_memalign((intptr_t)&buf); std::cout << std::endl; |
| if (img_bpp != img_tsize) { |
| std::cout << tag << " sizeof(T) = " << img_tsize << std::endl; |
| } |
| std::cout << tag << " host_dirty = " << host_dirty << std::endl; |
| std::cout << tag << " dev_dirty = " << dev_dirty << std::endl; |
| std::cout << tag << " dev handle = " << dev << std::endl; |
| std::cout << tag << " elem_size = " << img_bpp << std::endl; |
| std::cout << tag << " img_dim = " << dim << std::endl; |
| std::cout << tag << " width = " << img.width() << std::endl; |
| std::cout << tag << " height = " << img.height() << std::endl; |
| std::cout << tag << " channels = " << img.channels() << std::endl; |
| std::cout << tag << " extent[] = "; |
| for (int d = 0; d < dim; d++) { |
| std::cout << extent[d] << " "; |
| } |
| std::cout << std::endl; |
| std::cout << tag << " min[] = "; |
| for (int d = 0; d < dim; d++) { |
| std::cout << min[d] << " "; |
| } |
| std::cout << std::endl; |
| std::cout << tag << " stride[] = "; |
| for (int d = 0; d < dim; d++) { |
| std::cout << stride[d] << " "; |
| } |
| std::cout << std::endl; |
| if (img_bpp > 1) { |
| for (int d = 0; d < dim; d++) { |
| std::cout << tag << " str[" << d << "]*bpp = " |
| << std::left << std::setw(12) << stride[d] * img_bpp |
| << std::right << " # "; |
| print_memalign(stride[d] * img_bpp); std::cout << std::endl; |
| } |
| } |
| |
| const T *img_data = img.data(); |
| const T *img_next = img_data + size; |
| int32_t img_size = size * img_bpp; |
| int32_t data_size = (char*)img_next - (char*)img_data; |
| std::cout << tag << " size = " << size << " (0x" |
| << std::hex << size << ")" << std::dec << std::endl; |
| std::cout << tag << " img_size = " << img_size << " (0x" |
| << std::hex << img_size << ")" << std::dec << std::endl; |
| std::cout << tag << " data = 0x" << std::left << std::setw(10) << (void *)img_data |
| << std::right << " # "; |
| print_memalign((intptr_t)img_data); std::cout << std::endl; |
| std::cout << tag << " next = 0x" << std::left << std::setw(10) << (void *)img_next |
| << std::right << " # "; |
| print_memalign((intptr_t)img_next); std::cout << std::endl; |
| std::cout << tag << " data_size = " << data_size << " (0x" |
| << std::hex << data_size << ")" << std::dec << std::endl; |
| std::cout << tag << " => [ 0x" << (void *)img_data |
| << ", 0x" << (void *)(((char*)img_next)-1) |
| << "], # size:" << data_size << ", "; |
| print_memalign((intptr_t)img_data); std::cout << std::endl; |
| } |
| |
| template<typename T> |
| void dump(Image<T> &img, const char *tag = "Image") { |
| buffer_t *buf = &(*img); |
| int32_t *min = buf->min; |
| int32_t *extent = buf->extent; |
| int32_t *stride = buf->stride; |
| int dim = img.dimensions(); |
| int bpp = buf->elem_size; |
| int32_t size = 1; |
| |
| std::cout << std::endl << "Image dump: " << tag |
| << " dim:" << dim << " bpp:" << bpp; |
| for (int d = 0; d < dim; d++) { |
| print_dimid(d, extent[d]); |
| size *= extent[d]; |
| } |
| |
| // Arbitrary dimension image traversal |
| const T *ptr = img.data(); |
| int32_t curloc[dim]; |
| for (int d = 1; d < dim; d++) { |
| curloc[d] = -1; |
| } |
| curloc[0] = 0; |
| |
| for (int32_t i = 0; i < size; i++) { |
| // Track changes in position in higher dimensions |
| for (int d = 1; d < dim; d++) { |
| if ((i % stride[d]) == 0) { |
| curloc[d]++; |
| for (int din = 0; din < d; din++) { |
| curloc[din] = 0; |
| } |
| std::cout << std::endl; |
| // Print separators for dimensions beyond (x0,y1) |
| if (d > 1) { |
| print_dimid(d, curloc[d]+min[d]); |
| std::cout << "\n=========================================="; |
| } |
| } |
| } |
| |
| // Check for start of row (or wrap due to width) |
| if ((curloc[0] % 16) == 0) { |
| int widx = 0; |
| std::ostringstream idx; |
| if (dim > 1) { // Multi-dim, just report (x0,y1) on each row |
| idx << "(" << curloc[0]+min[0] << "," << curloc[1]+min[1] << ")"; |
| widx = 12; |
| } else { // Single-dim |
| idx << curloc[0]+min[0]; |
| widx = 4; |
| } |
| std::cout << std::endl << std::setw(widx) << idx.str() << ": "; |
| } |
| |
| // Display data |
| std::cout << std::setw(4) << *ptr++ + 0 << " "; |
| |
| curloc[0]++; // Track position in row |
| } |
| std::cout << std::endl; |
| } |
| |
| template<typename T> |
| void stats(Image<T> &img, const char *tag = "Image") { |
| buffer_t *buf = &(*img); |
| int32_t *min = buf->min; |
| int32_t *extent = buf->extent; |
| int32_t *stride = buf->stride; |
| int dim = img.dimensions(); |
| int bpp = buf->elem_size; |
| int32_t size = 1; |
| std::cout << std::endl << "Image stats: " << tag |
| << " dim:" << dim << " bpp:" << bpp; |
| for (int d = 0; d < dim; d++) { |
| print_dimid(d, extent[d]); |
| size *= extent[d]; |
| } |
| |
| // Arbitrary dimension image traversal |
| const T *ptr = img.data(); |
| int32_t curloc[dim]; |
| for (int d = 1; d < dim; d++) { |
| curloc[d] = -1; |
| } |
| curloc[0] = 0; |
| |
| // Statistics |
| int32_t cnt = 0; |
| double sum = 0; |
| T minval = *ptr; |
| T maxval = *ptr; |
| int32_t minloc[dim]; |
| int32_t maxloc[dim]; |
| for (int d = 0; d < dim; d++) { |
| minloc[d] = 0; |
| maxloc[d] = 0; |
| } |
| |
| for (int32_t i = 0; i < size; i++) { |
| // Track changes in position in higher dimensions |
| for (int d = 1; d < dim; d++) { |
| if ((i % stride[d]) == 0) { |
| curloc[d]++; |
| for (int din = 0; din < d; din++) { |
| curloc[din] = 0; |
| } |
| } |
| } |
| |
| // Collect data |
| T val = *ptr++; |
| sum += val; |
| cnt++; |
| if (val < minval) { |
| minval = val; |
| for (int d = 0; d < dim; d++) { |
| minloc[d] = curloc[d]; |
| } |
| } |
| if (val > maxval) { |
| maxval = val; |
| for (int d = 0; d < dim; d++) { |
| maxloc[d] = curloc[d]; |
| } |
| } |
| |
| curloc[0]++; // Track position in row |
| } |
| |
| double avg = sum / cnt; |
| std::cout << std::endl; |
| std::cout << "min = " << minval + 0 << " @ ("; |
| print_loc(minloc, dim, min); |
| std::cout << ")" << std::endl; |
| std::cout << "max = " << maxval + 0 << " @ ("; |
| print_loc(maxloc, dim, min); |
| std::cout << ")" << std::endl; |
| std::cout << "mean = " << avg << std::endl; |
| std::cout << "N = " << cnt << std::endl; |
| std::cout << std::endl; |
| } |
| |
| } // namespace Tools |
| } // namespace Halide |
| |
| #endif // HALIDE_TOOLS_IMAGE_INFO_H |