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