astcenc_diagnostic_trace.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // SPDX-License-Identifier: Apache-2.0
  2. // ----------------------------------------------------------------------------
  3. // Copyright 2021-2022 Arm Limited
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  6. // use this file except in compliance with the License. You may obtain a copy
  7. // of the License at:
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. // License for the specific language governing permissions and limitations
  15. // under the License.
  16. // ----------------------------------------------------------------------------
  17. /**
  18. * @brief This module provides a set of diagnostic tracing utilities.
  19. *
  20. * Overview
  21. * ========
  22. *
  23. * The built-in diagnostic trace tool generates a hierarchical JSON tree structure. The tree
  24. * hierarchy contains three levels:
  25. *
  26. * - block
  27. * - pass
  28. * - candidate
  29. *
  30. * One block node exists for each compressed block in the image. One pass node exists for each major
  31. * pass (N partition, M planes, O components) applied to a block. One candidate node exists for each
  32. * encoding candidate trialed for a pass.
  33. *
  34. * Each node contains both the hierarchy but also a number of attributes which explain the behavior.
  35. * For example, the block node contains the block coordinates in the image, the pass explains the
  36. * pass configuration, and the candidate will explain the candidate encoding such as weight
  37. * decimation, refinement error, etc.
  38. *
  39. * Trace Nodes are designed as scope-managed C++ objects with stack-like push/pop behavior.
  40. * Constructing a trace node on the stack will automatically add it to the current node as a child,
  41. * and then make it the current node. Destroying the current node will pop the stack and set the
  42. * parent to the current node. This provides a robust mechanism for ensuring reliable nesting in the
  43. * tree structure.
  44. *
  45. * A set of utility macros are provided to add attribute annotations to the current trace node.
  46. *
  47. * Usage
  48. * =====
  49. *
  50. * Create Trace Nodes on the stack using the @c TRACE_NODE() macro. This will compile-out completely
  51. * in builds with diagnostics disabled.
  52. *
  53. * Add annotations to the current trace node using the @c trace_add_data() macro. This will
  54. * similarly compile out completely in builds with diagnostics disabled.
  55. *
  56. * If you need to add additional code to support diagnostics-only behavior wrap
  57. * it in preprocessor guards:
  58. *
  59. * #if defined(ASTCENC_DIAGNOSTICS)
  60. * #endif
  61. */
  62. #ifndef ASTCENC_DIAGNOSTIC_TRACE_INCLUDED
  63. #define ASTCENC_DIAGNOSTIC_TRACE_INCLUDED
  64. #if defined(ASTCENC_DIAGNOSTICS)
  65. #include <iostream>
  66. #include <fstream>
  67. #include <vector>
  68. /**
  69. * @brief Class representing a single node in the trace hierarchy.
  70. */
  71. class TraceNode
  72. {
  73. public:
  74. /**
  75. * @brief Construct a new node.
  76. *
  77. * Constructing a node will push to the the top of the stack, automatically making it a child of
  78. * the current node, and then setting it to become the current node.
  79. *
  80. * @param format The format template for the node name.
  81. * @param ... The format parameters.
  82. */
  83. TraceNode(const char* format, ...);
  84. /**
  85. * @brief Add an attribute to this node.
  86. *
  87. * Note that no quoting is applied to the @c value, so if quoting is needed it must be done by
  88. * the caller.
  89. *
  90. * @param type The type of the attribute.
  91. * @param key The key of the attribute.
  92. * @param value The value of the attribute.
  93. */
  94. void add_attrib(std::string type, std::string key, std::string value);
  95. /**
  96. * @brief Destroy this node.
  97. *
  98. * Destroying a node will pop it from the top of the stack, making its parent the current node.
  99. * It is invalid behavior to destroy a node that is not the current node; usage must conform to
  100. * stack push-pop semantics.
  101. */
  102. ~TraceNode();
  103. /**
  104. * @brief The number of attributes and child nodes in this node.
  105. */
  106. unsigned int m_attrib_count { 0 };
  107. };
  108. /**
  109. * @brief Class representing the trace log file being written.
  110. */
  111. class TraceLog
  112. {
  113. public:
  114. /**
  115. * @brief Create a new trace log.
  116. *
  117. * The trace log is global; there can be only one at a time.
  118. *
  119. * @param file_name The name of the file to write.
  120. */
  121. TraceLog(const char* file_name);
  122. /**
  123. * @brief Detroy the trace log.
  124. *
  125. * Trace logs MUST be cleanly destroyed to ensure the file gets written.
  126. */
  127. ~TraceLog();
  128. /**
  129. * @brief Get the current child node.
  130. *
  131. * @return The current leaf node.
  132. */
  133. TraceNode* get_current_leaf();
  134. /**
  135. * @brief Get the stack depth of the current child node.
  136. *
  137. * @return The current leaf node stack depth.
  138. */
  139. size_t get_depth();
  140. /**
  141. * @brief The file stream to write to.
  142. */
  143. std::ofstream m_file;
  144. /**
  145. * @brief The stack of nodes (newest at the back).
  146. */
  147. std::vector<TraceNode*> m_stack;
  148. private:
  149. /**
  150. * @brief The root node in the JSON file.
  151. */
  152. TraceNode* m_root;
  153. };
  154. /**
  155. * @brief Utility macro to create a trace node on the stack.
  156. *
  157. * @param name The variable name to use.
  158. * @param ... The name template and format parameters.
  159. */
  160. #define TRACE_NODE(name, ...) TraceNode name(__VA_ARGS__);
  161. /**
  162. * @brief Add a string annotation to the current node.
  163. *
  164. * @param key The name of the attribute.
  165. * @param format The format template for the attribute value.
  166. * @param ... The format parameters.
  167. */
  168. void trace_add_data(const char* key, const char* format, ...);
  169. /**
  170. * @brief Add a float annotation to the current node.
  171. *
  172. * @param key The name of the attribute.
  173. * @param value The value of the attribute.
  174. */
  175. void trace_add_data(const char* key, float value);
  176. /**
  177. * @brief Add an integer annotation to the current node.
  178. *
  179. * @param key The name of the attribute.
  180. * @param value The value of the attribute.
  181. */
  182. void trace_add_data(const char* key, int value);
  183. /**
  184. * @brief Add an unsigned integer annotation to the current node.
  185. *
  186. * @param key The name of the attribute.
  187. * @param value The value of the attribute.
  188. */
  189. void trace_add_data(const char* key, unsigned int value);
  190. #else
  191. #define TRACE_NODE(name, ...)
  192. #define trace_add_data(...)
  193. #endif
  194. #endif