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