1// SPDX-License-Identifier: Apache-2.0 2// ---------------------------------------------------------------------------- 3// Copyright 2021-2023 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 Functions for the library entrypoint. 20 */ 21 22#if defined(ASTCENC_DIAGNOSTICS) 23 24#include <cassert> 25#include <cstdarg> 26#include <cstdio> 27#include <cmath> 28#include <limits> 29#include <string> 30 31#include "astcenc_diagnostic_trace.h" 32 33/** @brief The global trace logger. */ 34static TraceLog* g_TraceLog = nullptr; 35 36/** @brief The JSON indentation level. */ 37static const size_t g_trace_indent = 2; 38 39TraceLog::TraceLog( 40 const char* file_name): 41 m_file(file_name, std::ofstream::out | std::ofstream::binary) 42{ 43 assert(!g_TraceLog); 44 g_TraceLog = this; 45 m_root = new TraceNode("root"); 46} 47 48/* See header for documentation. */ 49TraceNode* TraceLog::get_current_leaf() 50{ 51 if (m_stack.size()) 52 { 53 return m_stack.back(); 54 } 55 56 return nullptr; 57} 58 59/* See header for documentation. */ 60size_t TraceLog::get_depth() 61{ 62 return m_stack.size(); 63} 64 65/* See header for documentation. */ 66TraceLog::~TraceLog() 67{ 68 assert(g_TraceLog == this); 69 delete m_root; 70 g_TraceLog = nullptr; 71} 72 73/* See header for documentation. */ 74TraceNode::TraceNode( 75 const char* format, 76 ... 77) { 78 // Format the name string 79 constexpr size_t bufsz = 256; 80 char buffer[bufsz]; 81 82 va_list args; 83 va_start (args, format); 84 vsnprintf (buffer, bufsz, format, args); 85 va_end (args); 86 87 // Guarantee there is a nul terminator 88 buffer[bufsz - 1] = 0; 89 90 // Generate the node 91 TraceNode* parent = g_TraceLog->get_current_leaf(); 92 size_t depth = g_TraceLog->get_depth(); 93 g_TraceLog->m_stack.push_back(this); 94 95 bool comma = parent && parent->m_attrib_count; 96 auto& out = g_TraceLog->m_file; 97 98 if (parent) 99 { 100 parent->m_attrib_count++; 101 } 102 103 if (comma) 104 { 105 out << ','; 106 } 107 108 if (depth) 109 { 110 out << '\n'; 111 } 112 113 size_t out_indent = (depth * 2) * g_trace_indent; 114 size_t in_indent = (depth * 2 + 1) * g_trace_indent; 115 116 std::string out_indents(""); 117 if (out_indent) 118 { 119 out_indents = std::string(out_indent, ' '); 120 } 121 122 std::string in_indents(in_indent, ' '); 123 124 out << out_indents << "[ \"node\", \"" << buffer << "\",\n"; 125 out << in_indents << "["; 126} 127 128/* See header for documentation. */ 129void TraceNode::add_attrib( 130 std::string type, 131 std::string key, 132 std::string value 133) { 134 (void)type; 135 136 size_t depth = g_TraceLog->get_depth(); 137 size_t indent = (depth * 2) * g_trace_indent; 138 auto& out = g_TraceLog->m_file; 139 bool comma = m_attrib_count; 140 m_attrib_count++; 141 142 if (comma) 143 { 144 out << ','; 145 } 146 147 out << '\n'; 148 out << std::string(indent, ' ') << "[ " 149 << "\"" << key << "\", " 150 << value << " ]"; 151} 152 153/* See header for documentation. */ 154TraceNode::~TraceNode() 155{ 156 g_TraceLog->m_stack.pop_back(); 157 158 auto& out = g_TraceLog->m_file; 159 size_t depth = g_TraceLog->get_depth(); 160 size_t out_indent = (depth * 2) * g_trace_indent; 161 size_t in_indent = (depth * 2 + 1) * g_trace_indent; 162 163 std::string out_indents(""); 164 if (out_indent) 165 { 166 out_indents = std::string(out_indent, ' '); 167 } 168 169 std::string in_indents(in_indent, ' '); 170 171 if (m_attrib_count) 172 { 173 out << "\n" << in_indents; 174 } 175 out << "]\n"; 176 177 out << out_indents << "]"; 178} 179 180/* See header for documentation. */ 181void trace_add_data( 182 const char* key, 183 const char* format, 184 ... 185) { 186 constexpr size_t bufsz = 256; 187 char buffer[bufsz]; 188 189 va_list args; 190 va_start (args, format); 191 vsnprintf (buffer, bufsz, format, args); 192 va_end (args); 193 194 // Guarantee there is a nul terminator 195 buffer[bufsz - 1] = 0; 196 197 std::string value = "\"" + std::string(buffer) + "\""; 198 199 TraceNode* node = g_TraceLog->get_current_leaf(); 200 node->add_attrib("str", key, value); 201} 202 203/* See header for documentation. */ 204void trace_add_data( 205 const char* key, 206 float value 207) { 208 // Turn infinities into parseable values 209 if (std::isinf(value)) 210 { 211 if (value > 0.0f) 212 { 213 value = std::numeric_limits<float>::max(); 214 } 215 else 216 { 217 value = -std::numeric_limits<float>::max(); 218 } 219 } 220 221 char buffer[256]; 222 sprintf(buffer, "%.20g", (double)value); 223 TraceNode* node = g_TraceLog->get_current_leaf(); 224 node->add_attrib("float", key, buffer); 225} 226 227/* See header for documentation. */ 228void trace_add_data( 229 const char* key, 230 int value 231) { 232 TraceNode* node = g_TraceLog->get_current_leaf(); 233 node->add_attrib("int", key, std::to_string(value)); 234} 235 236/* See header for documentation. */ 237void trace_add_data( 238 const char* key, 239 unsigned int value 240) { 241 TraceNode* node = g_TraceLog->get_current_leaf(); 242 node->add_attrib("int", key, std::to_string(value)); 243} 244 245#endif 246