• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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