HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
refPtrTracker.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_REF_PTR_TRACKER_H
8 #define PXR_BASE_TF_REF_PTR_TRACKER_H
9 
10 /// \file tf/refPtrTracker.h
11 
12 #include "pxr/pxr.h"
13 
14 #include "pxr/base/tf/api.h"
15 #include "pxr/base/tf/hash.h"
16 #include "pxr/base/tf/hashmap.h"
17 #include "pxr/base/tf/weakBase.h"
18 #include "pxr/base/tf/singleton.h"
19 #include <iosfwd>
20 #include <mutex>
21 #include <vector>
22 
24 
25 class TfRefBase;
26 template <class T> class TfRefPtr;
27 
28 /// \class TfRefPtrTracker
29 ///
30 /// Provides tracking of \c TfRefPtr objects to particular objects.
31 ///
32 /// Clients can enable, at compile time, tracking of \c TfRefPtr objects that
33 /// point to particular instances of classes derived from \c TfRefBase.
34 /// This is useful if you have a ref counted object with a ref count that
35 /// should've gone to zero but didn't. This tracker can tell you every
36 /// \c TfRefPtr that's holding the \c TfRefBase and a stack trace where it
37 /// was created or last assigned to.
38 ///
39 /// Clients can get a report of all watched instances and how many \c TfRefPtr
40 /// objects are holding them using \c ReportAllWatchedCounts() (in python use
41 /// \c Tf.RefPtrTracker().GetAllWatchedCountsReport()). You can see all of
42 /// the stack traces using \c ReportAllTraces() (in python use
43 /// \c Tf.RefPtrTracker().GetAllTracesReport()).
44 ///
45 /// Clients will typically enable tracking using code like this:
46 ///
47 /// \code
48 /// #include "pxr/base/tf/refPtrTracker.h"
49 ///
50 /// class MyRefBaseType;
51 /// typedef TfRefPtr<MyRefBaseType> MyRefBaseTypeRefPtr;
52 ///
53 /// TF_DECLARE_REFPTR_TRACK(MyRefBaseType);
54 ///
55 /// class MyRefBaseType {
56 /// ...
57 /// public:
58 /// static bool _ShouldWatch(const MyRefBaseType*);
59 /// ...
60 /// };
61 ///
62 /// TF_DEFINE_REFPTR_TRACK(MyRefBaseType, MyRefBaseType::_ShouldWatch);
63 /// \endcode
64 ///
65 /// Note that the \c TF_DECLARE_REFPTR_TRACK() macro must be invoked before
66 /// any use of the \c MyRefBaseTypeRefPtr type.
67 ///
68 /// The \c MyRefBaseType::_ShouldWatch() function returns \c true if the
69 /// given instance of \c MyRefBaseType should be tracked. You can also
70 /// use \c TfRefPtrTracker::WatchAll() to watch every instance (but that
71 /// might use a lot of memory and time).
72 ///
73 /// If you have a base type, \c B, and a derived type, \c D, and you hold
74 /// instances of \c D in a \c TfRefPtr<\c B> (i.e. a pointer to the base) then
75 /// you must track both type \c B and type \c D. But you can use
76 /// \c TfRefPtrTracker::WatchNone() when tracking \c B if you're not
77 /// interested in instances of \c B.
78 ///
79 class TfRefPtrTracker : public TfWeakBase {
80  TfRefPtrTracker(const TfRefPtrTracker&) = delete;
81  TfRefPtrTracker& operator=(const TfRefPtrTracker&) = delete;
82 public:
83  enum TraceType { Add, Assign };
84 
86  {
88  }
89 
90  /// Returns the maximum stack trace depth.
91  TF_API
92  size_t GetStackTraceMaxDepth() const;
93 
94  /// Sets the maximum stack trace depth.
95  TF_API
96  void SetStackTraceMaxDepth(size_t);
97 
98  /// A track trace.
99  struct Trace {
100  /// The stack trace when the \c TfRefPtr was created or assigned to.
101  std::vector<uintptr_t> trace;
102 
103  /// The object being pointed to.
104  const TfRefBase* obj;
105 
106  /// Whether the \c TfRefPtr was created or assigned to.
108  };
109 
110  /// Maps a \c TfRefPtr address to the most recent trace for it.
112 
113  /// Maps a \c TfRefBase object pointer to the number of \c TfRefPtr
114  /// objects using it. This should be the ref count on the \c TfRefBase
115  /// but it's tracked separately.
117 
118  /// Returns the watched objects and the number of owners of each.
119  /// Returns a copy for thread safety.
120  TF_API
122 
123  /// Returns traces for all owners. Returns a copy for thread safety.
124  TF_API
125  OwnerTraces GetAllTraces() const;
126 
127  /// Writes all watched objects and the number of owners of each
128  /// to \p stream.
129  TF_API
130  void ReportAllWatchedCounts(std::ostream& stream) const;
131 
132  /// Writes all traces to \p stream.
133  TF_API
134  void ReportAllTraces(std::ostream& stream) const;
135 
136  /// Writes traces for all owners of \p watched.
137  TF_API
138  void ReportTracesForWatched(std::ostream& stream,
139  const TfRefBase* watched) const;
140 
141  /// Handy function to pass as second argument to \c TF_DEFINE_REFPTR_TRACK.
142  /// No objects of the type will be watched but you can watch derived types.
143  /// This is important if you'll be holding TfRefPtr objects to base types;
144  /// if you don't track the base types, you'll fail to track all uses of
145  /// the derived objects.
146  static bool WatchNone(const void*)
147  {
148  return false;
149  }
150 
151  /// Handy function to pass as second argument to \c TF_DEFINE_REFPTR_TRACK.
152  /// All objects of the type will be watched.
153  static bool WatchAll(const void*)
154  {
155  return true;
156  }
157 
158 private:
159  TfRefPtrTracker();
160  ~TfRefPtrTracker();
161 
162  /// Start watching \p obj. Only watched objects are traced.
163  void _Watch(const TfRefBase* obj);
164 
165  /// Stop watching \p obj. Existing traces for \p obj are kept.
166  void _Unwatch(const TfRefBase* obj);
167 
168  /// Add a trace for a new owner \p owner of object \p obj if \p obj
169  /// is being watched.
170  void _AddTrace(const void* owner, const TfRefBase* obj, TraceType = Add);
171 
172  /// Remove traces for owner \p owner.
173  void _RemoveTraces(const void* owner);
174 
175 private:
176  typedef std::mutex _Mutex;
177  typedef std::lock_guard<std::mutex> _Lock;
178  mutable _Mutex _mutex;
179  size_t _maxDepth;
180  WatchedCounts _watched;
181  OwnerTraces _traces;
182 
183  friend class Tf_RefPtrTrackerUtil;
185 };
186 
188 
189 // For internal use only.
191 public:
192  /// Start watching \p obj. Only watched objects are traced.
193  static void Watch(const TfRefBase* obj)
194  {
195  TfRefPtrTracker::GetInstance()._Watch(obj);
196  }
197 
198  /// Stop watching \p obj. Existing traces for \p obj are kept.
199  static void Unwatch(const TfRefBase* obj)
200  {
201  TfRefPtrTracker::GetInstance()._Unwatch(obj);
202  }
203 
204  /// Add a trace for a new owner \p owner of object \p obj if \p obj
205  /// is being watched.
206  static void AddTrace(const void* owner, const TfRefBase* obj,
208  {
209  TfRefPtrTracker::GetInstance()._AddTrace(owner, obj, type);
210  }
211 
212  /// Remove traces for owner \p owner.
213  static void RemoveTraces(const void* owner)
214  {
215  TfRefPtrTracker::GetInstance()._RemoveTraces(owner);
216  }
217 };
218 
219 #define TF_DECLARE_REFPTR_TRACK(T) \
220  inline void \
221  Tf_RefPtrTracker_FirstRef(const void*, const TfRefBase *obj, T*); \
222  inline void \
223  Tf_RefPtrTracker_LastRef(const void*, const TfRefBase *obj, T*); \
224  inline void \
225  Tf_RefPtrTracker_New(const void* owner, const TfRefBase *obj, T*); \
226  inline void \
227  Tf_RefPtrTracker_Delete(const void* owner, const TfRefBase *obj, T*); \
228  inline void \
229  Tf_RefPtrTracker_Assign(const void* owner, \
230  const TfRefBase *obj, const TfRefBase *oldObj, T*);
231 
232 #define TF_DEFINE_REFPTR_TRACK(T, COND) \
233  inline void \
234  Tf_RefPtrTracker_FirstRef(const void*, const TfRefBase *obj, T*) { \
235  if (obj && COND(obj)) Tf_RefPtrTrackerUtil::Watch(obj); \
236  } \
237  inline void \
238  Tf_RefPtrTracker_LastRef(const void*, const TfRefBase *obj, T*) { \
239  Tf_RefPtrTrackerUtil::Unwatch(obj); \
240  } \
241  inline void \
242  Tf_RefPtrTracker_New(const void* owner, const TfRefBase *obj, T*) { \
243  Tf_RefPtrTrackerUtil::AddTrace(owner, obj); \
244  } \
245  inline void \
246  Tf_RefPtrTracker_Delete(const void* owner, const TfRefBase *obj, T*) { \
247  Tf_RefPtrTrackerUtil::RemoveTraces(owner); \
248  } \
249  inline void \
250  Tf_RefPtrTracker_Assign(const void* owner, const TfRefBase *obj, \
251  const TfRefBase *oldObj, T*) { \
252  if (oldObj != obj) { \
253  Tf_RefPtrTrackerUtil::AddTrace( \
254  owner, obj, TfRefPtrTracker::Assign); \
255  } \
256  }
257 
259 
260 #endif
GLuint GLuint stream
Definition: glcorearb.h:1832
TF_API void ReportTracesForWatched(std::ostream &stream, const TfRefBase *watched) const
Writes traces for all owners of watched.
static T & GetInstance()
Definition: singleton.h:120
A track trace.
Definition: refPtrTracker.h:99
#define TF_API
Definition: api.h:23
static bool WatchNone(const void *)
static void AddTrace(const void *owner, const TfRefBase *obj, TfRefPtrTracker::TraceType type=TfRefPtrTracker::Add)
TfHashMap< const TfRefBase *, size_t, TfHash > WatchedCounts
TF_API_TEMPLATE_CLASS(TfSingleton< TfRefPtrTracker >)
static bool WatchAll(const void *)
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
TF_API void ReportAllTraces(std::ostream &stream) const
Writes all traces to stream.
TfHashMap< const void *, Trace, TfHash > OwnerTraces
Maps a TfRefPtr address to the most recent trace for it.
TraceType type
Whether the TfRefPtr was created or assigned to.
static void Unwatch(const TfRefBase *obj)
Stop watching obj. Existing traces for obj are kept.
TF_API WatchedCounts GetWatchedCounts() const
static void Watch(const TfRefBase *obj)
Start watching obj. Only watched objects are traced.
TF_API OwnerTraces GetAllTraces() const
Returns traces for all owners. Returns a copy for thread safety.
std::vector< uintptr_t > trace
The stack trace when the TfRefPtr was created or assigned to.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
const TfRefBase * obj
The object being pointed to.
static TF_API TfRefPtrTracker & GetInstance()
Definition: refPtrTracker.h:85
TF_API void ReportAllWatchedCounts(std::ostream &stream) const
static void RemoveTraces(const void *owner)
Remove traces for owner owner.
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
TF_API void SetStackTraceMaxDepth(size_t)
Sets the maximum stack trace depth.
TF_API size_t GetStackTraceMaxDepth() const
Returns the maximum stack trace depth.