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