Loading...
Searching...
No Matches
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 _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
244 ~ScopeHelper() {
245 if (active)
246 TfDebug::_ScopedOutput(false, str);
247 }
248
249 bool active;
250 const char* str;
251 };
252
253 template <bool B>
254 struct TimedScopeHelper {
255 TimedScopeHelper(bool enabled, const char* fmt, ...)
257 ~TimedScopeHelper();
258
259 bool active;
260 std::string str;
261 TfStopwatch stopwatch;
262 };
263
270 TF_API
271 static std::vector<std::string> SetDebugSymbolsByName(
272 const std::string& pattern, bool value);
273
275 TF_API
276 static bool IsDebugSymbolNameEnabled(const std::string& name);
277
282 TF_API
283 static std::string GetDebugSymbolDescriptions();
284
286 TF_API
287 static std::vector<std::string> GetDebugSymbolNames();
288
294 TF_API
295 static std::string GetDebugSymbolDescription(const std::string& name);
296
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
343private:
344
345 template <class T>
346 struct _Data {
347 static _Node nodes[_Traits<T>::NumCodes];
348 };
349
350 template <class T>
351 static _Node &_GetNode(T val) {
352 return _Data<T>::nodes[static_cast<int>(val)];
353 }
354
355 friend class Tf_DebugSymbolRegistry;
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
370template <class T>
371TfDebug::_Node TfDebug::_Data<T>::nodes[];
372
373template <>
374struct TfDebug::TimedScopeHelper<false> {
375 TimedScopeHelper(bool, const char*, ...)
376 ARCH_PRINTF_FUNCTION(3, 4) {
377 }
378};
379
392#define TF_DEBUG_CODES(...) \
393 TF_CONDITIONALLY_COMPILE_TIME_ENABLED_DEBUG_CODES(true, __VA_ARGS__)
394
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
465#define TF_DEBUG_MSG(enumVal, ...) \
466 if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; \
467 else TfDebug::_Helper(enumVal).Msg(__VA_ARGS__)
468
501#define TF_DEBUG(enumVal) \
502 if (!TfDebug::IsEnabled(enumVal)) /* empty */ ; \
503 else TfDebug::_Helper(enumVal)
504
512#define TF_INFO(x) TF_DEBUG(x)
513
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
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
574
575PXR_NAMESPACE_CLOSE_SCOPE
576
577#endif
Define function attributes.
#define ARCH_PRINTF_FUNCTION(_fmt, _firstArg)
Macro used to indicate a function takes a printf-like specification.
Definition: attributes.h:36
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.