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.