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