All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
collector.h
1//
2// Copyright 2018 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7
8#ifndef PXR_BASE_TRACE_COLLECTOR_H
9#define PXR_BASE_TRACE_COLLECTOR_H
10
11#include "pxr/pxr.h"
12
13#include "pxr/base/trace/api.h"
14#include "pxr/base/trace/concurrentList.h"
15#include "pxr/base/trace/collection.h"
16#include "pxr/base/trace/event.h"
17#include "pxr/base/trace/key.h"
18#include "pxr/base/trace/threads.h"
19
22
23#include "pxr/base/tf/pyTracing.h"
24
26#include "pxr/base/tf/refBase.h"
27#include "pxr/base/tf/refPtr.h"
29#include "pxr/base/tf/weakPtr.h"
30
32
33#include <atomic>
34#include <string>
35#include <vector>
36
37#include <tbb/spin_mutex.h>
38
39PXR_NAMESPACE_OPEN_SCOPE
40
41class TraceScopeHolder;
42
45
46
54class TraceCollector : public TfWeakBase {
55public:
56
57 TF_MALLOC_TAG_NEW("Trace", "TraceCollector");
58
59 using This = TraceCollector;
60 using ThisPtr = TraceCollectorPtr;
61
62 using TimeStamp = TraceEvent::TimeStamp;
63
64 using Key = TraceDynamicKey;
65
67 TRACE_API static TraceCollector& GetInstance() {
69 }
70
71 TRACE_API ~TraceCollector();
72
74 TRACE_API void SetEnabled(bool isEnabled);
75
77 static bool IsEnabled() {
78 return (_isEnabled.load(std::memory_order_acquire) == 1);
79 }
80
85 static constexpr TraceCategoryId GetId() { return TraceCategory::Default;}
87 static bool IsEnabled() { return TraceCollector::IsEnabled(); }
88 };
89
90#ifdef PXR_PYTHON_SUPPORT_ENABLED
93 return _isPythonTracingEnabled.load(std::memory_order_acquire) != 0;
94 }
95
97 TRACE_API void SetPythonTracingEnabled(bool enabled);
98#endif // PXR_PYTHON_SUPPORT_ENABLED
99
101 TRACE_API TimeStamp GetScopeOverhead() const;
102
105 TRACE_API void Clear();
106
109
118 template <typename Category = DefaultCategory>
119 TimeStamp BeginEvent(const Key& key) {
120 if (ARCH_LIKELY(!Category::IsEnabled())) {
121 return 0;
122 }
123 return _BeginEvent(key, Category::GetId());
124 }
125
131 template <typename Category = DefaultCategory>
132 void BeginEventAtTime(const Key& key, double ms) {
133 if (ARCH_LIKELY(!Category::IsEnabled())) {
134 return;
135 }
136 _BeginEventAtTime(key, ms, Category::GetId());
137 }
138
147 template <typename Category = DefaultCategory>
148 TimeStamp EndEvent(const Key& key) {
149 if (ARCH_LIKELY(!Category::IsEnabled())) {
150 return 0;
151 }
152 return _EndEvent(key, Category::GetId());
153 }
154
160 template <typename Category = DefaultCategory>
161 void EndEventAtTime(const Key& key, double ms) {
162 if (ARCH_LIKELY(!Category::IsEnabled())) {
163 return;
164 }
165 _EndEventAtTime(key, ms, Category::GetId());
166 }
167
168
172
173 template <typename Category = DefaultCategory>
174 TimeStamp MarkerEvent(const Key& key) {
175 if (ARCH_LIKELY(!Category::IsEnabled())) {
176 return 0;
177 }
178 return _MarkerEvent(key, Category::GetId());
179 }
180
186 template <typename Category = DefaultCategory>
187 void MarkerEventAtTime(const Key& key, double ms) {
188 if (ARCH_LIKELY(!Category::IsEnabled())) {
189 return;
190 }
191 _MarkerEventAtTime(key, ms, Category::GetId());
192 }
193
199 template <typename Category = DefaultCategory>
200 void BeginScope(const TraceKey& _key) {
201 if (ARCH_LIKELY(!Category::IsEnabled()))
202 return;
203
204 _BeginScope(_key, Category::GetId());
205 }
206
212 template <typename Category, typename... Args>
214 const TraceKey& key, Args&&... args) {
215 static_assert( sizeof...(Args) %2 == 0,
216 "Data arguments must come in pairs");
217
218 if (ARCH_LIKELY(!Category::IsEnabled()))
219 return;
220
221 _PerThreadData *threadData = _GetThreadData();
222 threadData->BeginScope(key, Category::GetId());
223 _StoreDataRec(threadData, Category::GetId(), std::forward<Args>(args)...);
224 }
225
230 template <typename... Args>
231 void BeginScope(const TraceKey& key, Args&&... args) {
232 static_assert( sizeof...(Args) %2 == 0,
233 "Data arguments must come in pairs");
234
235 // Explicitly cast to TraceCategoryId so overload resolution choose the
236 // version with a category arguement.
237 BeginScope<DefaultCategory>(key,
238 std::forward<Args>(args)...);
239 }
240
245 template <typename Category = DefaultCategory>
246 void EndScope(const TraceKey& key) {
247 if (ARCH_LIKELY(!Category::IsEnabled()))
248 return;
249
250 _EndScope(key, Category::GetId());
251 }
252
259 TRACE_API
260 static void
261 Scope(const TraceKey& key, TimeStamp start, TimeStamp stop) noexcept;
262
269 template <typename Category = DefaultCategory>
270 void Scope(const TraceKey& key, TimeStamp start, TimeStamp stop) {
271 if (ARCH_LIKELY(!Category::IsEnabled()))
272 return;
273 _PerThreadData *threadData = _GetThreadData();
274 threadData->EmplaceEvent(
275 TraceEvent::Timespan, key, start, stop, Category::GetId());
276 }
277
281 template <typename Category, typename... Args>
282 void ScopeArgs(Args&&... args) {
283 static_assert( sizeof...(Args) %2 == 0,
284 "Data arguments must come in pairs");
285
286 if (ARCH_LIKELY(!Category::IsEnabled()))
287 return;
288
289 _PerThreadData *threadData = _GetThreadData();
290 _StoreDataRec(threadData, Category::GetId(), std::forward<Args>(args)...);
291 }
292
299 template <typename... Args>
300 void ScopeArgs(Args&&... args) {
301 static_assert( sizeof...(Args) %2 == 0,
302 "Data arguments must come in pairs");
303
304 ScopeArgs<DefaultCategory>(std::forward<Args>(args)...);
305 }
306
307
314 template <typename Category = DefaultCategory>
315 void MarkerEventStatic(const TraceKey& key) {
316 if (ARCH_LIKELY(!Category::IsEnabled()))
317 return;
318
319 _PerThreadData *threadData = _GetThreadData();
320 threadData->EmplaceEvent(
321 TraceEvent::Marker, key, Category::GetId());
322 }
323
328 template <typename Category = DefaultCategory, typename T>
329 void StoreData(const TraceKey &key, const T& value) {
330 if (ARCH_UNLIKELY(Category::IsEnabled())) {
331 _StoreData(_GetThreadData(), key, Category::GetId(), value);
332 }
333 }
334
336 template <typename Category = DefaultCategory>
337 void RecordCounterDelta(const TraceKey &key,
338 double delta) {
339 // Only record counter values if the collector is enabled.
340 if (ARCH_UNLIKELY(Category::IsEnabled())) {
341 _PerThreadData *threadData = _GetThreadData();
342 threadData->EmplaceEvent(
343 TraceEvent::CounterDelta, key, delta, Category::GetId());
344 }
345 }
346
348 template <typename Category = DefaultCategory>
349 void RecordCounterDelta(const Key &key, double delta) {
350 if (ARCH_UNLIKELY(Category::IsEnabled())) {
351 _PerThreadData *threadData = _GetThreadData();
352 threadData->CounterDelta(key, delta, Category::GetId());
353 }
354 }
355
357 template <typename Category = DefaultCategory>
358 void RecordCounterValue(const TraceKey &key, double value) {
359 // Only record counter values if the collector is enabled.
360 if (ARCH_UNLIKELY(Category::IsEnabled())) {
361 _PerThreadData *threadData = _GetThreadData();
362 threadData->EmplaceEvent(
363 TraceEvent::CounterValue, key, value, Category::GetId());
364 }
365 }
366
369 template <typename Category = DefaultCategory>
370 void RecordCounterValue(const Key &key, double value) {
371
372 if (ARCH_UNLIKELY(Category::IsEnabled())) {
373 _PerThreadData *threadData = _GetThreadData();
374 threadData->CounterValue(key, value, Category::GetId());
375 }
376 }
377
379
381 const std::string& GetLabel() {
382 return _label;
383 }
384
389 TRACE_API void CreateCollection();
390
391private:
392
394
395 friend class TfSingleton<TraceCollector>;
396
397 class _PerThreadData;
398
399 // Return a pointer to existing per-thread data or create one if none
400 // exists.
401 TRACE_API _PerThreadData* _GetThreadData() noexcept;
402
403 TRACE_API TimeStamp _BeginEvent(const Key& key, TraceCategoryId cat);
404
405 TRACE_API void _BeginEventAtTime(
406 const Key& key, double ms, TraceCategoryId cat);
407
408 TRACE_API TimeStamp _EndEvent(const Key& key, TraceCategoryId cat);
409
410 TRACE_API void _EndEventAtTime(
411 const Key& key, double ms, TraceCategoryId cat);
412
413 TRACE_API TimeStamp _MarkerEvent(const Key& key, TraceCategoryId cat);
414
415 TRACE_API void _MarkerEventAtTime(
416 const Key& key, double ms, TraceCategoryId cat);
417
418 // This is the fast execution path called from the TRACE_FUNCTION
419 // and TRACE_SCOPE macros
420 void _BeginScope(const TraceKey& key, TraceCategoryId cat)
421 {
422 // Note we're not calling _NewEvent, don't need to cache key
423 _PerThreadData *threadData = _GetThreadData();
424 threadData->BeginScope(key, cat);
425 }
426
427 // This is the fast execution path called from the TRACE_FUNCTION
428 // and TRACE_SCOPE macros
429 TRACE_API void _EndScope(const TraceKey& key, TraceCategoryId cat);
430
431 TRACE_API void _MeasureScopeOverhead();
432
433#ifdef PXR_PYTHON_SUPPORT_ENABLED
434 // Callback function registered as a python tracing function.
435 void _PyTracingCallback(const TfPyTraceInfo &info);
436#endif // PXR_PYTHON_SUPPORT_ENABLED
437
438 // Implementation for small data that can stored inlined with the event.
439 template <typename T,
440 typename std::enable_if<
441 sizeof(T) <= sizeof(uintptr_t)
442 && !std::is_pointer<T>::value , int>::type = 0>
443 void _StoreData(_PerThreadData* threadData, const TraceKey &key,
444 TraceCategoryId cat, const T& value) {
445 threadData->StoreData(key, value, cat);
446 }
447
448 // Implementation for data that must be stored outside of the events.
449 template <typename T,
450 typename std::enable_if<
451 (sizeof(T) > sizeof(uintptr_t))
452 && !std::is_pointer<T>::value, int>::type = 0>
453 void _StoreData(_PerThreadData* threadData, const TraceKey &key,
454 TraceCategoryId cat, const T& value) {
455 threadData->StoreLargeData(key, value, cat);
456 }
457
458 // Specialization for c string
459 void _StoreData(
460 _PerThreadData* threadData,
461 const TraceKey &key,
462 TraceCategoryId cat,
463 const char* value) {
464 threadData->StoreLargeData(key, value, cat);
465 }
466
467 // Specialization for std::string
468 void _StoreData(
469 _PerThreadData* threadData,
470 const TraceKey &key,
471 TraceCategoryId cat,
472 const std::string& value) {
473 threadData->StoreLargeData(key, value.c_str(), cat);
474 }
475
476 // Variadic version to store multiple data events in one function call.
477 template <typename K, typename T, typename... Args>
478 void _StoreDataRec(
479 _PerThreadData* threadData, TraceCategoryId cat, K&& key,
480 const T& value, Args&&... args) {
481 _StoreData(threadData, std::forward<K>(key), cat, value);
482 _StoreDataRec(threadData, cat, std::forward<Args>(args)...);
483 }
484
485 // Base case to terminate template recursion
486 void _StoreDataRec(_PerThreadData* threadData, TraceCategoryId cat) {}
487
488
489 // Thread-local storage, accessed via _GetThreadData()
490 //
491 class _PerThreadData {
492 public:
493 using EventList = TraceCollection::EventList;
494
495 _PerThreadData();
496 ~_PerThreadData();
497
498 const TraceThreadId& GetThreadId() const {
499 return _threadIndex;
500 }
501 TimeStamp BeginEvent(const Key& key, TraceCategoryId cat);
502 TimeStamp EndEvent(const Key& key, TraceCategoryId cat);
503 TimeStamp MarkerEvent(const Key& key, TraceCategoryId cat);
504
505 // Debug Methods
506 void BeginEventAtTime(
507 const Key& key, double ms, TraceCategoryId cat);
508 void EndEventAtTime(const Key& key, double ms, TraceCategoryId cat);
509 void MarkerEventAtTime(const Key& key, double ms, TraceCategoryId cat);
510
511 void BeginScope(const TraceKey& key, TraceCategoryId cat) {
512 AtomicRef lock(_writing);
513 _BeginScope(key, cat);
514 }
515
516 void EndScope(const TraceKey& key, TraceCategoryId cat) {
517 AtomicRef lock(_writing);
518 _EndScope(key, cat);
519 }
520
521 TRACE_API void CounterDelta(
522 const Key&, double value, TraceCategoryId cat);
523
524 TRACE_API void CounterValue(
525 const Key&, double value, TraceCategoryId cat);
526
527 template <typename T>
528 void StoreData(
529 const TraceKey& key, const T& data, TraceCategoryId cat) {
530 AtomicRef lock(_writing);
531 _events.load(std::memory_order_acquire)->EmplaceBack(
532 TraceEvent::Data, key, data, cat);
533 }
534
535 template <typename T>
536 void StoreLargeData(
537 const TraceKey& key, const T& data, TraceCategoryId cat) {
538 AtomicRef lock(_writing);
539 EventList* events = _events.load(std::memory_order_acquire);
540 const auto* cached = events->StoreData(data);
541 events->EmplaceBack(TraceEvent::Data, key, cached, cat);
542 }
543
544 template <typename... Args>
545 void EmplaceEvent(Args&&... args) {
546 AtomicRef lock(_writing);
547 _events.load(std::memory_order_acquire)->EmplaceBack(
548 std::forward<Args>(args)...);
549 }
550
551#ifdef PXR_PYTHON_SUPPORT_ENABLED
552 void PushPyScope(const Key& key, bool enabled);
553 void PopPyScope(bool enabled);
554#endif // PXR_PYTHON_SUPPORT_ENABLED
555
556 // These methods can be called from threads at the same time as the
557 // other methods.
558 std::unique_ptr<EventList> GetCollectionData();
559 void Clear();
560
561 private:
562 void _BeginScope(const TraceKey& key, TraceCategoryId cat) {
563 _events.load(std::memory_order_acquire)->EmplaceBack(
564 TraceEvent::Begin, key, cat);
565 }
566
567 void _EndScope(const TraceKey& key, TraceCategoryId cat);
568
569 // Flag to let other threads know that the list is being written to.
570 mutable std::atomic<bool> _writing;
571 std::atomic<EventList*> _events;
572
573 class AtomicRef {
574 public:
575 AtomicRef(std::atomic<bool>& b) : _bool(b) {
576 _bool.store(true, std::memory_order_release);
577 }
578 ~AtomicRef() {
579 _bool.store(false, std::memory_order_release);
580 }
581 private:
582 std::atomic<bool>& _bool;
583 };
584
585 // An integer that is unique for each thread launched by any
586 // threadDispatcher. Each time a thread is Start-ed it get's
587 // a new id.
588 //
589 TraceThreadId _threadIndex;
590
591 // When auto-tracing python frames, this stores the stack of scopes.
592 struct PyScope {
593 Key key;
594 };
595 std::vector<PyScope> _pyScopes;
596 };
597
598 TRACE_API static std::atomic<int> _isEnabled;
599
600 // A list with one _PerThreadData per thread.
601 TraceConcurrentList<_PerThreadData> _allPerThreadData;
602
603 std::string _label;
604
605 TimeStamp _measuredScopeOverhead;
606
607 // These members are unused if Python support is disabled. However, we
608 // leave them in place and just mark them unused to provide ABI
609 // compatibility between USD builds with and without Python enabled.
610#ifndef PXR_PYTHON_SUPPORT_ENABLED
611 ARCH_PRAGMA_PUSH
612 ARCH_PRAGMA_UNUSED_PRIVATE_FIELD
613#endif
614 std::atomic<int> _isPythonTracingEnabled;
615 TfPyTraceFnId _pyTraceFnId;
616#ifndef PXR_PYTHON_SUPPORT_ENABLED
617 ARCH_PRAGMA_POP
618#endif
619};
620
621TRACE_API_TEMPLATE_CLASS(TfSingleton<TraceCollector>);
622
623PXR_NAMESPACE_CLOSE_SCOPE
624
625#endif // PXR_BASE_TRACE_COLLECTOR_H
uint32_t TraceCategoryId
Categories that a TraceReporter can use to filter events.
Definition: category.h:27
Manage a single instance of an object (see.
Definition: singleton.h:105
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
Definition: singleton.h:120
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:124
This is a singleton class that records TraceEvent instances and populates TraceCollection instances.
Definition: collector.h:54
TRACE_API void SetEnabled(bool isEnabled)
Enables or disables collection of events for DefaultCategory.
void BeginEventAtTime(const Key &key, double ms)
Record a begin event with key at a specified time if Category is enabled.
Definition: collector.h:132
bool IsPythonTracingEnabled() const
Returns whether automatic tracing of all python scopes is enabled.
Definition: collector.h:92
void RecordCounterDelta(const TraceKey &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:337
TimeStamp MarkerEvent(const Key &key)
Record a marker event with key if Category is enabled.
Definition: collector.h:174
void EndEventAtTime(const Key &key, double ms)
Record an end event with key at a specified time if Category is enabled.
Definition: collector.h:161
void ScopeArgs(Args &&... args)
Record multiple data events with the default category if collection of events is enabled.
Definition: collector.h:300
TRACE_API void SetPythonTracingEnabled(bool enabled)
Set whether automatic tracing of all python scopes is enabled.
void BeginScope(const TraceKey &_key)
Record a begin event for a scope described by key if Category is enabled.
Definition: collector.h:200
TimeStamp EndEvent(const Key &key)
Record an end event with key if Category is enabled.
Definition: collector.h:148
TRACE_API void CreateCollection()
Produces a TraceCollection from all the events that recorded in the collector and issues a TraceColle...
void StoreData(const TraceKey &key, const T &value)
Record a data event with the given key and value if Category is enabled.
Definition: collector.h:329
void MarkerEventAtTime(const Key &key, double ms)
Record a marker event with key at a specified time if Category is enabled.
Definition: collector.h:187
static TRACE_API void Scope(const TraceKey &key, TimeStamp start, TimeStamp stop) noexcept
Record a scope event described by key that started at start for the DefaultCategory.
void ScopeArgs(Args &&... args)
Record multiple data events with category cat if Category is enabled.
Definition: collector.h:282
static bool IsEnabled()
Returns whether collection of events is enabled for DefaultCategory.
Definition: collector.h:77
TRACE_API void Clear()
Clear all pending events from the collector.
const std::string & GetLabel()
Return the label associated with this collector.
Definition: collector.h:381
void RecordCounterValue(const TraceKey &key, double value)
Record a counter value for a name key if Category is enabled.
Definition: collector.h:358
static TRACE_API TraceCollector & GetInstance()
Returns the singleton instance.
Definition: collector.h:67
TRACE_API TimeStamp GetScopeOverhead() const
Return the overhead cost to measure a scope.
TimeStamp BeginEvent(const Key &key)
Record a begin event with key if Category is enabled.
Definition: collector.h:119
void RecordCounterValue(const Key &key, double value)
Record a counter value for a name key and delta value if Category is enabled.
Definition: collector.h:370
void Scope(const TraceKey &key, TimeStamp start, TimeStamp stop)
Record a scope event described by key that started at start if Category is enabled.
Definition: collector.h:270
void EndScope(const TraceKey &key)
Record an end event described by key if Category is enabled.
Definition: collector.h:246
void BeginScope(const TraceKey &key, Args &&... args)
Record a begin event for a scope described by key and store data arguments if Category is enabled.
Definition: collector.h:231
void BeginScope(const TraceKey &key, Args &&... args)
Record a begin event for a scope described by key and a specified category and store data arguments i...
Definition: collector.h:213
void MarkerEventStatic(const TraceKey &key)
Record a scope event described by key that started at start if Category is enabled.
Definition: collector.h:315
void RecordCounterDelta(const Key &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:349
This class supports thread safe insertion and iteration over a list of items.
This class stores data used to create dynamic keys which can be referenced in TraceEvent instances.
Definition: dynamicKey.h:25
uint64_t TimeStamp
Time in "ticks".
Definition: event.h:33
This class represents an ordered collection of TraceEvents and the TraceDynamicKeys and data that the...
Definition: eventList.h:29
A wrapper around a TraceStaticKeyData pointer that is stored in TraceEvent instances.
Definition: key.h:23
This class represents an identifier for a thread.
Definition: threads.h:23
Standard pointer typedefs.
#define TF_DECLARE_WEAK_PTRS(type)
Define standard weak pointer types.
Definition: declarePtrs.h:45
#define TF_DECLARE_WEAK_AND_REF_PTRS(type)
Define standard weak, ref, and vector pointer types.
Definition: declarePtrs.h:72
#define TF_MALLOC_TAG_NEW(name1, name2)
Enable lib/tf memory management.
Definition: mallocTag.h:475
Pragmas for controlling compiler-specific behaviors.
Reference counting.
Manage a single instance of an object.
Structure passed to python trace functions.
Definition: pyTracing.h:27
Default Trace category which corresponds to events stored for TRACE_ macros.
Definition: collector.h:83
static constexpr TraceCategoryId GetId()
Returns TraceCategory::Default.
Definition: collector.h:85
static bool IsEnabled()
Returns the result of TraceCollector::IsEnabled.
Definition: collector.h:87
Pointer storage with deletion detection.