Loading...
Searching...
No Matches
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"
39#include "pxr/base/arch/hints.h"
40
41#include <atomic>
42#include <cstdio>
43#include <string>
44#include <vector>
45
46PXR_NAMESPACE_OPEN_SCOPE
47
48class Tf_DebugSymbolRegistry;
49
52
139class TfDebug {
140 enum _NodeState { _NodeUninitialized, _NodeDisabled, _NodeEnabled };
141
142public:
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, ...)
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
344private:
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
371template <class T>
372TfDebug::_Node TfDebug::_Data<T>::nodes[];
373
374template <>
375struct 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
574PXR_NAMESPACE_CLOSE_SCOPE
575
576#endif
Define function attributes.
#define ARCH_PRINTF_FUNCTION(_fmt, _firstArg)
Macro used to indicate a function takes a printf-like specification.
Definition: attributes.h:51
Enum-based debugging messages.
Definition: debug.h:139
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 size_t GetNumDebugCodes()
Return the number of debugging symbols of this type.
Definition: debug.h:221
static bool IsEnabled(T val)
True if debugging is enabled for the enum value val.
Definition: debug.h:193
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 EnableAll()
Mark debugging as enabled for all enum values of type T.
Definition: debug.h:168
static void DisableAll()
Mark debugging as disabled for all enum values of type T.
Definition: debug.h:178
Low-cost, high-resolution timer datatype.
Definition: stopwatch.h:56
Compiler hints.
STL namespace.
A file containing basic constants and definitions.