HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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 
10 /// \file tf/debug.h
11 /// \ingroup group_tf_DebuggingOutput
12 /// Conditional debugging output class and macros.
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"
20 #include "pxr/base/tf/stopwatch.h"
22 #include "pxr/base/arch/hints.h"
23 
24 #include <atomic>
25 #include <cstdio>
26 #include <string>
27 #include <vector>
28 
30 
31 class Tf_DebugSymbolRegistry;
32 
33 /// \addtogroup group_tf_DebuggingOutput
34 ///@{
35 
36 /// \class TfDebug
37 ///
38 /// Enum-based debugging messages.
39 ///
40 /// The \c TfDebug class encapsulates a simple enum-based conditional
41 /// debugging message system. It is meant as a tool for developers, and
42 /// \e NOT as a means of issuing diagnostic messages to end-users. (This is
43 /// not strictly true. The TfDebug class is extremely useful and has many
44 /// properties that make its use attractive for issuing messages to end-users.
45 /// However, for this purpose, please use the \c TF_INFO macro which more
46 /// clearly indicates its intent.)
47 ///
48 /// The features of \c TfDebug are:
49 /// \li Debugging messages/calls for an entire enum group can be
50 /// compiled out-of-existence.
51 /// \li The cost of checking if a specific message should be printed
52 /// at runtime (assuming the enum group of the message has not been
53 /// compile-time disabled) is a single inline array lookup,
54 /// with a compile-time index into a global array.
55 ///
56 /// The use of the facility is simple:
57 /// \code
58 /// // header file
59 /// #include "pxr/base/tf/debug.h"
60 /// TF_DEBUG_CODES(MY_E1, MY_E2, MY_E3);
61 ///
62 /// // source file
63 /// TF_DEBUG(MY_E2).Msg("something about e2\n");
64 ///
65 /// TF_DEBUG(MY_E3).Msg("val = %d\n", value);
66 /// \endcode
67 ///
68 /// The code in the header file declares the debug symbols to use. Under
69 /// the hood, this creates an enum with the values given in the argument to
70 /// TF_DEBUG_CODES, along with a first and last sentinel values and passes
71 /// that to TF_DEBUG_RANGE.
72 ///
73 /// If you need to obtain the enum type name, use decltype(SOME_ENUM_VALUE).
74 ///
75 /// In the source file, the indicated debugging messages are printed
76 /// only if the debugging symbols are enabled. Effectively, the construct
77 /// \code
78 /// TF_DEBUG(MY_E1).Msg(msgExpr)
79 /// \endcode
80 /// is translated to
81 /// \code
82 /// if (symbol-MY_E1-is-enabled)
83 /// output(msgExpr)
84 /// \endcode
85 ///
86 /// The implications are that \c msgExpr is only evaluated if symbol \c MY_E1
87 /// symbol is enabled.
88 ///
89 /// To totally disable TF_DEBUG output for a set of codes at compile time,
90 /// declare the codes using
91 /// TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(condition, ...) where
92 /// ... is all the debug codes. If 'condition' is false at compile time then
93 /// all TF_DEBUG().Msg()s for these codes are elminated at compile time, so they
94 /// have zero cost.
95 ///
96 /// Most commonly debug symbols are inactive by default, but can be turned
97 /// on either by an environment variable \c TF_DEBUG, or interactively once
98 /// a program has started.
99 ///
100 /// \code
101 /// TfDebug::DisableAll<MyDebugCodes>(); // disable everything
102 ///
103 /// TfDebug::Enable(MY_E1); // enable just MY_E1
104 /// \endcode
105 ///
106 /// Description strings may be associated with debug codes as follows:
107 /// \code
108 /// // source file xyz/debugCodes.cpp
109 ///
110 /// #include "proj/my/debugCodes.h"
111 /// #include "pxr/base/tf/debug.h"
112 /// #include "pxr/base/tf/registryManager.h"
113 ///
114 /// TF_REGISTRY_FUNCTION(TfDebug) {
115 /// TF_DEBUG_ENVIRONMENT_SYMBOL(MY_E1, "loading of blah-blah files");
116 /// TF_DEBUG_ENVIRONMENT_SYMBOL(MY_E2, "parsing of mdl code");
117 /// // etc.
118 /// }
119 /// \endcode
120 ///
121 ///
122 class TfDebug {
123  enum _NodeState { _NodeUninitialized, _NodeDisabled, _NodeEnabled };
124 
125 public:
126  /// Mark debugging as enabled for enum value \c val.
127  ///
128  /// The default state for all debugging symbols is disabled. Note that the
129  /// template parameter is deduced from \c val:
130  /// \code
131  /// TfDebug::Enable(MY_E3);
132  /// \endcode
133  template <class T>
134  static void Enable(T val) {
135  _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), true);
136  }
137 
138  /// Mark debugging as disabled for enum value \c val.
139  template <class T>
140  static void Disable(T val) {
141  _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), false);
142  }
143 
144  /// Mark debugging as enabled for all enum values of type \c T.
145  ///
146  /// Note that the template parameter must be explicitly supplied:
147  /// \code
148  /// TfDebug::EnableAll<MyDebugCodes>()
149  /// \endcode
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 
159  /// Mark debugging as disabled for all enum values of type \c T.
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 
169  /// True if debugging is enabled for the enum value \c val.
170  ///
171  /// Note that not only must the specific enum value \c val be marked as
172  /// enabled, but the enum type \c T must be globally enabled; this is
173  /// controlled by the first argument to the
174  /// \c TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES() macro.
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()");
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 
191  /// True if debugging can be activated at run-time, whether or not it is
192  /// currently enabled.
193  template <class T>
194  static bool IsCompileTimeEnabled() {
195  static_assert(_Traits<T>::IsDeclared,
196  "Must declare debug codes with TF_DEBUG_CODES()");
198  }
199 
200  /// Return the number of debugging symbols of this type.
201  ///
202  /// Returns the number of different enums in the range.
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  _Helper() = default;
213  template <class Enum>
214  explicit _Helper(Enum val) : _enumName(Tf_DebugGetEnumName(val)) {}
215  TF_API void Msg(const std::string& msg) const;
216  TF_API void Msg(const char* msg, ...) const ARCH_PRINTF_FUNCTION(2,3);
217  private:
218  char const * const _enumName = "<< no debug code >>";
219  };
220 
221  struct Helper {
222  template <class A1, class ...Args>
223  static void Msg(char const *fmt, A1 &&a1, Args && ...args) {
224  return _Helper().Msg(
225  fmt, std::forward<A1>(a1), std::forward<Args>(args)...);
226  }
227  static void Msg(const std::string &msg) {
228  return _Helper().Msg(msg);
229  }
230  };
231 #endif
232 
233  template <bool B>
234  struct ScopeHelper {
235  ScopeHelper(bool enabled, const char* name) {
236  if ((active = enabled)) {
237  str = name;
238  TfDebug::_ScopedOutput(true, str);
239  }
240  else
241  str = NULL;
242  }
243 
245  if (active)
246  TfDebug::_ScopedOutput(false, str);
247  }
248 
249  bool active;
250  const char* str;
251  };
252 
253  template <bool B>
255  TimedScopeHelper(bool enabled, const char* fmt, ...)
256  ARCH_PRINTF_FUNCTION(3, 4);
257  ~TimedScopeHelper();
258 
259  bool active;
260  std::string str;
262  };
263 
264  /// Set registered debug symbols matching \p pattern to \p value.
265  ///
266  /// All registered debug symbols matching \p pattern are set to \p value.
267  /// The only matching is an exact match with \p pattern, or if \p pattern
268  /// ends with an '*' as is otherwise a prefix of a debug symbols. The
269  /// names of all debug symbols set by this call are returned as a vector.
270  TF_API
271  static std::vector<std::string> SetDebugSymbolsByName(
272  const std::string& pattern, bool value);
273 
274  /// True if the specified debug symbol is set.
275  TF_API
276  static bool IsDebugSymbolNameEnabled(const std::string& name);
277 
278  /// Get a description of all debug symbols and their purpose.
279  ///
280  /// A single string describing all registered debug symbols along with
281  /// short descriptions is returned.
282  TF_API
283  static std::string GetDebugSymbolDescriptions();
284 
285  /// Get a listing of all debug symbols.
286  TF_API
287  static std::vector<std::string> GetDebugSymbolNames();
288 
289  /// Get a description for the specified debug symbol.
290  ///
291  /// A short description of the debug symbol is returned. This is the same
292  /// description string that is embedded in the return value of
293  /// GetDebugSymbolDescriptions.
294  TF_API
295  static std::string GetDebugSymbolDescription(const std::string& name);
296 
297  /// Direct debug output to \a either stdout or stderr.
298  ///
299  /// Note that \a file MUST be either stdout or stderr. If not, issue an
300  /// error and do nothing. Debug output is issued to stdout by default.
301  /// If the environment variable TF_DEBUG_OUTPUT_FILE is set to 'stderr',
302  /// then output is issued to stderr by default.
303  TF_API
304  static void SetOutputFile(FILE *file);
305 
306  struct _Node;
307 
308  // Public, to be used in TF_DEBUG_ENVIRONMENT_SYMBOL() macro,
309  // but not meant to be used otherwise.
310  template <class T>
311  static void _RegisterDebugSymbol(
312  T enumVal, char const *name, char const *descrip) {
313  static_assert(_Traits<T>::IsDeclared,
314  "Must declare debug codes with TF_DEBUG_CODES()");
315  const int index = static_cast<int>(enumVal);
316  const int numCodes = _Traits<T>::NumCodes;
317  if (ARCH_UNLIKELY(index < 0 || index >= numCodes)) {
318  _ComplainAboutInvalidSymbol(name);
319  return;
320  }
321  _RegisterDebugSymbolImpl(&_GetNode(enumVal), name, descrip);
322  }
323 
324  TF_API
325  static void _RegisterDebugSymbolImpl(_Node *addr, char const *enumName,
326  char const *descrip);
327 
328  // Unfortunately, we need to make both _Traits and _Node, below
329  // public because of their use in macros.
330  // Please treat both as a private data structures!
331 
332  template <class T>
333  struct _Traits {
334  static constexpr bool IsDeclared = false;
335  };
336 
337  // Note: this structure gets initialized statically zero
338  // (_NodeUninitialized) statically.
339  struct _Node {
340  mutable std::atomic<_NodeState> state;
341  };
342 
343 private:
344 
345  template <class T>
346  struct _Data {
348  };
349 
350  template <class T>
351  static _Node &_GetNode(T val) {
352  return _Data<T>::nodes[static_cast<int>(val)];
353  }
354 
356 
357  TF_API
358  static void _InitializeNode(_Node &node, char const *name);
359 
360  TF_API
361  static void _ComplainAboutInvalidSymbol(char const *name);
362 
363  TF_API
364  static void _SetNode(_Node &node, char const *name, bool state);
365 
366  TF_API
367  static void _ScopedOutput(bool start, char const *str);
368 };
369 
370 template <class T>
371 TfDebug::_Node TfDebug::_Data<T>::nodes[];
372 
373 template <>
375  TimedScopeHelper(bool, const char*, ...)
376  ARCH_PRINTF_FUNCTION(3, 4) {
377  }
378 };
379 
380 /// Define debugging symbols
381 ///
382 /// This is a simple macro that takes care of declaring debug codes. Use it as
383 /// follows:
384 /// \code
385 /// TF_DEBUG_CODES(
386 /// MY_E1,
387 /// MY_E2
388 /// );
389 /// \endcode
390 ///
391 /// \hideinitializer
392 #define TF_DEBUG_CODES(...) \
393  TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(true, __VA_ARGS__)
394 
395 /// Define debugging symbols
396 ///
397 /// This is a simple macro that takes care of declaring debug codes, subject to
398 /// a compile-time condition that enables or disables them completely. Use it as
399 /// follows:
400 /// \code
401 /// TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(
402 /// <Enabled State: a compile-time value convertible to bool>
403 /// MY_E1,
404 /// MY_E2
405 /// );
406 /// \endcode
407 ///
408 /// If the Enabled State is true, this is equivalent to the TF_DEBUG_CODES()
409 /// macro. If it is false, then these debug codes are disabled at compile time
410 /// and generated code pays no cost for them.
411 ///
412 /// \hideinitializer
413 #define TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(condition, ...) \
414  enum _TF_DEBUG_ENUM_NAME(__VA_ARGS__) { \
415  __VA_ARGS__ , \
416  TF_PP_CAT( _TF_DEBUG_ENUM_NAME(__VA_ARGS__), __PAST_END) \
417  }; \
418  template <> \
419  struct TfDebug::_Traits<_TF_DEBUG_ENUM_NAME(__VA_ARGS__)> { \
420  static constexpr bool IsDeclared = true; \
421  static constexpr int NumCodes = \
422  TF_PP_CAT(_TF_DEBUG_ENUM_NAME(__VA_ARGS__), __PAST_END); \
423  static constexpr bool CompileTimeEnabled = (condition); \
424  }; \
425  inline char const * \
426  Tf_DebugGetEnumName(_TF_DEBUG_ENUM_NAME(__VA_ARGS__) val) { \
427  constexpr char const *CStrings[] = { \
428  TF_PP_FOR_EACH(_TF_DEBUG_MAKE_STRING, __VA_ARGS__) \
429  }; \
430  return CStrings[static_cast<int>(val)]; \
431  };
432 
433 #define _TF_DEBUG_MAKE_STRING(x) #x,
434 
435 // In the _TF_DEBUG_ENUM_NAME macro below we pass 'dummy' to
436 // _TF_DEBUG_FIRST_CODE as the second argument to ensure that we always
437 // have more than one argument as expected by _TF_DEBUG_FIRST_CODE.
438 #define _TF_DEBUG_ENUM_NAME(...) \
439  TF_PP_CAT(_TF_DEBUG_FIRST_CODE(__VA_ARGS__, dummy), __DebugCodes)
440 
441 #define _TF_DEBUG_FIRST_CODE(first, ...) first
442 
443 /// Evaluate and print debugging message \c msg if \c enumVal is enabled for
444 /// debugging.
445 ///
446 /// This macro is a newer, more convenient form of the \c TF_DEBUG() macro.
447 /// Writing
448 /// \code
449 /// TF_DEBUG_MSG(enumVal, msg, ...);
450 /// \endcode
451 /// is equivalent to
452 /// \code
453 /// TF_DEBUG(enumVal).Msg(msg, ...);
454 /// \endcode
455 ///
456 /// The TF_DEBUG_MSG() macro allows either an std::string argument or
457 /// a printf-like format string followed by a variable number of arguments:
458 /// \code
459 /// TF_DEBUG_MSG(enumVal, "opening file %s\n", file.c_str());
460 ///
461 /// TF_DEBUG_MSG(enumVal, "opening file " + file);
462 /// \endcode
463 ///
464 /// \hideinitializer
465 #define TF_DEBUG_MSG(enumVal, ...) \
466  if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; \
467  else TfDebug::_Helper(enumVal).Msg(__VA_ARGS__)
468 
469 /// Evaluate and print debugging message \c msg if \c enumVal is enabled for
470 /// debugging.
471 ///
472 /// The \c TF_DEBUG() macro is used as follows:
473 /// \code
474 /// TF_DEBUG(enumVal).Msg("opening file %s, count = %d\n",
475 /// file.c_str(), count);
476 /// \endcode
477 ///
478 /// If \c enumVal is of enumerated type \c enumType, and \c enumType
479 /// has been enabled for debugging (see \c TF_DEBUG_CODES()), and
480 /// the specific value \c enumVal has been enabled for debugging by a call
481 /// to \c TfDebug::Enable(), then the arguments in the \c Msg() call are
482 /// evaluated and printed. The argument to \c Msg() may either be a
483 /// \c const \c char* and a variable number of arguments, using standard
484 /// printf-formatting rules, or a \c std::string variable:
485 /// \code
486 /// TF_DEBUG(enumVal).Msg("opening file " + file + "\n");
487 /// \endcode
488 ///
489 /// Note that the arguments to \c Msg() are unevaluated when the value
490 /// \c enumVal is not enabled for debugging, so \c Msg() must be free
491 /// of side-effects; however, when \c enumVal is not enabled, there is
492 /// no expense incurred in computing the arguments to \c Msg(). Note
493 /// that if the entire enum type corresponding to \c enumVal is
494 /// disabled (a compile-time determination) then the code for the \e
495 /// entire \c TF_DEBUG().Msg() statement will typically not even be
496 /// generated!
497 ///
498 /// \sa TF_DEBUG_MSG()
499 ///
500 /// \hideinitializer
501 #define TF_DEBUG(enumVal) \
502  if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; \
503  else TfDebug::_Helper(enumVal)
504 
505 /// Evaluate and print diagnostic messages intended for end-users.
506 ///
507 /// The TF_INFO(x) macro is cosmetic; it actually just calls the TF_DEBUG
508 /// macro (see above). This macro should be used if its output is intended to
509 /// be seen by end-users.
510 ///
511 /// \hideinitializer
512 #define TF_INFO(x) TF_DEBUG(x)
513 
514 /// Print description and time spent in scope upon beginning and exiting it if
515 /// \p enumVal is enabled for debugging.
516 ///
517 /// The \c TF_DEBUG_TIMED_SCOPE() macro is used as follows:
518 /// \code
519 /// void Attribute::Compute()
520 /// {
521 /// TF_DEBUG_TIMED_SCOPE(ATTR_COMPUTE, "Computing %s", name.c_str());
522 /// ...
523 /// }
524 /// \endcode
525 ///
526 /// When the \c TF_DEBUG_TIMED_SCOPE macro is invoked, a timer is started and
527 /// the supplied description is printed. When the enclosing scope is exited
528 /// (in the example, when Attribute::Compute() finishes) the timer is stopped
529 /// and the scope description and measured time are printed. This allows for
530 /// very fine-grained timing of operations.
531 ///
532 /// Note that if the entire enum type corresponding to \p enumVal is disabled
533 /// (a compile-time determination) then the presence of a
534 /// \c TF_DEBUG_TIMED_SCOPE() macro should not produce any extra generated
535 /// code (in an optimized build). If the enum type is enabled, but the
536 /// particular value \p enumVal is disabled, the cost of the macro should be
537 /// quite minimal; still, it would be best not to embed the macro in functions
538 /// that are called in very tight loops, in final released code.
539 ///
540 /// \hideinitializer
541 #define TF_DEBUG_TIMED_SCOPE(enumVal, ...) \
542  TfDebug::TimedScopeHelper< \
543  TfDebug::_Traits< \
544  std::decay<decltype(enumVal)>::type>::CompileTimeEnabled> \
545  TF_PP_CAT(local__TfScopeDebugSwObject, __LINE__)( \
546  TfDebug::IsEnabled(enumVal), __VA_ARGS__)
547 
548 /// Register description strings with enum symbols for debugging.
549 ///
550 /// This call should be used in source files, not header files, and should
551 /// This macro should usually appear within a
552 /// \c TF_REGISTRY_FUNCTION(TfDebug,...) call. The first argument should be
553 /// the literal name of the enum symbol, while the second argument should be a
554 /// (short) description of what debugging will be enabled if the symbol is
555 /// activated. The enum being registered must be one which is contained in
556 /// some TF_DEBUG_CODES() call. For example:
557 /// \code
558 /// TF_REGISTRY_FUNCTION(TfDebug) {
559 /// TF_DEBUG_ENVIRONMENT_SYMBOL(MY_E1, "loading of blah-blah files");
560 /// TF_DEBUG_ENVIRONMENT_SYMBOL(MY_E2, "parsing of mdl code");
561 /// // etc.
562 /// }
563 /// \endcode
564 ///
565 /// \hideinitializer
566 #define TF_DEBUG_ENVIRONMENT_SYMBOL(VAL, descrip) \
567  if (TfDebug::_Traits< \
568  std::decay<decltype(VAL)>::type>::CompileTimeEnabled) { \
569  TF_ADD_ENUM_NAME(VAL); \
570  TfDebug::_RegisterDebugSymbol(VAL, #VAL, descrip); \
571  }
572 
573 ///@}
574 
576 
577 #endif
static TF_API void SetOutputFile(FILE *file)
static size_t GetNumDebugCodes()
Definition: debug.h:204
static TF_API std::vector< std::string > SetDebugSymbolsByName(const std::string &pattern, bool value)
static void Msg(char const *fmt, A1 &&a1, Args &&...args)
Definition: debug.h:223
static TF_API std::string GetDebugSymbolDescription(const std::string &name)
#define TF_API
Definition: api.h:23
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLuint start
Definition: glcorearb.h:475
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static void Disable(T val)
Mark debugging as disabled for enum value val.
Definition: debug.h:140
GLenum GLenum GLsizei const GLuint GLboolean enabled
Definition: glcorearb.h:2539
_Helper()=default
static TF_API std::string GetDebugSymbolDescriptions()
Definition: debug.h:122
static void Enable(T val)
Definition: debug.h:134
_Helper(Enum val)
Definition: debug.h:214
#define ARCH_UNLIKELY(x)
Definition: hints.h:30
GLdouble n
Definition: glcorearb.h:2008
TfStopwatch stopwatch
Definition: debug.h:261
friend class Tf_DebugSymbolRegistry
Definition: debug.h:355
static void _RegisterDebugSymbol(T enumVal, char const *name, char const *descrip)
Definition: debug.h:311
static TF_API void _RegisterDebugSymbolImpl(_Node *addr, char const *enumName, char const *descrip)
GLuint const GLchar * name
Definition: glcorearb.h:786
GLushort pattern
Definition: glad.h:2583
static bool IsEnabled(T val)
Definition: debug.h:176
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate active
static bool IsCompileTimeEnabled()
Definition: debug.h:194
GLuint index
Definition: glcorearb.h:786
static void EnableAll()
Definition: debug.h:151
GLuint GLfloat * val
Definition: glcorearb.h:1608
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
static TF_API bool IsDebugSymbolNameEnabled(const std::string &name)
True if the specified debug symbol is set.
**If you just want to fire and args
Definition: thread.h:618
static void Msg(const std::string &msg)
Definition: debug.h:227
TF_API void Msg(const std::string &msg) const
TimedScopeHelper(bool enabled, const char *fmt,...) ARCH_PRINTF_FUNCTION(3
ScopeHelper(bool enabled, const char *name)
Definition: debug.h:235
state
Definition: core.h:2289
static void DisableAll()
Mark debugging as disabled for all enum values of type T.
Definition: debug.h:161
std::atomic< _NodeState > state
Definition: debug.h:340
static TF_API std::vector< std::string > GetDebugSymbolNames()
Get a listing of all debug symbols.
const char * str
Definition: debug.h:250