This document is for a version of USD that is under development. See this page for the current release.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
debug.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_DEBUG_H
8#define PXR_BASE_TF_DEBUG_H
9
13
14#include "pxr/pxr.h"
15#include "pxr/base/tf/api.h"
16#include "pxr/base/tf/tf.h"
17#include "pxr/base/tf/enum.h"
18#include "pxr/base/tf/preprocessorUtilsLite.h"
22#include "pxr/base/arch/hints.h"
23
24#include <atomic>
25#include <cstdio>
26#include <string>
27#include <vector>
28
29PXR_NAMESPACE_OPEN_SCOPE
30
31class Tf_DebugSymbolRegistry;
32
35
122class TfDebug {
123 enum _NodeState { _NodeUninitialized, _NodeDisabled, _NodeEnabled };
124
125public:
133 template <class T>
134 static void Enable(T val) {
135 _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), true);
136 }
137
139 template <class T>
140 static void Disable(T val) {
141 _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), false);
142 }
143
150 template <class T>
151 static void EnableAll() {
152 const int n = _Traits<T>::NumCodes;
153 for (int i = 0; i != n; ++i) {
154 T code = static_cast<T>(i);
155 _SetNode(_GetNode(code), Tf_DebugGetEnumName(code), true);
156 }
157 }
158
160 template <class T>
161 static void DisableAll() {
162 const int n = _Traits<T>::NumCodes;
163 for (int i = 0; i != n; ++i) {
164 T code = static_cast<T>(i);
165 _SetNode(_GetNode(code), Tf_DebugGetEnumName(code), false);
166 }
167 }
168
175 template <class T>
176 static bool IsEnabled(T val) {
177 static_assert(_Traits<T>::IsDeclared,
178 "Must declare debug codes with TF_DEBUG_CODES()");
179 if (_Traits<T>::CompileTimeEnabled) {
180 _Node &node = _GetNode(val);
181 _NodeState curState = node.state.load();
182 if (ARCH_UNLIKELY(curState == _NodeUninitialized)) {
183 _InitializeNode(_GetNode(val), Tf_DebugGetEnumName(val));
184 curState = node.state.load();
185 }
186 return curState == _NodeEnabled;
187 }
188 return false;
189 }
190
193 template <class T>
194 static bool IsCompileTimeEnabled() {
195 static_assert(_Traits<T>::IsDeclared,
196 "Must declare debug codes with TF_DEBUG_CODES()");
197 return _Traits<T>::CompileTimeEnabled;
198 }
199
203 template <class T>
204 static size_t GetNumDebugCodes() {
205 static_assert(_Traits<T>::IsDeclared,
206 "Must declare debug codes with TF_DEBUG_CODES()");
207 return _Traits<T>::NumCodes;
208 }
209
210#if !defined(doxygen)
211 struct Helper {
212 static TF_API void Msg(const std::string& msg);
213 static TF_API void Msg(const char* msg, ...) ARCH_PRINTF_FUNCTION(1,2);
214 };
215#endif
216
217 template <bool B>
218 struct ScopeHelper {
219 ScopeHelper(bool enabled, const char* name) {
220 if ((active = enabled)) {
221 str = name;
222 TfDebug::_ScopedOutput(true, str);
223 }
224 else
225 str = NULL;
226 }
227
228 ~ScopeHelper() {
229 if (active)
230 TfDebug::_ScopedOutput(false, str);
231 }
232
233 bool active;
234 const char* str;
235 };
236
237 template <bool B>
238 struct TimedScopeHelper {
239 TimedScopeHelper(bool enabled, const char* fmt, ...)
241 ~TimedScopeHelper();
242
243 bool active;
244 std::string str;
245 TfStopwatch stopwatch;
246 };
247
254 TF_API
255 static std::vector<std::string> SetDebugSymbolsByName(
256 const std::string& pattern, bool value);
257
259 TF_API
260 static bool IsDebugSymbolNameEnabled(const std::string& name);
261
266 TF_API
267 static std::string GetDebugSymbolDescriptions();
268
270 TF_API
271 static std::vector<std::string> GetDebugSymbolNames();
272
278 TF_API
279 static std::string GetDebugSymbolDescription(const std::string& name);
280
287 TF_API
288 static void SetOutputFile(FILE *file);
289
290 struct _Node;
291
292 // Public, to be used in TF_DEBUG_ENVIRONMENT_SYMBOL() macro,
293 // but not meant to be used otherwise.
294 template <class T>
295 static void _RegisterDebugSymbol(
296 T enumVal, char const *name, char const *descrip) {
297 static_assert(_Traits<T>::IsDeclared,
298 "Must declare debug codes with TF_DEBUG_CODES()");
299 const int index = static_cast<int>(enumVal);
300 const int numCodes = _Traits<T>::NumCodes;
301 if (ARCH_UNLIKELY(index < 0 || index >= numCodes)) {
302 _ComplainAboutInvalidSymbol(name);
303 return;
304 }
305 _RegisterDebugSymbolImpl(&_GetNode(enumVal), name, descrip);
306 }
307
308 TF_API
309 static void _RegisterDebugSymbolImpl(_Node *addr, char const *enumName,
310 char const *descrip);
311
312 // Unfortunately, we need to make both _Traits and _Node, below
313 // public because of their use in macros.
314 // Please treat both as a private data structures!
315
316 template <class T>
317 struct _Traits {
318 static constexpr bool IsDeclared = false;
319 };
320
321 // Note: this structure gets initialized statically zero
322 // (_NodeUninitialized) statically.
323 struct _Node {
324 mutable std::atomic<_NodeState> state;
325 };
326
327private:
328
329 template <class T>
330 struct _Data {
331 static _Node nodes[_Traits<T>::NumCodes];
332 };
333
334 template <class T>
335 static _Node &_GetNode(T val) {
336 return _Data<T>::nodes[static_cast<int>(val)];
337 }
338
339 friend class Tf_DebugSymbolRegistry;
340
341 TF_API
342 static void _InitializeNode(_Node &node, char const *name);
343
344 TF_API
345 static void _ComplainAboutInvalidSymbol(char const *name);
346
347 TF_API
348 static void _SetNode(_Node &node, char const *name, bool state);
349
350 TF_API
351 static void _ScopedOutput(bool start, char const *str);
352};
353
354template <class T>
355TfDebug::_Node TfDebug::_Data<T>::nodes[];
356
357template <>
358struct TfDebug::TimedScopeHelper<false> {
359 TimedScopeHelper(bool, const char*, ...)
360 ARCH_PRINTF_FUNCTION(3, 4) {
361 }
362};
363
376#define TF_DEBUG_CODES(...) \
377 TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(true, __VA_ARGS__)
378
397#define TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(condition, ...) \
398 enum _TF_DEBUG_ENUM_NAME(__VA_ARGS__) { \
399 __VA_ARGS__ , \
400 TF_PP_CAT( _TF_DEBUG_ENUM_NAME(__VA_ARGS__), __PAST_END) \
401 }; \
402 template <> \
403 struct TfDebug::_Traits<_TF_DEBUG_ENUM_NAME(__VA_ARGS__)> { \
404 static constexpr bool IsDeclared = true; \
405 static constexpr int NumCodes = \
406 TF_PP_CAT(_TF_DEBUG_ENUM_NAME(__VA_ARGS__), __PAST_END); \
407 static constexpr bool CompileTimeEnabled = (condition); \
408 }; \
409 inline char const * \
410 Tf_DebugGetEnumName(_TF_DEBUG_ENUM_NAME(__VA_ARGS__) val) { \
411 constexpr char const *CStrings[] = { \
412 TF_PP_FOR_EACH(_TF_DEBUG_MAKE_STRING, __VA_ARGS__) \
413 }; \
414 return CStrings[static_cast<int>(val)]; \
415 };
416
417#define _TF_DEBUG_MAKE_STRING(x) #x,
418
419// In the _TF_DEBUG_ENUM_NAME macro below we pass 'dummy' to
420// _TF_DEBUG_FIRST_CODE as the second argument to ensure that we always
421// have more than one argument as expected by _TF_DEBUG_FIRST_CODE.
422#define _TF_DEBUG_ENUM_NAME(...) \
423 TF_PP_CAT(_TF_DEBUG_FIRST_CODE(__VA_ARGS__, dummy), __DebugCodes)
424
425#define _TF_DEBUG_FIRST_CODE(first, ...) first
426
449#define TF_DEBUG_MSG(enumVal, ...) \
450 if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; else TfDebug::Helper().Msg(__VA_ARGS__)
451
484#define TF_DEBUG(enumVal) \
485 if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; else TfDebug::Helper()
486
494#define TF_INFO(x) TF_DEBUG(x)
495
523#define TF_DEBUG_TIMED_SCOPE(enumVal, ...) \
524 TfDebug::TimedScopeHelper< \
525 TfDebug::_Traits< \
526 std::decay<decltype(enumVal)>::type>::CompileTimeEnabled> \
527 TF_PP_CAT(local__TfScopeDebugSwObject, __LINE__)( \
528 TfDebug::IsEnabled(enumVal), __VA_ARGS__)
529
548#define TF_DEBUG_ENVIRONMENT_SYMBOL(VAL, descrip) \
549 if (TfDebug::_Traits< \
550 std::decay<decltype(VAL)>::type>::CompileTimeEnabled) { \
551 TF_ADD_ENUM_NAME(VAL); \
552 TfDebug::_RegisterDebugSymbol(VAL, #VAL, descrip); \
553 }
554
556
557PXR_NAMESPACE_CLOSE_SCOPE
558
559#endif
Define function attributes.
#define ARCH_PRINTF_FUNCTION(_fmt, _firstArg)
Macro used to indicate a function takes a printf-like specification.
Definition: attributes.h:34
Enum-based debugging messages.
Definition: debug.h:122
static void Enable(T val)
Mark debugging as enabled for enum value val.
Definition: debug.h:134
static void Disable(T val)
Mark debugging as disabled for enum value val.
Definition: debug.h:140
static size_t GetNumDebugCodes()
Return the number of debugging symbols of this type.
Definition: debug.h:204
static bool IsEnabled(T val)
True if debugging is enabled for the enum value val.
Definition: debug.h:176
static bool IsCompileTimeEnabled()
True if debugging can be activated at run-time, whether or not it is currently enabled.
Definition: debug.h:194
static void EnableAll()
Mark debugging as enabled for all enum values of type T.
Definition: debug.h:151
static void DisableAll()
Mark debugging as disabled for all enum values of type T.
Definition: debug.h:161
Low-cost, high-resolution timer datatype.
Definition: stopwatch.h:39
Compiler hints.
STL namespace.
A file containing basic constants and definitions.