Loading...
Searching...
No Matches
collector.h
1//
2// Copyright 2018 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
25#ifndef PXR_BASE_TRACE_COLLECTOR_H
26#define PXR_BASE_TRACE_COLLECTOR_H
27
28#include "pxr/pxr.h"
29
30#include "pxr/base/trace/api.h"
31#include "pxr/base/trace/concurrentList.h"
32#include "pxr/base/trace/collection.h"
33#include "pxr/base/trace/event.h"
34#include "pxr/base/trace/key.h"
35#include "pxr/base/trace/threads.h"
36
39
40#include "pxr/base/tf/pyTracing.h"
41
43#include "pxr/base/tf/refBase.h"
44#include "pxr/base/tf/refPtr.h"
46#include "pxr/base/tf/weakPtr.h"
47
49
50#include <atomic>
51#include <string>
52#include <vector>
53
54#include <tbb/spin_mutex.h>
55
56PXR_NAMESPACE_OPEN_SCOPE
57
58class TraceScopeHolder;
59
62
63
71class TraceCollector : public TfWeakBase {
72public:
73
74 TF_MALLOC_TAG_NEW("Trace", "TraceCollector");
75
76 using This = TraceCollector;
77 using ThisPtr = TraceCollectorPtr;
78
79 using TimeStamp = TraceEvent::TimeStamp;
80
81 using Key = TraceDynamicKey;
82
84 TRACE_API static TraceCollector& GetInstance() {
86 }
87
88 TRACE_API ~TraceCollector();
89
91 TRACE_API void SetEnabled(bool isEnabled);
92
94 static bool IsEnabled() {
95 return (_isEnabled.load(std::memory_order_acquire) == 1);
96 }
97
102 static constexpr TraceCategoryId GetId() { return TraceCategory::Default;}
104 static bool IsEnabled() { return TraceCollector::IsEnabled(); }
105 };
106
107#ifdef PXR_PYTHON_SUPPORT_ENABLED
110 return _isPythonTracingEnabled.load(std::memory_order_acquire) != 0;
111 }
112
114 TRACE_API void SetPythonTracingEnabled(bool enabled);
115#endif // PXR_PYTHON_SUPPORT_ENABLED
116
118 TRACE_API TimeStamp GetScopeOverhead() const;
119
122 TRACE_API void Clear();
123
126
135 template <typename Category = DefaultCategory>
136 TimeStamp BeginEvent(const Key& key) {
137 if (ARCH_LIKELY(!Category::IsEnabled())) {
138 return 0;
139 }
140 return _BeginEvent(key, Category::GetId());
141 }
142
148 template <typename Category = DefaultCategory>
149 void BeginEventAtTime(const Key& key, double ms) {
150 if (ARCH_LIKELY(!Category::IsEnabled())) {
151 return;
152 }
153 _BeginEventAtTime(key, ms, Category::GetId());
154 }
155
164 template <typename Category = DefaultCategory>
165 TimeStamp EndEvent(const Key& key) {
166 if (ARCH_LIKELY(!Category::IsEnabled())) {
167 return 0;
168 }
169 return _EndEvent(key, Category::GetId());
170 }
171
177 template <typename Category = DefaultCategory>
178 void EndEventAtTime(const Key& key, double ms) {
179 if (ARCH_LIKELY(!Category::IsEnabled())) {
180 return;
181 }
182 _EndEventAtTime(key, ms, Category::GetId());
183 }
184
185
189
190 template <typename Category = DefaultCategory>
191 TimeStamp MarkerEvent(const Key& key) {
192 if (ARCH_LIKELY(!Category::IsEnabled())) {
193 return 0;
194 }
195 return _MarkerEvent(key, Category::GetId());
196 }
197
203 template <typename Category = DefaultCategory>
204 void MarkerEventAtTime(const Key& key, double ms) {
205 if (ARCH_LIKELY(!Category::IsEnabled())) {
206 return;
207 }
208 _MarkerEventAtTime(key, ms, Category::GetId());
209 }
210
216 template <typename Category = DefaultCategory>
217 void BeginScope(const TraceKey& _key) {
218 if (ARCH_LIKELY(!Category::IsEnabled()))
219 return;
220
221 _BeginScope(_key, Category::GetId());
222 }
223
229 template <typename Category, typename... Args>
231 const TraceKey& key, Args&&... args) {
232 static_assert( sizeof...(Args) %2 == 0,
233 "Data arguments must come in pairs");
234
235 if (ARCH_LIKELY(!Category::IsEnabled()))
236 return;
237
238 _PerThreadData *threadData = _GetThreadData();
239 threadData->BeginScope(key, Category::GetId());
240 _StoreDataRec(threadData, Category::GetId(), std::forward<Args>(args)...);
241 }
242
247 template <typename... Args>
248 void BeginScope(const TraceKey& key, Args&&... args) {
249 static_assert( sizeof...(Args) %2 == 0,
250 "Data arguments must come in pairs");
251
252 // Explicitly cast to TraceCategoryId so overload resolution choose the
253 // version with a category arguement.
254 BeginScope<DefaultCategory>(key,
255 std::forward<Args>(args)...);
256 }
257
262 template <typename Category = DefaultCategory>
263 void EndScope(const TraceKey& key) {
264 if (ARCH_LIKELY(!Category::IsEnabled()))
265 return;
266
267 _EndScope(key, Category::GetId());
268 }
269
276 TRACE_API
277 static void
278 Scope(const TraceKey& key, TimeStamp start, TimeStamp stop) noexcept;
279
286 template <typename Category = DefaultCategory>
287 void Scope(const TraceKey& key, TimeStamp start, TimeStamp stop) {
288 if (ARCH_LIKELY(!Category::IsEnabled()))
289 return;
290 _PerThreadData *threadData = _GetThreadData();
291 threadData->EmplaceEvent(
292 TraceEvent::Timespan, key, start, stop, Category::GetId());
293 }
294
298 template <typename Category, typename... Args>
299 void ScopeArgs(Args&&... args) {
300 static_assert( sizeof...(Args) %2 == 0,
301 "Data arguments must come in pairs");
302
303 if (ARCH_LIKELY(!Category::IsEnabled()))
304 return;
305
306 _PerThreadData *threadData = _GetThreadData();
307 _StoreDataRec(threadData, Category::GetId(), std::forward<Args>(args)...);
308 }
309
316 template <typename... Args>
317 void ScopeArgs(Args&&... args) {
318 static_assert( sizeof...(Args) %2 == 0,
319 "Data arguments must come in pairs");
320
321 ScopeArgs<DefaultCategory>(std::forward<Args>(args)...);
322 }
323
324
331 template <typename Category = DefaultCategory>
332 void MarkerEventStatic(const TraceKey& key) {
333 if (ARCH_LIKELY(!Category::IsEnabled()))
334 return;
335
336 _PerThreadData *threadData = _GetThreadData();
337 threadData->EmplaceEvent(
338 TraceEvent::Marker, key, Category::GetId());
339 }
340
345 template <typename Category = DefaultCategory, typename T>
346 void StoreData(const TraceKey &key, const T& value) {
347 if (ARCH_UNLIKELY(Category::IsEnabled())) {
348 _StoreData(_GetThreadData(), key, Category::GetId(), value);
349 }
350 }
351
353 template <typename Category = DefaultCategory>
354 void RecordCounterDelta(const TraceKey &key,
355 double delta) {
356 // Only record counter values if the collector is enabled.
357 if (ARCH_UNLIKELY(Category::IsEnabled())) {
358 _PerThreadData *threadData = _GetThreadData();
359 threadData->EmplaceEvent(
360 TraceEvent::CounterDelta, key, delta, Category::GetId());
361 }
362 }
363
365 template <typename Category = DefaultCategory>
366 void RecordCounterDelta(const Key &key, double delta) {
367 if (ARCH_UNLIKELY(Category::IsEnabled())) {
368 _PerThreadData *threadData = _GetThreadData();
369 threadData->CounterDelta(key, delta, Category::GetId());
370 }
371 }
372
374 template <typename Category = DefaultCategory>
375 void RecordCounterValue(const TraceKey &key, double value) {
376 // Only record counter values if the collector is enabled.
377 if (ARCH_UNLIKELY(Category::IsEnabled())) {
378 _PerThreadData *threadData = _GetThreadData();
379 threadData->EmplaceEvent(
380 TraceEvent::CounterValue, key, value, Category::GetId());
381 }
382 }
383
386 template <typename Category = DefaultCategory>
387 void RecordCounterValue(const Key &key, double value) {
388
389 if (ARCH_UNLIKELY(Category::IsEnabled())) {
390 _PerThreadData *threadData = _GetThreadData();
391 threadData->CounterValue(key, value, Category::GetId());
392 }
393 }
394
396
398 const std::string& GetLabel() {
399 return _label;
400 }
401
406 TRACE_API void CreateCollection();
407
408private:
409
411
412 friend class TfSingleton<TraceCollector>;
413
414 class _PerThreadData;
415
416 // Return a pointer to existing per-thread data or create one if none
417 // exists.
418 TRACE_API _PerThreadData* _GetThreadData() noexcept;
419
420 TRACE_API TimeStamp _BeginEvent(const Key& key, TraceCategoryId cat);
421
422 TRACE_API void _BeginEventAtTime(
423 const Key& key, double ms, TraceCategoryId cat);
424
425 TRACE_API TimeStamp _EndEvent(const Key& key, TraceCategoryId cat);
426
427 TRACE_API void _EndEventAtTime(
428 const Key& key, double ms, TraceCategoryId cat);
429
430 TRACE_API TimeStamp _MarkerEvent(const Key& key, TraceCategoryId cat);
431
432 TRACE_API void _MarkerEventAtTime(
433 const Key& key, double ms, TraceCategoryId cat);
434
435 // This is the fast execution path called from the TRACE_FUNCTION
436 // and TRACE_SCOPE macros
437 void _BeginScope(const TraceKey& key, TraceCategoryId cat)
438 {
439 // Note we're not calling _NewEvent, don't need to cache key
440 _PerThreadData *threadData = _GetThreadData();
441 threadData->BeginScope(key, cat);
442 }
443
444 // This is the fast execution path called from the TRACE_FUNCTION
445 // and TRACE_SCOPE macros
446 TRACE_API void _EndScope(const TraceKey& key, TraceCategoryId cat);
447
448 TRACE_API void _MeasureScopeOverhead();
449
450#ifdef PXR_PYTHON_SUPPORT_ENABLED
451 // Callback function registered as a python tracing function.
452 void _PyTracingCallback(const TfPyTraceInfo &info);
453#endif // PXR_PYTHON_SUPPORT_ENABLED
454
455 // Implementation for small data that can stored inlined with the event.
456 template <typename T,
457 typename std::enable_if<
458 sizeof(T) <= sizeof(uintptr_t)
459 && !std::is_pointer<T>::value , int>::type = 0>
460 void _StoreData(_PerThreadData* threadData, const TraceKey &key,
461 TraceCategoryId cat, const T& value) {
462 threadData->StoreData(key, value, cat);
463 }
464
465 // Implementation for data that must be stored outside of the events.
466 template <typename T,
467 typename std::enable_if<
468 (sizeof(T) > sizeof(uintptr_t))
469 && !std::is_pointer<T>::value, int>::type = 0>
470 void _StoreData(_PerThreadData* threadData, const TraceKey &key,
471 TraceCategoryId cat, const T& value) {
472 threadData->StoreLargeData(key, value, cat);
473 }
474
475 // Specialization for c string
476 void _StoreData(
477 _PerThreadData* threadData,
478 const TraceKey &key,
479 TraceCategoryId cat,
480 const char* value) {
481 threadData->StoreLargeData(key, value, cat);
482 }
483
484 // Specialization for std::string
485 void _StoreData(
486 _PerThreadData* threadData,
487 const TraceKey &key,
488 TraceCategoryId cat,
489 const std::string& value) {
490 threadData->StoreLargeData(key, value.c_str(), cat);
491 }
492
493 // Variadic version to store multiple data events in one function call.
494 template <typename K, typename T, typename... Args>
495 void _StoreDataRec(
496 _PerThreadData* threadData, TraceCategoryId cat, K&& key,
497 const T& value, Args&&... args) {
498 _StoreData(threadData, std::forward<K>(key), cat, value);
499 _StoreDataRec(threadData, cat, std::forward<Args>(args)...);
500 }
501
502 // Base case to terminate template recursion
503 void _StoreDataRec(_PerThreadData* threadData, TraceCategoryId cat) {}
504
505
506 // Thread-local storage, accessed via _GetThreadData()
507 //
508 class _PerThreadData {
509 public:
510 using EventList = TraceCollection::EventList;
511
512 _PerThreadData();
513 ~_PerThreadData();
514
515 const TraceThreadId& GetThreadId() const {
516 return _threadIndex;
517 }
518 TimeStamp BeginEvent(const Key& key, TraceCategoryId cat);
519 TimeStamp EndEvent(const Key& key, TraceCategoryId cat);
520 TimeStamp MarkerEvent(const Key& key, TraceCategoryId cat);
521
522 // Debug Methods
523 void BeginEventAtTime(
524 const Key& key, double ms, TraceCategoryId cat);
525 void EndEventAtTime(const Key& key, double ms, TraceCategoryId cat);
526 void MarkerEventAtTime(const Key& key, double ms, TraceCategoryId cat);
527
528 void BeginScope(const TraceKey& key, TraceCategoryId cat) {
529 AtomicRef lock(_writing);
530 _BeginScope(key, cat);
531 }
532
533 void EndScope(const TraceKey& key, TraceCategoryId cat) {
534 AtomicRef lock(_writing);
535 _EndScope(key, cat);
536 }
537
538 TRACE_API void CounterDelta(
539 const Key&, double value, TraceCategoryId cat);
540
541 TRACE_API void CounterValue(
542 const Key&, double value, TraceCategoryId cat);
543
544 template <typename T>
545 void StoreData(
546 const TraceKey& key, const T& data, TraceCategoryId cat) {
547 AtomicRef lock(_writing);
548 _events.load(std::memory_order_acquire)->EmplaceBack(
549 TraceEvent::Data, key, data, cat);
550 }
551
552 template <typename T>
553 void StoreLargeData(
554 const TraceKey& key, const T& data, TraceCategoryId cat) {
555 AtomicRef lock(_writing);
556 EventList* events = _events.load(std::memory_order_acquire);
557 const auto* cached = events->StoreData(data);
558 events->EmplaceBack(TraceEvent::Data, key, cached, cat);
559 }
560
561 template <typename... Args>
562 void EmplaceEvent(Args&&... args) {
563 AtomicRef lock(_writing);
564 _events.load(std::memory_order_acquire)->EmplaceBack(
565 std::forward<Args>(args)...);
566 }
567
568#ifdef PXR_PYTHON_SUPPORT_ENABLED
569 void PushPyScope(const Key& key, bool enabled);
570 void PopPyScope(bool enabled);
571#endif // PXR_PYTHON_SUPPORT_ENABLED
572
573 // These methods can be called from threads at the same time as the
574 // other methods.
575 std::unique_ptr<EventList> GetCollectionData();
576 void Clear();
577
578 private:
579 void _BeginScope(const TraceKey& key, TraceCategoryId cat) {
580 _events.load(std::memory_order_acquire)->EmplaceBack(
581 TraceEvent::Begin, key, cat);
582 }
583
584 void _EndScope(const TraceKey& key, TraceCategoryId cat);
585
586 // Flag to let other threads know that the list is being written to.
587 mutable std::atomic<bool> _writing;
588 std::atomic<EventList*> _events;
589
590 class AtomicRef {
591 public:
592 AtomicRef(std::atomic<bool>& b) : _bool(b) {
593 _bool.store(true, std::memory_order_release);
594 }
595 ~AtomicRef() {
596 _bool.store(false, std::memory_order_release);
597 }
598 private:
599 std::atomic<bool>& _bool;
600 };
601
602 // An integer that is unique for each thread launched by any
603 // threadDispatcher. Each time a thread is Start-ed it get's
604 // a new id.
605 //
606 TraceThreadId _threadIndex;
607
608 // When auto-tracing python frames, this stores the stack of scopes.
609 struct PyScope {
610 Key key;
611 };
612 std::vector<PyScope> _pyScopes;
613 };
614
615 TRACE_API static std::atomic<int> _isEnabled;
616
617 // A list with one _PerThreadData per thread.
618 TraceConcurrentList<_PerThreadData> _allPerThreadData;
619
620 std::string _label;
621
622 TimeStamp _measuredScopeOverhead;
623
624 // These members are unused if Python support is disabled. However, we
625 // leave them in place and just mark them unused to provide ABI
626 // compatibility between USD builds with and without Python enabled.
627#ifndef PXR_PYTHON_SUPPORT_ENABLED
628 ARCH_PRAGMA_PUSH
629 ARCH_PRAGMA_UNUSED_PRIVATE_FIELD
630#endif
631 std::atomic<int> _isPythonTracingEnabled;
632 TfPyTraceFnId _pyTraceFnId;
633#ifndef PXR_PYTHON_SUPPORT_ENABLED
634 ARCH_PRAGMA_POP
635#endif
636};
637
638TRACE_API_TEMPLATE_CLASS(TfSingleton<TraceCollector>);
639
640PXR_NAMESPACE_CLOSE_SCOPE
641
642#endif // PXR_BASE_TRACE_COLLECTOR_H
uint32_t TraceCategoryId
Categories that a TraceReporter can use to filter events.
Definition: category.h:44
Manage a single instance of an object (see.
Definition: singleton.h:122
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
Definition: singleton.h:137
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141
This is a singleton class that records TraceEvent instances and populates TraceCollection instances.
Definition: collector.h:71
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:149
bool IsPythonTracingEnabled() const
Returns whether automatic tracing of all python scopes is enabled.
Definition: collector.h:109
void RecordCounterDelta(const TraceKey &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:354
TimeStamp MarkerEvent(const Key &key)
Record a marker event with key if Category is enabled.
Definition: collector.h:191
void EndEventAtTime(const Key &key, double ms)
Record an end event with key at a specified time if Category is enabled.
Definition: collector.h:178
void ScopeArgs(Args &&... args)
Record multiple data events with the default category if collection of events is enabled.
Definition: collector.h:317
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:217
TimeStamp EndEvent(const Key &key)
Record an end event with key if Category is enabled.
Definition: collector.h:165
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:346
void MarkerEventAtTime(const Key &key, double ms)
Record a marker event with key at a specified time if Category is enabled.
Definition: collector.h:204
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:299
static bool IsEnabled()
Returns whether collection of events is enabled for DefaultCategory.
Definition: collector.h:94
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:398
void RecordCounterValue(const TraceKey &key, double value)
Record a counter value for a name key if Category is enabled.
Definition: collector.h:375
static TRACE_API TraceCollector & GetInstance()
Returns the singleton instance.
Definition: collector.h:84
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:136
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:387
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:287
void EndScope(const TraceKey &key)
Record an end event described by key if Category is enabled.
Definition: collector.h:263
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:248
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:230
void MarkerEventStatic(const TraceKey &key)
Record a scope event described by key that started at start if Category is enabled.
Definition: collector.h:332
void RecordCounterDelta(const Key &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:366
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:42
uint64_t TimeStamp
Time in "ticks".
Definition: event.h:50
This class represents an ordered collection of TraceEvents and the TraceDynamicKeys and data that the...
Definition: eventList.h:46
A wrapper around a TraceStaticKeyData pointer that is stored in TraceEvent instances.
Definition: key.h:40
This class represents an identifier for a thread.
Definition: threads.h:40
Standard pointer typedefs.
#define TF_DECLARE_WEAK_PTRS(type)
Define standard weak pointer types.
Definition: declarePtrs.h:62
#define TF_DECLARE_WEAK_AND_REF_PTRS(type)
Define standard weak, ref, and vector pointer types.
Definition: declarePtrs.h:89
#define TF_MALLOC_TAG_NEW(name1, name2)
Enable lib/tf memory management.
Definition: mallocTag.h:489
Pragmas for controlling compiler-specific behaviors.
Reference counting.
Manage a single instance of an object.
Structure passed to python trace functions.
Definition: pyTracing.h:44
Default Trace category which corresponds to events stored for TRACE_ macros.
Definition: collector.h:100
static constexpr TraceCategoryId GetId()
Returns TraceCategory::Default.
Definition: collector.h:102
static bool IsEnabled()
Returns the result of TraceCollector::IsEnabled.
Definition: collector.h:104
Pointer storage with deletion detection.