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