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
TraceLog(const char * file_name)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. */
get_current_leaf()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. */
get_depth()60 size_t TraceLog::get_depth()
61 {
62 return m_stack.size();
63 }
64
65 /* See header for documentation. */
~TraceLog()66 TraceLog::~TraceLog()
67 {
68 assert(g_TraceLog == this);
69 delete m_root;
70 g_TraceLog = nullptr;
71 }
72
73 /* See header for documentation. */
TraceNode(const char * format,...)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. */
add_attrib(std::string type,std::string key,std::string value)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. */
~TraceNode()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. */
trace_add_data(const char * key,const char * format,...)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. */
trace_add_data(const char * key,float value)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. */
trace_add_data(const char * key,int value)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. */
trace_add_data(const char * key,unsigned int value)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