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. */ |
34 | static TraceLog* g_TraceLog = nullptr; |
35 | |
36 | /** @brief The JSON indentation level. */ |
37 | static const size_t g_trace_indent = 2; |
38 | |
39 | TraceLog::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. */ |
49 | TraceNode* 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. */ |
60 | size_t TraceLog::get_depth() |
61 | { |
62 | return m_stack.size(); |
63 | } |
64 | |
65 | /* See header for documentation. */ |
66 | TraceLog::~TraceLog() |
67 | { |
68 | assert(g_TraceLog == this); |
69 | delete m_root; |
70 | g_TraceLog = nullptr; |
71 | } |
72 | |
73 | /* See header for documentation. */ |
74 | TraceNode::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. */ |
129 | void 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. */ |
154 | TraceNode::~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. */ |
181 | void 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. */ |
204 | void 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. */ |
228 | void 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. */ |
237 | void 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 | |