xref: /aosp_15_r20/external/angle/src/common/debug.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // debug.cpp: Debugging utilities.
8 
9 #include "common/debug.h"
10 
11 #include <stdarg.h>
12 
13 #include <array>
14 #include <cstdio>
15 #include <cstring>
16 #include <fstream>
17 #include <ostream>
18 #include <vector>
19 
20 #if defined(ANGLE_PLATFORM_ANDROID)
21 #    include <android/log.h>
22 #endif
23 
24 #if defined(ANGLE_PLATFORM_APPLE)
25 #    include <os/log.h>
26 #endif
27 
28 #if defined(ANGLE_PLATFORM_WINDOWS)
29 #    include <windows.h>
30 #endif
31 
32 #include "anglebase/no_destructor.h"
33 #include "common/Optional.h"
34 #include "common/SimpleMutex.h"
35 #include "common/angleutils.h"
36 #include "common/entry_points_enum_autogen.h"
37 #include "common/system_utils.h"
38 
39 namespace gl
40 {
41 
42 namespace
43 {
44 
45 DebugAnnotator *g_debugAnnotator = nullptr;
46 
47 angle::SimpleMutex *g_debugMutex = nullptr;
48 
49 constexpr std::array<const char *, LOG_NUM_SEVERITIES> g_logSeverityNames = {
50     {"EVENT", "INFO", "WARN", "ERR", "FATAL"}};
51 
LogSeverityName(int severity)52 constexpr const char *LogSeverityName(int severity)
53 {
54     return (severity >= 0 && severity < LOG_NUM_SEVERITIES) ? g_logSeverityNames[severity]
55                                                             : "UNKNOWN";
56 }
57 
ShouldCreateLogMessage(LogSeverity severity)58 bool ShouldCreateLogMessage(LogSeverity severity)
59 {
60 #if defined(ANGLE_TRACE_ENABLED)
61     return true;
62 #elif defined(ANGLE_ALWAYS_LOG_INFO)
63     return severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN ||
64            severity == LOG_INFO;
65 #elif defined(ANGLE_ENABLE_ASSERTS)
66     return severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN;
67 #else
68     return severity == LOG_FATAL || severity == LOG_ERR;
69 #endif
70 }
71 
72 }  // namespace
73 
74 namespace priv
75 {
76 
ShouldCreatePlatformLogMessage(LogSeverity severity)77 bool ShouldCreatePlatformLogMessage(LogSeverity severity)
78 {
79 #if defined(ANGLE_TRACE_ENABLED)
80     return true;
81 #else
82     return severity != LOG_EVENT;
83 #endif
84 }
85 
86 // This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to an object of the correct
87 // type on the LHS of the unused part of the ternary operator.
88 std::ostream *gSwallowStream;
89 }  // namespace priv
90 
DebugAnnotationsActive(const gl::Context * context)91 bool DebugAnnotationsActive(const gl::Context *context)
92 {
93 #if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) || defined(ANGLE_ENABLE_DEBUG_TRACE)
94     return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus(context);
95 #else
96     return false;
97 #endif
98 }
99 
ShouldBeginScopedEvent(const gl::Context * context)100 bool ShouldBeginScopedEvent(const gl::Context *context)
101 {
102 #if defined(ANGLE_ENABLE_ANNOTATOR_RUN_TIME_CHECKS)
103     return DebugAnnotationsActive(context);
104 #else
105     return true;
106 #endif  // defined(ANGLE_ENABLE_ANNOTATOR_RUN_TIME_CHECKS)
107 }
108 
DebugAnnotationsInitialized()109 bool DebugAnnotationsInitialized()
110 {
111     return g_debugAnnotator != nullptr;
112 }
113 
InitializeDebugAnnotations(DebugAnnotator * debugAnnotator)114 void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator)
115 {
116     UninitializeDebugAnnotations();
117     g_debugAnnotator = debugAnnotator;
118 }
119 
UninitializeDebugAnnotations()120 void UninitializeDebugAnnotations()
121 {
122     // Pointer is not managed.
123     g_debugAnnotator = nullptr;
124 }
125 
InitializeDebugMutexIfNeeded()126 void InitializeDebugMutexIfNeeded()
127 {
128     if (g_debugMutex == nullptr)
129     {
130         g_debugMutex = new angle::SimpleMutex();
131     }
132 }
133 
GetDebugMutex()134 angle::SimpleMutex &GetDebugMutex()
135 {
136     ASSERT(g_debugMutex);
137     return *g_debugMutex;
138 }
139 
ScopedPerfEventHelper(gl::Context * context,angle::EntryPoint entryPoint)140 ScopedPerfEventHelper::ScopedPerfEventHelper(gl::Context *context, angle::EntryPoint entryPoint)
141     : mContext(context), mEntryPoint(entryPoint), mFunctionName(nullptr), mCalledBeginEvent(false)
142 {}
143 
~ScopedPerfEventHelper()144 ScopedPerfEventHelper::~ScopedPerfEventHelper()
145 {
146     // EGL_Initialize() and EGL_Terminate() can change g_debugAnnotator.  Must check the value of
147     // g_debugAnnotator and whether ScopedPerfEventHelper::begin() initiated a begine that must be
148     // ended now.
149     if (DebugAnnotationsInitialized() && mCalledBeginEvent)
150     {
151         g_debugAnnotator->endEvent(mContext, mFunctionName, mEntryPoint);
152     }
153 }
154 
begin(const char * format,...)155 void ScopedPerfEventHelper::begin(const char *format, ...)
156 {
157     mFunctionName = GetEntryPointName(mEntryPoint);
158 
159     va_list vararg;
160     va_start(vararg, format);
161 
162     std::vector<char> buffer;
163     size_t len = FormatStringIntoVector(format, vararg, buffer);
164     va_end(vararg);
165 
166     ANGLE_LOG(EVENT) << std::string(&buffer[0], len);
167     if (DebugAnnotationsInitialized())
168     {
169         mCalledBeginEvent = true;
170         g_debugAnnotator->beginEvent(mContext, mEntryPoint, mFunctionName, buffer.data());
171     }
172 }
173 
LogMessage(const char * file,const char * function,int line,LogSeverity severity)174 LogMessage::LogMessage(const char *file, const char *function, int line, LogSeverity severity)
175     : mFile(file), mFunction(function), mLine(line), mSeverity(severity)
176 {
177     // INFO() and EVENT() do not require additional function(line) info.
178     if (mSeverity > LOG_INFO)
179     {
180         const char *slash = std::max(strrchr(mFile, '/'), strrchr(mFile, '\\'));
181         mStream << (slash ? (slash + 1) : mFile) << ":" << mLine << " (" << mFunction << "): ";
182     }
183 }
184 
~LogMessage()185 LogMessage::~LogMessage()
186 {
187     {
188         std::unique_lock<angle::SimpleMutex> lock;
189         if (g_debugMutex != nullptr)
190         {
191             lock = std::unique_lock<angle::SimpleMutex>(*g_debugMutex);
192         }
193 
194         if (DebugAnnotationsInitialized() && (mSeverity > LOG_INFO))
195         {
196             g_debugAnnotator->logMessage(*this);
197         }
198         else
199         {
200             Trace(getSeverity(), getMessage().c_str());
201         }
202     }
203 
204     if (mSeverity == LOG_FATAL)
205     {
206         if (angle::IsDebuggerAttached())
207         {
208             angle::BreakDebugger();
209         }
210         else
211         {
212             ANGLE_CRASH();
213         }
214     }
215 }
216 
Trace(LogSeverity severity,const char * message)217 void Trace(LogSeverity severity, const char *message)
218 {
219     if (!ShouldCreateLogMessage(severity))
220     {
221         return;
222     }
223 
224     std::string str(message);
225 
226     if (DebugAnnotationsActive(/*context=*/nullptr))
227     {
228 
229         switch (severity)
230         {
231             case LOG_EVENT:
232                 // Debugging logging done in ScopedPerfEventHelper
233                 break;
234             default:
235                 g_debugAnnotator->setMarker(/*context=*/nullptr, message);
236                 break;
237         }
238     }
239 
240     if (severity == LOG_FATAL || severity == LOG_ERR || severity == LOG_WARN ||
241 #if defined(ANGLE_ENABLE_TRACE_ANDROID_LOGCAT) || defined(ANGLE_ENABLE_TRACE_EVENTS)
242         severity == LOG_EVENT ||
243 #endif
244         severity == LOG_INFO)
245     {
246 #if defined(ANGLE_PLATFORM_ANDROID)
247         android_LogPriority android_priority = ANDROID_LOG_ERROR;
248         switch (severity)
249         {
250             case LOG_INFO:
251             case LOG_EVENT:
252                 android_priority = ANDROID_LOG_INFO;
253                 break;
254             case LOG_WARN:
255                 android_priority = ANDROID_LOG_WARN;
256                 break;
257             case LOG_ERR:
258                 android_priority = ANDROID_LOG_ERROR;
259                 break;
260             case LOG_FATAL:
261                 android_priority = ANDROID_LOG_FATAL;
262                 break;
263             default:
264                 UNREACHABLE();
265         }
266         __android_log_print(android_priority, "ANGLE", "%s: %s\n", LogSeverityName(severity),
267                             str.c_str());
268         // Note: we also log to stdout/stderr below.
269 #endif
270 
271 #if defined(ANGLE_PLATFORM_APPLE)
272         if (__builtin_available(macOS 10.12, iOS 10.0, *))
273         {
274             os_log_type_t apple_log_type = OS_LOG_TYPE_DEFAULT;
275             switch (severity)
276             {
277                 case LOG_INFO:
278                 case LOG_EVENT:
279                     apple_log_type = OS_LOG_TYPE_INFO;
280                     break;
281                 case LOG_WARN:
282                     apple_log_type = OS_LOG_TYPE_DEFAULT;
283                     break;
284                 case LOG_ERR:
285                     apple_log_type = OS_LOG_TYPE_ERROR;
286                     break;
287                 case LOG_FATAL:
288                     // OS_LOG_TYPE_FAULT is too severe - grabs the entire process tree.
289                     apple_log_type = OS_LOG_TYPE_ERROR;
290                     break;
291                 default:
292                     UNREACHABLE();
293             }
294             os_log_with_type(OS_LOG_DEFAULT, apple_log_type, "ANGLE: %s: %s\n",
295                              LogSeverityName(severity), str.c_str());
296         }
297 #else
298         // Note: we use fprintf because <iostream> includes static initializers.
299         fprintf((severity >= LOG_WARN) ? stderr : stdout, "%s: %s\n", LogSeverityName(severity),
300                 str.c_str());
301 #endif
302     }
303 
304 #if defined(ANGLE_PLATFORM_WINDOWS) && \
305     (defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) || !defined(NDEBUG))
306 #    if !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
307     if (severity >= LOG_ERR)
308 #    endif  // !defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER)
309     {
310         OutputDebugStringA(str.c_str());
311         OutputDebugStringA("\n");
312     }
313 #endif
314 
315 #if defined(ANGLE_ENABLE_DEBUG_TRACE)
316 #    if defined(NDEBUG)
317     if (severity == LOG_EVENT || severity == LOG_WARN || severity == LOG_INFO)
318     {
319         return;
320     }
321 #    endif  // defined(NDEBUG)
322     static angle::base::NoDestructor<std::ofstream> file(TRACE_OUTPUT_FILE, std::ofstream::app);
323     if (file->good())
324     {
325         if (severity > LOG_EVENT)
326         {
327             *file << LogSeverityName(severity) << ": ";
328         }
329         *file << str << "\n";
330         file->flush();
331     }
332 #endif  // defined(ANGLE_ENABLE_DEBUG_TRACE)
333 }
334 
getSeverity() const335 LogSeverity LogMessage::getSeverity() const
336 {
337     return mSeverity;
338 }
339 
getMessage() const340 std::string LogMessage::getMessage() const
341 {
342     return mStream.str();
343 }
344 
345 #if defined(ANGLE_PLATFORM_WINDOWS)
FmtHR(HRESULT value)346 priv::FmtHexHelper<HRESULT, char> FmtHR(HRESULT value)
347 {
348     return priv::FmtHexHelper<HRESULT, char>("HRESULT: ", value);
349 }
350 
FmtErr(DWORD value)351 priv::FmtHexHelper<DWORD, char> FmtErr(DWORD value)
352 {
353     return priv::FmtHexHelper<DWORD, char>("error: ", value);
354 }
355 #endif  // defined(ANGLE_PLATFORM_WINDOWS)
356 
357 }  // namespace gl
358