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 
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"
35 #include "pxr/base/tf/preprocessorUtilsLite.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 
46 PXR_NAMESPACE_OPEN_SCOPE
47 
48 class Tf_DebugSymbolRegistry;
49 
52 
139 class TfDebug {
140  enum _NodeState { _NodeUninitialized, _NodeDisabled, _NodeEnabled };
141 
142 public:
150  template <class T>
151  static void Enable(T val) {
152  _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), true);
153  }
154 
156  template <class T>
157  static void Disable(T val) {
158  _SetNode(_GetNode(val), Tf_DebugGetEnumName(val), false);
159  }
160 
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 
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 
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()");
196  if (_Traits<T>::CompileTimeEnabled) {
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 
210  template <class T>
211  static bool IsCompileTimeEnabled() {
212  static_assert(_Traits<T>::IsDeclared,
213  "Must declare debug codes with TF_DEBUG_CODES()");
214  return _Traits<T>::CompileTimeEnabled;
215  }
216 
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 
245  ~ScopeHelper() {
246  if (active)
247  TfDebug::_ScopedOutput(false, str);
248  }
249 
250  bool active;
251  const char* str;
252  };
253 
254  template <bool B>
255  struct TimedScopeHelper {
256  TimedScopeHelper(bool enabled, const char* fmt, ...)
257  ARCH_PRINTF_FUNCTION(3, 4);
258  ~TimedScopeHelper();
259 
260  bool active;
261  std::string str;
262  TfStopwatch stopwatch;
263  };
264 
271  TF_API
272  static std::vector<std::string> SetDebugSymbolsByName(
273  const std::string& pattern, bool value);
274 
276  TF_API
277  static bool IsDebugSymbolNameEnabled(const std::string& name);
278 
283  TF_API
284  static std::string GetDebugSymbolDescriptions();
285 
287  TF_API
288  static std::vector<std::string> GetDebugSymbolNames();
289 
295  TF_API
296  static std::string GetDebugSymbolDescription(const std::string& name);
297 
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 {
348  static _Node nodes[_Traits<T>::NumCodes];
349  };
350 
351  template <class T>
352  static _Node &_GetNode(T val) {
353  return _Data<T>::nodes[static_cast<int>(val)];
354  }
355 
356  friend class Tf_DebugSymbolRegistry;
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 <>
375 struct TfDebug::TimedScopeHelper<false> {
376  TimedScopeHelper(bool, const char*, ...)
377  ARCH_PRINTF_FUNCTION(3, 4) {
378  }
379 };
380 
393 #define TF_DEBUG_CODES(...) \
394  TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(true, __VA_ARGS__)
395 
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 
466 #define TF_DEBUG_MSG(enumVal, ...) \
467  if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; else TfDebug::Helper().Msg(__VA_ARGS__)
468 
501 #define TF_DEBUG(enumVal) \
502  if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; else TfDebug::Helper()
503 
511 #define TF_INFO(x) TF_DEBUG(x)
512 
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 
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 
573 
574 PXR_NAMESPACE_CLOSE_SCOPE
575 
576 #endif
static TF_API void SetOutputFile(FILE *file)
Direct debug output to either stdout or stderr.
static bool IsCompileTimeEnabled()
True if debugging can be activated at run-time, whether or not it is currently enabled.
Definition: debug.h:211
static void DisableAll()
Mark debugging as disabled for all enum values of type T.
Definition: debug.h:178
Define function attributes.
static TF_API bool IsDebugSymbolNameEnabled(const std::string &name)
True if the specified debug symbol is set.
static TF_API std::vector< std::string > SetDebugSymbolsByName(const std::string &pattern, bool value)
Set registered debug symbols matching pattern to value.
Low-cost, high-resolution timer datatype.
Definition: stopwatch.h:55
Compiler hints.
Enum-based debugging messages.
Definition: debug.h:139
static bool IsEnabled(T val)
True if debugging is enabled for the enum value val.
Definition: debug.h:193
#define ARCH_PRINTF_FUNCTION(_fmt, _firstArg)
Macro used to indicate a function takes a printf-like specification.
Definition: attributes.h:51
static TF_API std::vector< std::string > GetDebugSymbolNames()
Get a listing of all debug symbols.
static void EnableAll()
Mark debugging as enabled for all enum values of type T.
Definition: debug.h:168
static TF_API std::string GetDebugSymbolDescriptions()
Get a description of all debug symbols and their purpose.
static size_t GetNumDebugCodes()
Return the number of debugging symbols of this type.
Definition: debug.h:221
static void Enable(T val)
Mark debugging as enabled for enum value val.
Definition: debug.h:151
static void Disable(T val)
Mark debugging as disabled for enum value val.
Definition: debug.h:157
static TF_API std::string GetDebugSymbolDescription(const std::string &name)
Get a description for the specified debug symbol.
A file containing basic constants and definitions.