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 
38 #include "pxr/base/tf/mallocTag.h"
39 
40 #include "pxr/base/tf/pyTracing.h"
41 
42 #include "pxr/base/tf/singleton.h"
43 #include "pxr/base/tf/refBase.h"
44 #include "pxr/base/tf/refPtr.h"
45 #include "pxr/base/tf/weakBase.h"
46 #include "pxr/base/tf/weakPtr.h"
47 
48 #include "pxr/base/arch/pragmas.h"
49 
50 #include <atomic>
51 #include <string>
52 #include <vector>
53 
54 #include <tbb/spin_mutex.h>
55 
56 PXR_NAMESPACE_OPEN_SCOPE
57 
58 class TraceScopeHolder;
59 
62 
63 
71 class TraceCollector : public TfWeakBase {
72 public:
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
108  bool IsPythonTracingEnabled() const {
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 
408 private:
409 
410  TraceCollector();
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 
638 TRACE_API_TEMPLATE_CLASS(TfSingleton<TraceCollector>);
639 
640 PXR_NAMESPACE_CLOSE_SCOPE
641 
642 #endif // PXR_BASE_TRACE_COLLECTOR_H
const std::string & GetLabel()
Return the label associated with this collector.
Definition: collector.h:398
static bool IsEnabled()
Returns the result of TraceCollector::IsEnabled.
Definition: collector.h:104
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
Manage a single instance of an object.
TRACE_API void CreateCollection()
Produces a TraceCollection from all the events that recorded in the collector and issues a TraceColle...
TRACE_API void SetEnabled(bool isEnabled)
Enables or disables collection of events for DefaultCategory.
Pragmas for controlling compiler-specific behaviors.
Manage a single instance of an object (see.
Definition: singleton.h:120
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 BeginEventAtTime(const Key &key, double ms)
Record a begin event with key at a specified time if Category is enabled.
Definition: collector.h:149
#define TF_DECLARE_WEAK_PTRS(type)
Define standard weak pointer types.
Definition: declarePtrs.h:62
Standard pointer typedefs.
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 MarkerEventAtTime(const Key &key, double ms)
Record a marker event with key at a specified time if Category is enabled.
Definition: collector.h:204
TimeStamp EndEvent(const Key &key)
Record an end event with key if Category is enabled.
Definition: collector.h:165
This class represents an identifier for a thread.
Definition: threads.h:40
uint64_t TimeStamp
Time in "ticks".
Definition: event.h:50
void RecordCounterValue(const TraceKey &key, double value)
Record a counter value for a name key if Category is enabled.
Definition: collector.h:375
bool IsPythonTracingEnabled() const
Returns whether automatic tracing of all python scopes is enabled.
Definition: collector.h:109
Pointer storage with deletion detection.
#define TF_DECLARE_WEAK_AND_REF_PTRS(type)
Define standard weak, ref, and vector pointer types.
Definition: declarePtrs.h:89
static constexpr TraceCategoryId GetId()
Returns TraceCategory::Default.
Definition: collector.h:102
TRACE_API void Clear()
Clear all pending events from the collector.
This class stores data used to create dynamic keys which can be referenced in TraceEvent instances.
Definition: dynamicKey.h:42
TimeStamp BeginEvent(const Key &key)
Record a begin event with key if Category is enabled.
Definition: collector.h:136
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 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
Default Trace category which corresponds to events stored for TRACE_ macros.
Definition: collector.h:100
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 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 ScopeArgs(Args &&... args)
Record multiple data events with the default category if collection of events is enabled.
Definition: collector.h:317
TimeStamp MarkerEvent(const Key &key)
Record a marker event with key if Category is enabled.
Definition: collector.h:191
static TRACE_API TraceCollector & GetInstance()
Returns the singleton instance.
Definition: collector.h:84
This is a singleton class that records TraceEvent instances and populates TraceCollection instances.
Definition: collector.h:71
void EndScope(const TraceKey &key)
Record an end event described by key if Category is enabled.
Definition: collector.h:263
void RecordCounterDelta(const Key &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:366
Structure passed to python trace functions.
Definition: pyTracing.h:44
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
Definition: singleton.h:135
void BeginScope(const TraceKey &_key)
Record a begin event for a scope described by key if Category is enabled.
Definition: collector.h:217
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.
This class represents an ordered collection of TraceEvents and the TraceDynamicKeys and data that the...
Definition: eventList.h:46
Reference counting.
static bool IsEnabled()
Returns whether collection of events is enabled for DefaultCategory.
Definition: collector.h:94
TRACE_API void SetPythonTracingEnabled(bool enabled)
Set whether automatic tracing of all python scopes is enabled.
TRACE_API TimeStamp GetScopeOverhead() const
Return the overhead cost to measure a scope.
uint32_t TraceCategoryId
Categories that a TraceReporter can use to filter events.
Definition: category.h:44
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141
void RecordCounterDelta(const TraceKey &key, double delta)
Record a counter delta for a name key if Category is enabled.
Definition: collector.h:354
void ScopeArgs(Args &&... args)
Record multiple data events with category cat if Category is enabled.
Definition: collector.h:299
A wrapper around a TraceStaticKeyData pointer that is stored in TraceEvent instances.
Definition: key.h:40