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